Las aplicaciones van creciendo, y el código, como todo sistema organizado, tiene la tendencia natural a orientarse hacia el desorden. Esa tendencia al caos, en los sistemas se llama “entropía”.
Para que las cosas no se nos vayan de las manos, se necesitan esfuerzos tendientes a contrarrestar esa tendencia natural al desorden. En el mundo del desarrollo puede ser en forma de refactor, rearquitectura, rediseño, o muchas otras técnicas.
Una de las maneras habituales que tenemos para manejar problemas complejos es dividirlo en problemas más pequeños, darle solución a cada uno de esos problemas, y luego integrar esas soluciones. Los microservicios surgieron al aplicar esta manera de pensar, convertir problemas complejos en soluciones más parciales, pequeñas y manejables.
Ventajas de los microservicios
- Al partir el problema, puedo solucionar cada parte por separado
- Puedo probar cada parte por separado
- Puedo instalar cada parte por separado
- Puedo cambiar uno de los servicios sin cambiar el resto
- Puedo distribuir esos servicios en distintos equipos
- Puedo aplicar distintas tecnologías en cada servicio
Desventajas de los microservicios
- Contexto de la aplicación, web server, librerías, sistema operativo. Todo tiene que ser levantado nuevamente. Lo que redundará en mayor uso de recursos.
- Mayor dificultad para encontrar un error: si una petición se va repartiendo por distintos módulos, hay que ir buscando la petición en los distintos logs. Hay herramientas que se pueden usar para mitigar esto, como el uso y propagación de ciertos headers a los logs, junto con generación automática de identificador unívoco de petición
- Mayor dificultad para manejar errores cuando suceden. Si tenemos 2 servicios “encadenados” en el que uno persiste un dato, y en función de ese dato, el segundo servicio persiste otro dato, si se produce un fallo en el segundo, hay que deshacer los cambios del primer servicio. Lo que en una arquitectura monolítica puede ser fácilmente manejado con una transacción y un rollback, en microservicios tenemos que hacerlo a mano, y puede llegar a ser imposible volver al estado previo al fallo
Entonces, Aguanten los monolitos?
Por lo general conviene mantener simple las soluciones (ver principio KISS). En ese sentido, el monolito es la expresión más simple de la arquitectura. Llegado un momento, ya sea por complejidad, porque muchas personas se encuentren trabajando en simultáneo, o porque los recursos que consuma el módulo hacen que necesite un servidor gigante para correrlo, el monolito se tornará inmanejable, y necesitaremos partirlo en distintos servicios.
¿Cuándo partir un monolito en servicios?
Obviamente, no hay una fórmula mágica para calcular cada cuánto hay que dividirlos, pero hay diferentes aspectos que podemos contemplar antes de tomar la decisión:
- Independencia de negocio: ¿Qué tan independientes son los conceptos de negocio entre los candidatos a partirse en distintos servicios?¿Hablan de las mismas entidades?
- Independencia de desarrolladores: ¿Necesito que lo manejen distintos equipos?
- Acoplamiento de código: ¿Qué tan independiente/acoplado va a quedar el código de ambos servicios? ¿Cuando querramos agregar o modificar un campo en uno de los servicios, vamos a tener que modificar el otro servicio?
- Diferencia de tráfico: ¿Qué tanto se parece la cantidad de tráfico que reciben los servicios?¿Uno recibiría muchas peticiones, y el otro menos, entonces necesito escalarlos distinto?
- Frecuencia de despliegue: ¿Los servicios van a manejar frecuencias de despliegue distintas? ¿Uno lo voy a desplegar a cada rato, y el otro muy rara vez?
El mejor criterio para tomar estas decisiones es la experiencia y sabiduría. Cosas que lamentablemente se obtienen con los errores. Si nos pasamos de rosca partiendo en servicios, puede que terminemos con un “ABM” distribuido en red.
Aguanten los monolitos!