miércoles, 23 de diciembre de 2020

Estadística descriptiva con Python

Debes estar muy aburrid@ en el trabajo, o no tienes nada mejor que hacer, para pinchar en un enlace con la palabra clave 'Estadística'. Pero... ya que has pinchado intentaré que se haga lo más ameno posible.

Esta entrada está pensada para hacer una pequeña visita guiada por la librería de pandas en su sección de estadística. Y es que cuando hablamos de Python y de estadística es inevitable que surja pandas, pues tiene debajo todo el poder de la librería numpy para hacer multitud de cálculos de una forma muy eficiente.

Ya verás qué pronto te encariñas con estos seres.


Lo primero, (y evidentemente lo más importante) es importar dicha librería para poder utilizarla, para aquellas personas que no estéis familiarizadas se hace de la siguiente forma:


A continuación, vamos a 'cargar' algunos datos, para luego poder ver algunas de las estadísticas. ¿Que, qué datos voy a cargar? Pues las estadísticas de todos los Pokémon de la 1º a la 6º generación que son 800 en total (Para aquellas personas que no estén familiarizadas con este mundillo de Pokémon no os preocupéis, os vais a enterar igual).

¡Vamos a la obra!


En primer lugar, decirte que en pandas cuando hablamos de unos datos en formato 2D (con filas y columnas) se le denomina DataFrame (DF para acortar), y es muy habitual utilizar sus siglas para crear una variable que contenga un DataFrame. En este caso llamaré df_pkm al DataFrame con todos los datos de los Pokémon, y para leer esos datos usaremos .read_csv( ) y posteriormente echaremos un vistazo a los datos que tenemos con .head( )


Hagamos un inciso para que entiendas los datos.

Las columnas de Type hacen referencia a la 'familia' a la que pertenece uno de estos entrañables seres, por ejemplo, Pikachu (probablemente el más conocido) es de tipo eléctrico. Las columnas que van desde HP (Health Points) hasta Speed, hacen referencia a los atributos de estos seres, expresado en formato de puntos, en lo que a mayor número mejor es en este aspecto, y la columna Total es la suma de todas estas columnas. La columna Generation hace referencia a cuando salió dicho Pokémon en los juegos (del 1 al 6) y la Legendary hace referencia a si es un Pokémon con unas estadísticas muy especiales. Después de esta mini-chapa (pero fundamental para entender el contexto) sigamos con lo que cierne al título de esta entrada.

Este es Pikachu, seguro que te suena


Una vez tenemos cargado nuestro .csv en un DF, y antes de pasar a la parte de estadística, es fundamental comprobar el estado de nuestros datos, ya que, si no tenemos nuestros datos en un formato numérico (int, float, complex) no podremos operar con ellos como si fuesen números (Y sí, a veces ocurre que una columna que parece que está en formato numérico, pero en realidad está en un formato de texto (object)) . Para hacer una inspección rápida utilizaremos .dtypes 


Aquí podemos comprobar que todas nuestras columnas que tienen números están en un formato numérico, por lo tanto, ¡podemos continuar!

Ahora vamos a sacar estadísticas de todos estos datos. Para ello usaremos una de las herramientas que con una simple instrucción podemos sacar las estadísticas más importantes, y esa no es otra que .describe( )



Nada mal para una sola línea de código tan simple ¿eh?, este es el poder que reside en pandas. De esta forma de un simple vistazo tenemos muchas estadísticas a la vista, como puede ser la media, la desviación estándar, el mínimo o el máximo y los percentiles. Hay que decir, que la columna de Generation no tiene sentido en esta tabla, pues son valores discretos que van del 1 al 6 en función de cuando salió dicho Pokémon. Y como te puedes fijar solo ha hecho el análisis de aquellas columnas numéricas, el resto las ha obviado, por ello es fundamental comprobar primero el tipo de dato que tenemos.

Si quieres acceder a un dato en concreto solo tienes que seguir la siguiente sintaxis:

¿Y si en lugar de números lo vemos en un gráfico?

Otra ventaja que presenta pandas es que además de tener numpy debajo para hacer los cálculos numéricos, tiene también a matplotlib, una librería diseñada para representar gráficos. La conjunción de estas dos librerías más lo que aporta pandas hace que sea una de las herramientas más utilizadas en Python.

Volviendo a nuestros datos, probablemente la mejor forma de representar este tipos de datos sea mediante un diagrama de cajas y bigotes, para ello usamos .boxplot( ). Y seleccionaré aquellas columnas que realmente tienen interés, dejando de lado a 'Total' que es la suma de las que represento en el siguiente diagrama y a 'Generation':


Como puedes observar con comandos sencillos se pueden obtener buenos resultados.


¿Qué tal si ahora para finalizar ponemos fin a la lucha que ha habido siempre en el mundillo de Pokémon usando la estadística?

