Meiga: Mónadas en Python. Menos excepciones y más tipado en nuestro código

Artur Costa-Pazo

Artur Costa-Pazo

Meiga python

Existen dos tipos de complejidades con las que lidiamos todos los días en nuestros trabajos. La complejidad intrínseca del problema que tratamos de resolver (en nuestro caso la detección de fraude en procesos de video identificación), y la complejidad accidental (todo lo que tenemos que ir resolviendo por el camino que tenga relación, como puede ser la tecnología utilizada o cómo diseñamos nuestros sistemas).

En Alice, controlamos toda nuestra tecnología sin necesidad de depender de desarrollos externos. Y además, nuestro objetivo (hacer un mundo digital más seguro a partir de procesos automáticos de IDV)  es de gran complejidad. Por ello, tenemos que invertir mucho en reducir el ruido que nos puede introducir tener una mala experiencia de desarrollo. Tanto en investigación, como en desarrollo de producto, desarrollamos herramientas que nos ayudan a que el tiempo desde que entrenamos un modelo de inteligencia artificial hasta que nuestros clientes se benefician del valor aportado sea muy pequeño. Hace unos años tomamos la decisión de que todo el equipo compartiera el mismo stack, y no podemos estar más felices con Python 🐍. El uso generalizado de este lenguaje entre desarrollo de producto e investigación nos ayuda a mejorar a todos los equipos y nos facilita mucho la vida a la hora de compartir conocimientos, trucos y herramientas. Además, la gran mayoría de estas herramientas que nos aporta valor, las hacemos Open Source por varios motivos:

  • Cuando expones tú código, la calidad aumenta: Mejor documentación de los casos de uso, issues reportados que ayudan a ver otras perspectivas, etc..
  • Devolver un poquito lo que nos dan todas las comunidades de software libre tanto locales como nacionales para aprender y seguir mejorando el sector.
  • Uso de herramientas de integración continua de manera gratuita para software libre.

Una de las herramientas que publicamos en los inicios de Alice y que seguimos utilizando a día de hoy en todos nuestros desarrollos es nuestra querida meiga 🧙(¡Habelas hailas!).

Esta biblioteca nos permite utilizar las Mónadas, concepto de programación funcional, que nos ayuda a definir nuestro código de retorno de cada función con un valor de éxito (Success) o un valor de fallo (Failure). En el siguiente ejemplo se puede ver cómo definimos los errores conocidos como fallos controlados:


Figura 1. Código muy sencillo para ilustrar cómo tipar una función con meiga.

De esta forma, los errores conocidos, los tipamos como fallos, y dejamos las excepciones para casos no controlados, respetando la definición estándar de las mismas.

Las excepciones son eventos que ocurren durante la ejecución de un programa y hacen que éste salga de su flujo normal de instrucciones.

¿De dónde nos vienen estas ganas por definir mejor los valores de retornos?

Somos un equipo que veníamos de programar mucho en  C, C++ y de crear bindings para Java y Objective-C (teníamos mucha complejidad accidental en nuestros desarrollos 🙂🔫, aunque realmente hacíamos cosas muy chulas como embeber modelos de reconocimiento facial en dispositivos móviles cuando había que picarlos y optimizarlos 🚀). Eran otros tiempos, dónde Python no había entrado tanto en el día a día de la investigación y donde lo estándar era usar Matlab para los “pipelines” de investigación. A medida que las tecnologías fueron avanzando, tuvimos la oportunidad de evolucionar a lenguajes mucho más avanzados, en términos de experiencia de desarrollo (DX), como Kotlin y Swift. Estos lenguajes nos apartaban formas mucho más expresivas y semánticas para modelar nuestro domino. En concreto, la forma en la que la biblioteca Result de Swift simplificaba el como actuar antes las diferentes posibilidades tanto de éxito como de error no gustaba mucho, y fue uno de los gérmenes para crear meiga 🧙.

El otro germen, fue el artículo “Remove visual noise of logging code with python decorators” que nos hizo pensar cómo queríamos que fuera la experiencia de desarrollo para tener todo los bueno de la monitorización y el logging, pero disponiendo de un código expresivo y entendible.

¿Cómo nos ayuda meiga 🧙 en el día a día?

