Los 12 factores para construir microservicios (y SaaS)
La adopción de una arquitectura de software soportada en microservicios para la construcción de grandes sistemas de software tiene entre sus objetivos ofrecer una aplicación escalable, robusta, con cero downtime, alta disponibilidad, soportar grandes números de transacciones en una pequeña unidad de tiempo y ofrecer una mejor experiencia a los clientes finales. En esta entrada vamos a nombrar 12 elementos claves que deben tener en cuenta para construir este tipo de soluciones.
¿Qué son los 12 factores?
Es una metodología, creada por experimentados desarrolladores y devops de la industria del software, que, tras la experiencia en el trabajo en cientos de proyectos han documentado los 12 elementos claves para tener en cuenta en la construcción y puesta en operación de sistemas de Software como Servicio.
La metodología es aplicable según sus creadores a cualquier aplicación SaaS que:
- Usan formatos declarativos para la automatización de la configuración, para minimizar el tiempo y el coste que supone que nuevos desarrolladores se unan al proyecto.
- Tienen un contrato claro con el sistema operativo sobre el que trabajan, ofreciendo la máxima portabilidad entre los diferentes entornos de ejecución.
- Son apropiadas para desplegarse en modernas plataformas en la nube, obviando la necesidad de servidores y administración de sistemas.
- Minimizan las diferencias entre los entornos de desarrollo y producción, posibilitando un despliegue continuo para conseguir la máxima agilidad.
- Pueden escalar sin cambios significativos para las herramientas, la arquitectura o las prácticas de desarrollo.
Los 12 factores a tener en cuenta
1- Código base: El código base debe estar correctamente versionado, recomendado tener ramas listas para desplegar en correcto estado.
2 – Gestión de dependencias: La aplicación debe declarar sus dependencias y manejarlas de forma aislada, pero sin depender de dependencias del sistema operativo base, es recomendado usar mecanismos de gestión de dependencias como Maven o sus equivalentes en los respectivos lenguajes.
3- Configuraciones: Debe evitarse el “hardcode” de las configuraciones en las aplicaciones, en su lugar deben usarse variables de entorno parametrizables para acceder a las configuraciones, es común usar ficheros de configuración para los diferentes entornos con las configuraciones específicas. La aplicación debe ser la misma, lo que cambia es la configuración por entorno.
4- Backing services: Los backing services son todos aquellos recursos a los que se conecta la aplicación que estamos construyendo, bases de datos, apis, servicios de mensajería, colas, etc. Una aplicación “12 factores” debe tener la capacidad de manejar estos recursos como “conectables”, ante un fallo por ejemplo en un servidor de bases de datos este debería poder desconectarse y conectarse a otro RDBMS, este principio está muy vinculado con el número 3.
5- Construir, distribuir y ejecutar: Los procesos de construcción, distribución y ejecución deben estar aislados entre sí. El código listo para desplegar que proviene del repositorio debe ser construido (build), en un proceso en el que se obtienen las dependencias, aplican configuraciones y se construye un binario, el cual se distribuye y llega al entorno de ejecución. Los procesos de entrega continua soportan este principio.
6- Procesos: La aplicación en cuestión se ejecuta como una combinación de uno o mas procesos pero no tienen estado, este es un elemento clave, si la aplicación necesita persistir o almacenar datos deberá usar un backing service para ello. Nunca debe darse por hecho que un recurso cacheado estará disponible en el entorno de la aplicación, puesto que un stop de la aplicación o un reinstall desde el proceso de entrega continua pudo eliminar los datos pre-cacheados y provocar un error. Se debe cumplir con el principio de arquitectura Share nothing.
7- Asignación de puertos: El séptimo de los principios que debe cumplir nuestra aplicación está asociado con la asignación de puertos. Las aplicaciones en Java, PHP o Python que ofrecen APIs suelen ejecutarse en contenedores web, por ejemplo Java puede emplear un servlet container como Tomcat o Jboss, en el que colocamos el war y se produce el despliegue a producción, este mecanismo viola el 7mo principio. La forma correcta es que cada aplicación sea autocontenida en un servidor de aplicaciones propio; ejemplo de ello es una aplicación Spring Boot por ejemplo; por defecto viene con un servidor Tomcat embebido. Todas las aplicaciones deberán proveerse autocontenidas en un servidor de aplicaciones y servir por un puerto en particular establecido en la configuración, al iniciar la aplicación es normal poder acceder a ella tipo http://localhost:8282, otros elementos de la infraestructura se encargarán de crear una URL friendly para el acceso a esta aplicación:puerto desde el exterior. No hay dependencia de un servidor externo para publicar la aplicación y el puerto se define desde la configuración.
8- Concurrencia: En aplicaciones que deben soportar una gran carga de trabajo y realizar tareas más pesadas debe delegarse en determinados procesos la ejecución de estas actividades, sin dejar la función de los hilos que normalmente se implementan en las aplicaciones. La forma correcta o recomendada de aplicar este principio para la concurrencia está inspirada en systemd (de Linux), el desarrollador debe distribuir la carga de trabajo a través de los diferentes procesos. Debe tenerse en cuenta que hay límites reales en los recursos del host donde se ejecuta la aplicación. Los procesos que se levantan, de diferentes categorías se llaman juegos de procesos.
9- Desechabilidad: Como principio la aplicación debe ser desechable, lo que significa que debe estar preparada para finalizaciones inesperadas y aún así concluir correctamente su ejecución. Debe además tener un tiempo de startup muy pequeño para poder recibir trabajos en un corto tiempo luego de que se inician. El uso de una cola donde almacenar la ejecución de los procesos puede ayudar a construir aplicaciones con estas características.
10- Similitud entre los entornos: Los entornos de desarrollo, pre-producción y producción deben ser tan similares como sea posible para reducir los tiempos de puesta en operación tanto como sea posible, siempre teniendo en cuenta que el entorno de desarrollo siempre no esta listo para pasar a producción, pues los desarrolladores pueden tener código que no está terminado, tener en cuenta además en el diseño de las aplicaciones la compatibilidad de los stacks de desarrollo; es normal que en desarrollo se trabaje por ejemplo con una base de datos H2 y Jetty como servlet container y en producción se trabaje con MySQL y tomcat. Este elemento hay que tenerlo en cuenta.
11- Manejo de logs: El historial o eventos de una aplicación que cumple con los 12 factores debe verse como una transmisión o flujo de eventos, el desarrollador no debe preocuparse por programar conectores para enviar los eventos a un fichero o base de datos. Los logs deben enviarse a la salida estándar (stdout) y con herramientas de terceros obtenerse y almacenarse en un sistema para su indexación y análisis.
12- Administración de procesos: El último factor está asociado con la administración de procesos que solo se ejecutan una vez. Es común ante la puesta en operación de algunas aplicación ejecutar procesos o operaciones que tienen lugar una sola vez, ejemplo de ello es ejecutar la migración o importación de datos. Esta metodología recomienda lenguajes que proporcionan una consola del tipo REPL, ya que facilitan las tareas relacionadas con la ejecución de scripts que solo han de usarse una vez.
¿Crees son aplicables los 12 factores? En lo personal creo que hay cuestiones muy interesantes que nos ayudarán a construir mejores aplicaciones para entornos distribuidos, permitiendo lograr los objetivos del diseño de una arquitectura microservicios.
La información completa de la metodología puedes verla acá.