Por fin sabremos si es mejor el tipo agua, fuego o planta (Para aquellas personas que no estén al día, al principio de todos los juegos te hacen elegir un Pokémon de entre estos 3 tipos, pero en el juego en general hay muchos más tipos). Lo que haremos será hacer este mismo gráfico pero para cada uno de esos tipos (agua, fuego y planta) y compararemos las gráficas para salir de dudas de cuál es el mejor tipo.

En primer lugar, lo que haremos será filtrar nuestro DF dejando únicamente aquellos Pokémon de tipo agua, fuego o planta, y guardaremos ese nuevo DF en pkm_wfg (wfg de las siglas de water, fire y grass), para ello haremos uso .loc[ ] y de .isin( )

Y finalmente, usaremos de nuevo .boxplot( ) esta vez con unos parámetros adicionales, el más importante es el 'by' utilizado para agrupar, hay que tener en cuenta que hay que agregar la columna que queremos usar como agregación, por ese motivo, añadiremos 'Type 1' a las columnas que usaremos en nuestro diagrama de cajas y bigotes.

Queda claro que gana el tipo fuego, pero cuidadito con los outliers de tipo agua que pueden apagar muchos incendios, y el tipo planta se queda como robusto siempre entre los dos tipos. Conclusión, no hay conclusión, aún seguiremos debatiendo si elegir entre Squirtle, Charmander o Bulbasaur

Y bueno espero que con esta pequeña visita guiada a pandas te hayas hecho una idea de lo potente que es esta herramienta y que hay muchas aplicaciones a nivel estadístico. Espero que hayas llegado al final y que no te haya matado de aburrimiento.

¡Muchas gracias por leerme!

Todas las imágenes que no son capturas de pantalla han sido sacas de pixabay.com











jueves, 17 de diciembre de 2020

Diseño de un api ReST (III)

Continuamos con la serie de posts sobre apis ReST dedicándole una entrada a los parámetros en una petición (cero emoción).


Filtrado de recursos

Hemos visto que una petición GET a un servicio REST tendrá como respuesta un único recurso si se indica el identificador al final de la ruta o todos los contenidos en ella si termina en directorio. Se hace necesario un método por el cual los clientes puedan definir exactamente cuales son recursos que solicita.


Típica entrega de 500.000 recursos cuando no se han filtrado los resultados


HTTP cuenta con una herramienta para filtrar que recursos serán afectados por el método: la ‘query string’. Se trata de una sucesión de pares clave-valor con una sintaxis simple que se coloca a continuación de la ruta, después de una interrogación:

GET /ruta?Param1=valor1&param2=valor2&param3=valor3

El significado de esta petición es ‘los recursos contenidos en el directorio cuyas propiedades coincidan con los valores incluidos en la query’. Por ejemplo:

GET /clientes?estado=activo - Del directorio ‘clientes’ queremos solo aquellos cuyo estado sea ‘activo’

GET /facturas?fecha=17/7/2020 - Del directorio ‘facturas’ solo queremos las del 17 de julio.

DELETE /pedidos?estado=cancelado - Queremos que se eliminen solo los pedidos cancelados.

PUT /productos?estado=descatalogado - Queremos modificar los productos descatalogados 

Naturalmente habrá que programar la lógica de control necesaria en el lado del servidor para buscar estos parámetros en la petición y actuar en consecuencia cuando se encuentren. También será necesaria lógica para que cuando esos parámetros no estén presentes la petición sea rechazada (también se puede  devolver una cantidad limitada de recursos o implementar una paginación)

-Aquí está su respuesta, ¡con extra de JSON!


Seleccionando por criterios distintos a 'igual a'

Cuando se filtran resultados lo habitual es utilizar parámetros que coincidan con las propiedades de los recursos, pero no siempre es posible. Por ejemplo, si queremos entregar facturas entre dos fechas no encontramos una propiedad en los recursos ‘factura’ que nos sirva puesto que las facturas simplemente tienen ‘fecha’. Tenemos algunas opciones:

Utilizar parámetros creados específicamente para la búsqueda:

GET /facturas?fechaInicio=<fecha_inicio>&fechaFin=<fecha_fin>

Utilizar parámetros asociados con propiedades existentes, pero utilizando alguna sintaxis especial:

GET /facturas?fecha=gte:<fecha_inicio>,lte:<fecha_fin>

GET /facturas?fecha[gte]=<fecha_inicio>,fecha[lte]=<fecha_fin>

GET /facturas?fecha=gte:<fecha_inicio>,&fecha=lte:<fecha_fin>

Estos últimos tres ejemplos son igual de válidos, pero hay que tener en cuenta que la lógica para procesar esos parámetros en el servidor será tediosa de implementar (y fácil)


Otros usos

El uso principal de los parámetros es el de filtrar con más precisión los resultados que entregará el servidor al cliente pero podemos darle otros sin salirnos del camino que marca el protocolo HTTP. Recordemos que si lo abandonamos la cosa no será REST.

Estos usos exigen una implementación más compleja en el lado del servidor pero como se trata de cosas muy concretas e independientes del api en si se pueden generalizar e introducir en una librería reutilizable.