De vez en cuando te entra el síndrome del impostor y te preguntas… ¿por qué no utilizamos excepciones como todo el mundo?  Ahí es cuando hay que preguntar al equipo. ¿En que te ayuda el uso de meiga en tú día a día?, la respuesta suele ser algo parecido a:

“Realmente me parece muy cómodo saber siempre el formato de resultado que voy a recibir. Esto permite que a la hora de testear el código, tanto en la preparación del test como en la aserción, tener muy claro el proceso a seguir sin depender de bibliotecas de terceros.” 

Una de las ventajas que también podemos destacar del uso de meiga a nuestro flujo de trabajo es la de ayudar al IDE a que nos ayude. En un tiempo en el que las LLMs están entrando de lleno en nuestros entornos de desarrollo para ayudarnos a programar (e.g Github Copilot), no hace falta meter una inteligencia artificial de millones de parámetros para que el IDE nos pueda ofrecer una experiencia de desarrollo mucho más rica. Para ello tenemos disponible el tipado de nuestro código, y con meiga, podremos saber los errores de nuestras funciones sin tener que entrar en el código para revisar todas las posibles excepciones. En las siguientes figuras podemos ver un par de ejemplos de esto:


Figura 2. En la parte de arriba se ve la problemática de utilizar las excepciones para devolver errores (no sabemos, sin entrar al código, que posibles errores puede tener la función). Sin embargo, en la solución de abajo (con meiga), sí que podemos saber que errores nos puede devolver la función en caso de que el estado fuera Failure.

Además, gracias a que siempre recibimos un objeto Result (bien tipado), podemos realizar operaciones de programación funcional que nos permiten tener un código mucho más claro, así como un testing más expresivo. En el siguiente apartado presentamos un caso de uso para ilustrar lo que pueden llegar a ser codificarlo con nuestras herramientas, así como la facilidad para testearlo.


Figura 3. Ejemplo de cómo el IDE (en este caso PyCharm), puede inferir el tipo del ejemplo que ponemos al principio del artículo en la Figura 1.

Ejemplo Práctico

En Alice usamos meiga en combinación con FastAPI y petisco (ya hablaremos de él en otro artículo de este proyecto tan chulo 🍪).


Figura 4. Las herramientas que utilizamos para que la experiencia de desarrollo sea óptima.

Con este stack disponible, imaginemos que tenemos un nuevo requisito para nuestra aplicación: tenemos que crear un endpoint que devuelva un HTML con una web agradeciendo a los organizadores/as y a los sponsors todo el trabajo realizado para mejorar la comunidad.

Para ello tendríamos que definir un router con un path y el verbo GET usando FastAPI.


Figura 5. Path definition and Controller execution.

Una vez que definimos nuestro router, podemos definir el Controller, dónde instanciamos el caso de uso, e inyectamos las dependencias a partir del objeto Container de petisco. Además, gracias a meiga + petisco (con el uso de metaclases), podemos tener un mapping entre los errores de dominio definidos en el Result de meiga y los errores HTTP.


Figura 6. Ejemplo de Controller.

En esta Figura 6 podemos ver cómo se añaden dos repositorios y una aplicación de servicio al caso de uso AcknowledgeCreator:

  • OrganizersRepository: dónde recuperaremos una lista de los organizadores de la conferencia (en el ejemplo se pone como una posible implementación, MySQL).
  • SponsorsRepository: dónde recuperamos una lista de los sponsors (en el ejemplo se pone a un Excel como posible implementación, por aquello de que igual a última hora conseguimos algún sponsor adicional 🥳).
  • HtmlFormatter: a partir de la información recuperada por los repositorios generará un html que será lo que finalmente se devuelva en el GET.


Figura 7. Ejemplo de Use Case.

Finalmente, en la Figura 7,  podemos ver qué pinta tendría el caso de uso, dónde cada uno de los colaboradores inyectados se relacionan entre ellos y utilizan meiga para expresar mejor la funcionalidad del código reduciendo muchísimo el ruido visual.

¿Quieres conocer más?

Alice participa activamente en conferencias y comunidades como Python Vigo o la conferencia anual PyCon, que este año 2023, tuvo lugar en Tenerife. Síguenos en LinkedIn y X para conocer nuestras próximas actividades. Cualquier duda contacta con nosotros a través de LinkedIn o escríbenos a hello@alicebiometrics.com

Espera, aún hay más… échale un vistazo a:

Si te ha gustado, comparte en