-Y ahora con un for revisas uno a uno los recursos a ver si cumplen el criterio de filtrado
-¿No lo hago mejor con el select?
-¿Se puede poner un for en el select?


Utilizando los parámetros para filtrar las propiedades de los recursos

Permite a los clientes indicar al servidor cuales propiedades de los recursos necesitan y minimizar así el trasiego de información y el consumo de memoria.

Tenemos libertad a la hora de definir el parámetro pero es habitual que tenga un nombre concreto que se puede utilizar en distintas peticiones y que sea de tipo múltiple. Por ejemplo

GET /libros?propiedades=id,titulo,autor

Con la adecuada implementación en el lado del servidor esta petición tendría como respuesta una lista de libros con los valores id, título y autor aunque el recurso tuviera muchos más valores.


Ordenando los resultados

Otro uso que puede darse a los parámetros es el de proporcionar a los clientes una manera de solicitar al servidor los recursos en un orden concreto. Debemos idear una sintaxis para el parámetro, existiendo muchas posibilidades. Los siguientes ejemplos son variaciones típicas y necesitan aproximadamente el mismo código en el servidor para extraer los valores:

GET /peliculas?orden=asc(titulo)

GET /peliculas?orden=desc(titulo)

GET /peliculas?orden=+titulo

GET /peliculas?orden=-titulo

También podríamos permitir varios campos para la ordenación. Quizás para esto sea más recomendable la segunda opción, con el más y el menos para poder alternan con más facilidad entre orden ascendente y descendente.

GET /productos?orden=+existencias,-precio


-Y aquí hemos puesto estas movidas para ordenar los resultados en el servidor
-¿Y cómo son esas movidas?
-Gordísimas

Y basta ya de parámetros. En el siguiente post continuaremos con más REST.








viernes, 13 de noviembre de 2020

From One Quandary to Another

I still remember the first crisis we suffered at Pronoide back in 2005. After the first two successful years of the company, suddenly we were left with no customers and no projects... We were a new development company, where even the maintenance of the software that we had created was commissioned to another much larger business. After six months of agony, the team was demoralized, I was bankrupt, and trying to keep the business afloat meant I owed money to my family, friends, and wife. The routine of withdrawing money from all my personal accounts and transferring it to the company account to pay the salaries. 

Fifteen years later, I look back on that crisis almost fondly. At that time we carried out almost any task related to the world of computing that was available to us. We tried to create new applications - which were never sold fast enough. I tried to be a Computer science judicial expert - but litigating is not for the ingenious -, or attempted to became an expert in personal data protection with legislation impossible to comply with..We even tried to set up wireless networks in Africa - with malaria vaccine included...And suddenly, without planning it, after a course on creating custom templates for MS Visio that I taught by chance - anyway, who needed a course in that matter? - we got into the computer technical training business. At first, it was just me, then Luis Ramón, and finally the whole company was transformed into a specialized computer training business for professionals. We changed from the development of computer programs, to teach computer programming; in 2005 by the end of the year, we have taught 4 courses and about 100 hours of training. Only during last year, 2019,  we taught 350 courses and almost reached 10,000 hours of training. We are not a large company, we do not have commercials, but we like what we do. There are 10 of us in the company - the vast majority of teachers - and about 30 collaborators.

Over these fourteen years, we have experienced other crises and difficult moments. Sometimes due to temporary issues, such as the economic crisis of 2008, others because of internal decisions, for example deciding to cover more technical areas of knowledge in 2013. Nonetheless, after every hard moment, we have grown as a company; in 2009 we hired many more teachers; up until 2014 Java had been our core, and in that year we left our comfort zone and began to teach courses on Big Data, DevOps and Front Development. Some years we have finished the year in the red, which I have always preferred to call an investment rather than a loss. Sometimes, I have had to take out personal bank loans to make sure the business survives. We were lucky, we could have been forced to close, but we have always grown after difficult periods.




So, what approach is Pronoide going to take in the coming weeks, months, or even quarters?  We are going to proceed completely normal, without haste. We are not going to fire anyone, we are not going to change the length of the workday, we are not going to make anyone take vacations, and we are going to continue assigning work to our external contractors without prioritizing the full-time employees. We are determined to take advantage of this crisis. Since right now almost all our courses are on hold - some are still being taught remotely -, we are making the most of this in many ways. First by accelerating the digital transformation of the company, which previously had been happening, but very slowly. Secondly, we are training our teachers in new subject areas, which before there never seemed to be enough time to do. This also means that in the future can avoid the problem that courses can only be taught by one particular teacher - putting an end to internal knowledge monopolies. Finally, we are creating a more agile methodology for managing our courses, which will allow us to grow more quickly when the situation goes back to normal.

Why are we taking this approach? Because we have trained our teachers for quite a long time to not give them full support when they most need it. Furthermore, we have worked hard to build our network of collaborators and so we are not going to allow it to crumble at the first sign of trouble. It is also so that we can continue to provide training virtually or remotely. Moreover, even though we will be in the red, we will be able to absorb the impact of the crisis. Many companies need our help in process of digital transformation, to learn how to move to the Cloud, to manage their systems, to create applications, and to lead their development teams. Because the companies and professionals that we train will recover and help others to recover. There Information Technology sector should never be cowed or cautious, now or ever.

I know that, in many other sectors and businesses, the prospects are not as rosy as in our company. All the more reason why at Pronoide we must be responsible and commit to our employees, our contractors, our families, the companies we work with, and even the society, which will have to start up again, as soon as possible, with many lessons learned and all in the space of a few weeks. 


viernes, 6 de noviembre de 2020

Viejos problemas para nuevos tiempos

Siempre hemos estado muy ocupados, hasta para mejorar...


Hace ya algo más de 6 meses que la dinámica en Pronoide cambió bruscamente, como también cambio para tantas empresas, familias y personas. En su día ya expusimos en este blog cual iba a ser nuestra estrategia,ante la convolución que se aproximaba por el covid19. Querría hacer en este artículo, un poco de retrospectiva de este periodo e intentar ver que nos depara el corto-medio plazo con lo que sabemos hoy. 

Aquí vemos la función f de crecimiento de Pronoide convolucionada por la funcion g del covid-19

Durante el segundo trimestre del año, estuvimos volcados en aumentar nuestra presencia en las redes sociales y ganar control sobre nuestras propiedades digitales... Reactivamos este blog, la cuenta de twitter, las redes con profesionales en LinkedIn, creamos una entidad en Facebook y en Instagram y produjimos un montón de videos en nuestro canal de YouTube. También rediseñamos nuestra web corporativa, en fin, nos dedicamos a todas esas cosas para las que nunca habíamos tenido tiempo... esos primeros meses de la crisis culminaron, con la integración en la Web de una pasarela de pagos (Stripes) y la programación e impartición de cursos de calendario abiertos para alumnos individuales, en lugar de los cursos para empresas que normalmente damos. Ahora podemos vender de forma electrónica cualquier servicio de formación que desarrollemos. 

Durante este tiempo, también aprendimos a utilizar campañas de publicidad de Google, Facebook y LinkedIn en nuestro día a día para apoyar la difusión de las actividades e iniciativas que íbamos teniendo. Hemos ejecutado campañas de marketing focalizadas en España, pero también otras focalizadas en Latinoamérica. Sinceramente ahora seriamos capaces de impartir un curso de Comunity Manager o Social Media para empresas.

Por fin estamos presentes y activos en la mayoría de las redes sociales

Con la entrada del tercer trimestre, en Julio, abordamos un proyecto nuevo, la creación de una plataforma de tele-formación propia, a la que hemos llamado Ergane, para impartir cursos en formato mixto: por un lado, sesiones en formato webinar dirigidas por el formador y por otro lado auto-servicio de contenidos y ejercicios para el alumno. Hemos conseguido plasmar nuestra metodología de generación de materiales y lo aprendido en edición de videos para ir creando itinerarios formativos que estén disponibles para él alumno durante un periodo de tiempo determinado para cada formación (3 semanas, dos meses, etc).

 Ergane, nuestra plataforma de teleformación ya disponible

Desde el comienzo de la crisis, descubrimos que la formación a empresas en formato remoto, mientras no se reanudará la vida escolar no iba a ser tan sencilla como quizás habíamos pensado al principio, eso unido con el parón estacional que siempre tenemos en verano (o sea el tercer trimestre), nos ha hecho acumular unas “pérdidas” importantes durante todos esos 6 meses desde abril a septiembre. Bueno como decimos siempre, no son pérdidas, es inversión. En abril reaccionamos rápido, solicitamos y recibimos un crédito ICO, que, si bien no cubre totalmente esa cantidad “invertida”, nos va a permitir repartir el grueso de ella durante los próximos cinco años. Así que, tratamos de ver este año 2020, como el año de la I+D concentrada de los próximos cinco. También es de agradecer que de entre los más de 30 inversores individuales del proyecto, ninguno se ha echado atrás durante este aciago año. En todo este período la única medida económica que hemos tomado "en contra" de los intereses de nuestros empleados ha sido, ajustar las vacaciones anuales a las definidas en el convenio laboral, ya que en Pronoide normalmente el total de días de vacaciones disfrutadas no se suele computar (es una compensación a no tener los mayores salarios del mercado).

Invertimos hoy para tener beneficios mañana


Ahora, ya estamos en el último trimestre del año, manejando unas cifras de facturación que no difieren mucho a la de otros últimos trimestres de los últimos años (bueno si, son un poquito más bajas) ... y aún no sabemos cómo va a acabar el año 2020. Sin embargo, el otro día en una reunión, un miembro del equipo comentó: "ya sé que os lo digo siempre, pero necesitamos más formadores en plantilla". Y yo sonreí con alegría. Es cierto que en Pronoide el problema, que nos limita históricamente para crecer, es la falta de formadores para impartir toda la demanda de formación que nos llega. Nos llegan más cursos de los que podemos impartir, a pesar de no tener fuerza comercial. Así que interpreto la vuelta de este viejo problema, como la vuelva a nuestro ser normal, como la verdadera señal de que hemos empezado la recuperación y la regularidad en un escenario muy diferente al anterior y que, por supuesto, aún tiene que cambiar mucho... pero que para nosotros significa, sin duda, volver a nuestros desafíos conocidos desde el pasado junto con los nuevos retos que hemos descubierto en el presente, durante este año.

Mi cara el otro día en la reunión sonriendo

En conclusión, para enfrentar todos estos retos y desafíos, vamos a ampliar la plantilla de formadores (estamos buscando 3 personas nuevas para el equipo), vamos acelerar la trasformación digital de nuestros procesos de negocio (intentando aplicar técnicas de RPA a nuestras tareas de gestión), vamos a ampliar el alcance del proyecto al mercado internacional (volvemos a mirar a Latinoamérica y al mercado europeo para formación) y en definitiva vamos a seguir preparándonos para que, a la vez que resolvemos los problemas que nos vienen del pasado, nos preparemos para los lances que aún están por llegar.

¡Llega el momento de pasar a la acción!


Todas las imágenes sacadas de https://pxhere.com/ bajo la licencia CC0.

lunes, 5 de octubre de 2020

Diseño de un api ReST (II)

Continuamos la serie sobre apis ReST. En el anterior post vimos el papel que tiene el protocolo HTTP y el significado de los métodos, así como ejemplos de las urls más sencillas. Con estos rudimentos podemos construir nuestra api, en un ejemplo en el que el recurso serán los clientes en una aplicación de gestión.


El recurso

Los recursos cliente de nuestro ejemplo tendrán las siguientes propiedades (a modo de muestra)

  • id: numérico, es un identificador único para cada cliente
  • nombre, cadena de texto
  • direccion, cadena de texto
  • telefono, cadena de texto

El api

Antes de definir un api debemos conocer lo que se esperan las aplicaciones clientes de nuestro servicio y cuales son los requisitos de la aplicación que lo publica. Vamos a suponer que en nuestro caso es necesario un mantenimiento básico de los datos de los clientes, con las siguientes funcionalidades:

  • Generación de listados de clientes
  • Búsqueda de un cliente
  • Alta de un nuevo cliente
  • Modificación de un cliente
  • Baja de un cliente

-Nada que ver aquí, es solo un CRUD


GET /clientes

Devuelve el contenido del directorio ‘clientes’. Aquí hay una idea importante: lo que debe devolver una petición GET será lo contenido en la última carpeta de la ruta si no se adjunta un identificador. ¿Y si hay muchos clientes? Pues mientras no filtremos los resultados deberán devolverse todos. Más adelante hablaremos de cómo debe expresarse el filtrado de resultados en un api ReST





Vemos que al solicitar clientes con GET nos envían un documento JSON con la representación del estado actual de los clientes en el servidor.


-¿Asi que eso es lo que significa representational state transfer?


GET /clientes/{id}

Devuelve el recurso contenido en el directorio ‘clientes’ cuyo identificador es ‘id’. ¿Y si no existe un recurso con ese identificador? Otro punto importante aquí: todas las respuestas que de el servidor deben incluir el código de respuesta HTTP adecuado. En este caso debería ser 404 NOT FOUND en lugar de un 200 OK.

Podría pensarse que para solicitar un único cliente debiera ser ‘GET /cliente/{id}’ pero esto no es así. El protocolo HTTP habla de recursos que están en directorios y los clientes están en ‘clientes’. Es una regla: los directorios guardan muchos recursos, los directorios están en plural. Es más: la petición ‘GET /clientes/{id}’ ha de interpretarse como ‘entra en el directorio clientes y localiza el recurso cuyo id es el indicado’.



POST /clientes

Insertará un recurso nuevo en el directorio ‘clientes’. De nuevo nos encontramos con asuntos destacables. El nuevo recurso deberá adjuntarse como contenido en el cuerpo de la petición HTTP, en el formato que el servidor espere o soporte. Como respuesta a una petición post es buena idea entregar el recurso tal y como ha quedado en el servidor, su id o un enlace a él.




PUT /clientes/{id}

Localiza el recurso cuyo id se indica en la ruta y lo sustituye por el que se haya proporcionado con la petición. Si el recurso no existiera es elección del servidor el devolver un 404 o crear un nuevo recurso.


En la petición el identificador del cliente a sustituir está en la ruta. En este ejemplo tambien lo vemos en el documento json del cuerpo. Esto es habitual, ya que las aplicaciones cliente suelen generar el json a partir de objetos en memoria y no se molestan en eliminar propiedades no solicitadas. El servidor utilizará solo el id de la ruta y deberá ignorar completamente cualquier otro. 


PATCH /clientes/{id}

PATCH fue añadido a HTTP en 2010. Es similar a PUT salvo que mientras PUT sustituye un recurso por otro PATCH modifica el existente. Esto implica que en una petición PATCH puede adjuntarse una representación parcial del recurso que incluya únicamente los valores que han de cambiar.


En la petición el identificador del recurso forma parte de la ruta (el recurso identificado con '25' del directorio 'clientes') y en el cuerpo de la petición solo se indica las propiedades que cambian. En la respuesta (y esto es opcional) se incluye el recurso entero tal y cómo ha quedado. 


DELETE /clientes/{id}

Esta petición solicita la eliminación del recurso identificado por ‘id’, que está en el directorio ‘clientes’.  Si el recurso se ha podido eliminar la respuesta será un 200 OK si queremos indicar algo al cliente (en el body de la respuesta) o 204 NO CONTENT si la simple respuesta 2XX basta. Si el recurso no existiera debería devolverse un 404 NOT FOUND.
Una petición DELETE que no incluya el identificador del recurso debería afectar a todos los recursos del directorio, es decir: ‘DELETE /clientes’ debería tener como resultado la eliminación de todos los clientes.  




Ya tenemos la base del diseño de un api ReST, pero aun faltan algunos temas importantes. Continuaremos hablando de ello en el siguiente post.


Esperando la respuesta a una petición GET

lunes, 21 de septiembre de 2020

Diseño de un api ReST

En la actualidad existen muchas tecnologías para publicar servicios y componer una arquitectura cliente-servidor. ReST es probablemente la más extendida y es difícil encontrar un sitio en el que no se esté usando. En este post veremos las bases de ReST y explicaremos como diseñar un api que sea aceptablemente ortodoxa.


Cables azules para las peticiones GET. Cables blancos para las POST


El protocolo HTTP

La idea que hay detrás del protocolo HTTP es sencilla y particular: en un servidor existen una serie de recursos guardados en directorios reales o imaginarios. Después los clientes envían peticiones en las que se incluye una ruta a uno o varios de esos recursos junto con un verbo que indica que acción debe realizarse una vez estos hayan sido localizados.

Otras características de HTTP que lo hacen muy conveniente como protocolo de comunicación entre cliente-servidor son:
  • Mensajes sencillos: Los mensajes HTTP son textos planos con apenas estructura. Una cabecera con información sobre la petición y un cuerpo opcional. Es tan sencillo que la separación entre cabecera y cuerpo son dos saltos de línea y retorno de carro seguidos.
  • Independiente del formato de la información intercambiada. Puede ser xml, json, una imagen, html o cualquier cosa que se nos pase por la cabeza.
  • Sin estado: La conversación más larga que puede mantenerse con HTTP es petición-respuesta, precisamente porque HTTP está pensado para aplicaciones distribuidas que trabajan con los recursos alojados en un servidor. El servidor no almacenará estado alguno ni dedicará recursos en ello (por ejemplo creando sesiones). Si es necesario mantener un estado esta tarea recaerá sobre las aplicaciones cliente.

Esta última característica tiene una gran importancia a la hora de diseñar un api ReST y todas las funcionalidades que ofrezca el servidor deberán tenerla en cuenta.


ReST

De Representational State Transfer, es una arquitectura de software para aplicaciones cliente-servidor ideada por Roy T. Fielding cuya principal característica es que utiliza el protocolo HTTP hasta la última consecuencia. Toda la información que maneje el servidor será representada como recursos y cualquier funcionalidad ofrecida por este deberá poder accederse a través de una petición HTTP que respete los principios del protocolo al pie de la letra. 

Roy T. Fielding diciendo lo que es ReST y lo que no.

Los recursos

Lo primero que definiremos cuándo diseñamos un api ReST son los recursos. Estos serán la información que maneje nuestro servicio. Ejemplos típicos (y tópicos) de recursos podrían ser clientes, facturas, productos, empleados... Cada uno de estos recursos deberá identificarse con un valor único y poseerá distintas propiedades. Por ejemplo: los clientes tendrán id, nombre, DNI, fecha de nacimiento y los productos id, referencia, fabricante, peso, etc.

Decidir cuáles son los recursos resulta más sencillo cuando ya disponemos de una base de datos o la lógica de la aplicación. Es la norma que exista una relación entre las tablas que tengamos y los recursos del servicio. Esto también ocurrirá con respecto a las entidades que utilice nuestra lógica de negocio. Además descubriremos que las relaciones entre esas tablas o entidades se ve reflejada en las relaciones existentes entre los recursos. Pero no nos confundamos: ¡un api ReST es una abstracción que a simple vista nada tiene que ver con un diagrama de clases o de entidad-relación!


La representación de los recursos

Una vez identificados los recursos debemos decidir cómo los representaremos en las peticiones y respuestas. HTTP permite cualquier formato, pero normalmente podremos escoger entre XML y JSON debido a que los frameworks suelen tener en cuenta únicamente esos dos formatos. Si escogemos otra manera de representar a los recursos nos tocará hacer las debidas conversiones con nuestro propio código.

La inmensa mayoría de servicios ReST trabajan con JSON puesto que contienen la misma información que un XML pero son más sucintos, a costa de no incluir ninguna descripción de la información que contienen. Veámoslo con un ejemplo:

Lucha de acrónimos

En el XML vemos que hay claramente una lista de clientes. En JSON básicamente sustituimos cada etiqueta xml por un único carácter. Cierto que no queda claro que se trate de clientes y bien pudieran ser ‘empleados’ o ‘personas’ pero no debemos olvidar que en un servicio ReST tenemos una aplicación cliente que es capaz de saber que está solicitando un listado de clientes, no de empleados. El XML en este caso es un despilfarro de ancho de banda.

Las rutas

El siguiente paso una vez que conozcamos cuáles son nuestros recursos será definir las rutas para localizarlos. Debemos ‘colocarlos’ en esos directorios de los que nos habla el protocolo HTTP y es el momento de hacer un inciso relacionado con ellos.
En HTTP localizamos los recursos utilizando URLs. Con una URL identificamos un recurso, su localización y el modo en el que accederemos a él.



En la ruta encontramos los directorios en los que se localiza el recurso identificado por el valor final. Cuando se trata de recursos físicos esos directorios existen realmente. Es lo que sucede, por ejemplo, con un servidor web. En Apache (el servidor web más utilizado) disponemos del directorio ‘www’ dentro del cual organizamos nuestros ficheros .html, .css, imágenes y demás cacharrería. Cuando los recursos son abstractos, representaciones de filas en una tabla u objetos en la memoria del servidor, los situaremos en directorios ficticios para ‘seguirle el juego’ al protocolo HTTP.


Recursos físicos en un servidor Apache de color azul


Una técnica que nos ayuda a definir las rutas es imaginarnos los recursos realmente como ficheros y realizarnos la siguiente pregunta: Si tuviera una serie de ficheros, a razón de uno por ‘Empleado’ ¿en qué directorio los guardaría? ¿Y si fueran facturas, productos o cualquier otra cosa? La respuesta es clara: en los directorios ‘empleados’, ‘facturas’ y ‘productos’.

Los métodos

En HTTP una petición es una ruta a los recursos más una acción, el método. De todos los métodos definidos en HTTP los cinco que sirven para actuar sobre los recursos son

  • GET: se solicitan recursos existentes en el servidor
  • POST: añade un nuevo recurso en la ruta indicada
  • PUT: Sustituye el recurso indicado por la url por el que se envía. Si no existe lo añadirá.
  • PATCH: Modifica el recurso utilizando los datos adjuntos a la petición.
  • DELETE: Elimina los recursos indicados en la url.

En realidad los métodos no hacen nada…todo depende de la implementación del servicio en el lado del servidor. Vamos a suponer que nadie programará que al recibir un GET se elimine un recurso y que cuando se reciba un DELETE se entregen. Suena absurdo, pero es perfectamente posible hacerlo así.

Con esto ya tenemos la base de que es un servicio ReST. En el siguiente post comenzaremos con el diseño de un api sencilla.


Jordan Peterson después de haber leído este artículo





miércoles, 29 de julio de 2020

Spark: la oportunidad


¡Vivimos una explosión de datos! Cada vez más se requieren más personas que sepan analizar y modelar estos datos para obtener la información. El dato es útil. El dato de alta calidad, bien entendido y auditable, no tiene precio. En este artículo vamos a dar una pincelada sobre este entorno de trabajo, un diamante en bruto, llamado Spark.




Obtenemos datos de todos los medios, como Twitter feeds, Facebook, mensajes, SMS, y una gran variedad de medios.  La necesidad de poder procesar esos datos tan rápidamente como sea posible se convierte en más importante que nunca. 

Hace unos pocos años, la programación mediante MapReduce ha sido útil para estos fines, pero la cantidad de tiempo que se tarda en ejecutar los trabajos no es la más aceptable en la mayoría de las situaciones. La curva de aprendizaje para escribir un trabajo MapReduce también es difícil, ya que requiere conocimientos específicos de programación y el know-how. Además en MapReduce los trabajos sólo funcionan para un conjunto específico de casos de uso. Necesitamos algo que funcione para un gran conjunto de casos de uso.


Apache Spark fue diseñado como una plataforma de computación rápida, de uso general y fácil de usar, de ahí viene su nombre: chispa.

Extiende el modelo MapReduce y lo lleva a otro nivel. La velocidad proviene de los cálculos en memoria. 

Las aplicaciones que se ejecutan en un proceso y con una respuesta mucho más rápida. Spark es incluso más rápido que MapReduce para aplicaciones muy complejas usando los discos. Puede ejecutar la aplicación por lotes, o algoritmos iterativos que se basan unos sobre otros. 

Se pueden ejecutar consultas interactivas y procesar datos de flujos continuos con una aplicación. 
Soporta un número de bibliotecas que pueden utilizarse fácilmente, para expandirse más allá de las capacidades básicas de Spark, son:


La gran facilidad de uso de Spark nos permite aprender rápidamente usando los APIs simples para Scala, Python, R y JavaSpark se ejecuta en clústeres Hadoop con YARN  o Apache Mesos, o incluso de manera autónoma con su propio planificador


¿Por qué y para qué querríamos usar Spark?


Spark proporciona procesamiento distribuido paralelo, tolerancia a fallos en hardware de productos básicos, escalabilidad, etc...Añade el concepto de computación agresiva en caché de memoria distribuida, con baja latencia, APIs de alto nivel y pila de herramientas de alto nivel. 

Hay dos grupos que podemos considerar aquí que querrían usar SparkCientíficos de Datos e Ingenieros (Analistas de Datos).

 ¿Pero no son similares?

En cierto sentido, sí, tienen superposición de conjuntos de habilidades, pero para nuestro propósito, vamos a definir al científico de datos como aquellos que necesitan analizar y modelar los datos para obtener información. Tendrían técnicas para transformar los datos en algo que pueden utilizar para el análisis de datos. 
  • Su análisis ad-hoc.
  • Ejecutar consultas interactivas que les proporcionen resultados inmediatamente. 
Los Científicos de datos también tienen experiencia en el uso de SQL, estadísticas, aprendizaje automático y algo de programación, por lo general usando lenguajes como Python o R.

Una vez que los científicos de datos han obtenido la información sobre los datos; más tarde, alguien determina que hay una necesidad de desarrollar una aplicación de procesamiento de datos de producción, una aplicación web, o algún sistema, la persona llamada a trabajar en ello estarían los ingenieros (analistas de Datos).

Los ingenieros (analistas de datos) utilizarían la API de programación de Spark para desarrollar un sistema de casos de uso. Spark paraleliza estas aplicaciones a través de los clústeres mientras se ocultan las complejidades de la programación de los sistemas distribuidos y tolerancia a fallos.  Pueden usar Spark para monitorear, inspeccionar y ajustar las aplicaciones. 

Spark Core, componentes...


El núcleo de Spark (Core) está en el centro de todo. Es un sistema de propósito general que proporciona programación, distribución y supervisión de las aplicaciones a través de un grupo de componentes.

Los componentes en la parte superior del Spark Core que están diseñados para trabajar internamente, dejando que los usuarios los combinen, como lo harían con cualquier biblioteca en un software de proyecto. El beneficio de esta pila es que todos los componentes de la capa superior heredarán las mejoras realizadas en las capas inferiores. 

El Spark Core está diseñado para escalar de uno a miles de nodos. Proporciona la abstracción fundamental de Spark: Resilient Distributed DataSet (RDD):
  • Resilient (Flexible): si se pierden los datos en la memoria, se pueden volver a crear
  • Distribuido: procesado en todo el clúster 
  • DataSet (conjunto de datos): los datos iniciales pueden provenir de una fuente, como un archivo, o pueden ser creados mediante programación

Los RDD son anteriores a Spark SQL y al API de los DataFrame / Dataset.

Spark SQL está diseñado para trabajar con Spark a través de SQL y HiveQL e Impala. Spark SQL permite a los desarrolladores mezclar las consultas de SQL con el lenguaje de programación de Spark elegido: Python, Scala, R o Java. 

Funciona con datos estructurados


DataFrames y Datasets que son la abstracción de los datos estructurados. Posee además un entorno de optimización de las consultas: el Catalyst Optimizer

Spark Streaming proporciona acceso al proceso de flujos de datos en tiempo real. Su API coincide con el de Spark Core, lo que facilita a los desarrolladores moverse entre aplicaciones que procesan los datos almacenados en la memoria y/o llegar a ejecutarlos en tiempo real, proporcionando el mismo grado de tolerancia a fallos, rendimiento y escalabilidad que ofrece el Spark Core.

MLlib, la biblioteca de aprendizaje automático de máquina (Machine Learning), proporciona múltiples tipos de algoritmos que están diseñados para escalar a través del clúster.

GraphX es una biblioteca de procesamiento de gráficos (Graph Processing) con API para manipular gráficos y realizar gráficos computacionales en paralelo.

Los DataFrames y los DataSets son la representación principal de los datos en Spark.
  • Los DataFrames representan datos estructurados en forma de tabla. Son similares a las tablas en un RDBMS. Consisten en una colección de objetos Row (fila) sin escribir. Las filas se organizan en columnas descritas por un esquema. 
  • Los DataSets representan datos como una colección de objetos de un tipo específico. Están fuertemente tipados
  • Realmente un DataFrame es un alias de un Dataset [Row]: conjuntos de datos que contienen objetos Row (filas)
Cómo veis, el entorno de Spark no es difícil ni complicado, simplemente requiere perseverancia para familiarizarse con él y una vez conseguido estaréis en disposición de entrar en un mundo apasionante, desafiante y novedoso tecnológico. Espero que pongáis más de una chispa en vuestro camino.





¡Hasta el próximo post queridos lectores!