Créditos de la fotografía: Lucas  de Lara

El auge de los microservicios prometió una mayor agilidad, escalabilidad y autonomía para los sistemas de software. Muchas organizaciones, ansiosas por aprovechar estos beneficios, adoptaron microservicios solo para enfrentarse más tarde a una complejidad imprevista, costos incrementados y sobrecarga operativa. En algunos casos, la transición de regreso a un monolito modular, donde una aplicación desplegable única se organiza en módulos distintos e independientes, ha demostrado ser una solución más eficiente en ciertos casos de uso.

Los monolitos no son tu enemigo, como comenté hace unos cuantos años.

Introducción: Mi Viaje Personal en la Arquitectura de Software

Durante los últimos años, he trabajado con diversas empresas para implementar soluciones de software utilizando tanto arquitecturas de microservicios como monolíticas. En mi experiencia, he observado que no existe una solución única para todos los problemas; cada enfoque tiene sus propios beneficios y desafíos. En este artículo, compartiré algunas lecciones aprendidas y exploraré cómo un monolito modular puede ofrecer un equilibrio entre simplicidad y modularidad.

Desafíos de los Microservicios: Una Realidad Inesperada

Cuando los microservicios comenzaron a ganar popularidad, prometían una serie de beneficios tentadores:

  • Escalabilidad: Cada microservicio puede escalar de manera independiente.
  • Autonomía: Los equipos pueden poseer, construir y desplegar servicios de forma independiente.
  • Resiliencia: La falla de un servicio generalmente no derriba todo el sistema.

Sin embargo, en la práctica, estos beneficios a menudo vienen acompañados de desafíos significativos:

  • Complejidad Operacional: Gestionar docenas o cientos de microservicios requiere prácticas DevOps sofisticadas, monitoreo y orquestación.
  • Sobrecarga de Comunicación: Los microservicios dependen de llamadas de red para la comunicación, lo que puede llevar a una mayor latencia y puntos de fallo.
  • Consistencia de Datos: Mantener la consistencia transaccional a través de servicios distribuidos a menudo requiere patrones complejos.
  • Proliferación de Servicios: La sobrecarga de gestionar numerosos servicios pequeños puede superar sus beneficios.

La Propuesta del Monolito Modular

Un monolito modular combina la simplicidad de una arquitectura monolítica con la organización interna y modularidad de los microservicios, ofreciendo muchos de los beneficios de ambos enfoques. A continuación, se detallan algunas de las ventajas clave:

  • Unidad Desplegable Única: Simplifica las operaciones, monitoreo y escalado.
  • Límites Claros de Módulos: El sistema se divide en módulos bien definidos e independientes, encapsulando dominios de negocio específicos.
  • Depuración y Mantenimiento Más Fácil: Todo el código se ejecuta en el mismo proceso, facilitando la depuración y el rastreo de problemas.

Lecciones Aprendidas de Implementaciones Reales

En mi experiencia trabajando con diferentes clientes, he visto cómo los desafíos de los microservicios pueden llevar a las empresas a reconsiderar sus elecciones arquitectónicas. Un monolito modular puede ser particularmente beneficioso en situaciones donde:

  • Sobredimensionamiento para Sistemas Pequeños a Medianos: Los microservicios pueden introducir complejidad innecesaria en sistemas de baja complejidad.
  • Consideraciones de Costos: Ejecutar y orquestar múltiples microservicios puede volverse costoso.
  • Tamaño del Equipo y Coordinación: Los equipos más pequeños pueden encontrar difícil gestionar la independencia requerida por los microservicios.

Puntos habituales que se repiten cuando pasamos de Microservicios a un Monolito Modular

  1. Analizar el escenario actual y buscar los problemas que tenemos: Describir el mapa de dependencias y ver dónde tenemos los problemas (sobrecarga operativa, cuellos de botella, uso excesivo de colas para evitar el acoplamiento, etc.).
  2. Agrupar los microservicios en módulos: Lo habitual es que los microservicios de un bounded context sean un solo módulo. En otras palabras es definir los límites claros para cada módulo y encapsulando su lógica.
  3. Mover a una infraestructura compartida: Tanto los servicios web como los datos deben ser consolidados; asegúrate de que tu nuevo sistema de base de datos pueda manejar todo el contenido, no como antes que eran piezas más pequeñas.
  4. Refactorizar las comunicaciones: Modificar las llamadas a servicios internos en lugar de llamadas HTTP.
  5. Simplificar la canalización de despliegue: Unificar la canalización CI/CD para el monolito y usar feature flags para la entrega continua.
  6. Integración y pruebas: Asegurar que los módulos integrados funcionen correctamente y realizar pruebas exhaustivas para validar la funcionalidad del monolito. En mi experiencia, las pruebas unitarias suelen ser prácticamente copiar y pegar de los microservicios originales. Muchas pruebas de integración desaparecen, ya que las interacciones internas se simplifican; generalmente, solo se mantienen las pruebas de base de datos, lecturas de ficheros y llamadas a APIs de terceros. Las pruebas de extremo a extremo (E2E) cambian mínimamente, ya que solo necesitan apuntar a los nuevos endpoints del monolito. Además, las pruebas de carga deben ajustarse para reflejar la nueva arquitectura y asegurar que el monolito puede manejar el tráfico esperado de manera eficiente.
  7. Descomisionado de los microservicios en favor del monolito: Una vez que un módulo del monolito modular esté completamente funcional y probado, descomisiona los microservicios correspondientes. Utiliza patrones como el Strangler Fig Pattern para reemplazar partes del sistema antiguo de microservicios con el nuevo monolito sin interrumpir el servicio. Este patrón es especialmente útil en los puntos 1 y 2, ya que te ayudará a identificar y cortar las partes problemáticas del sistema actual mientras agrupas los microservicios en módulos. Asegúrate de redirigir el tráfico y las dependencias hacia el monolito de manera controlada.

Beneficios de Moverse hacia un Monolito Modular

  • Mejora del Rendimiento: Al consolidar servicios que se comunicaban frecuentemente en un solo módulo, se puede observar una reducción significativa en la latencia de la red. Dado que la comunicación dentro del módulo se realiza a través de llamadas de función en lugar de a través de la red, el sistema se vuelve mucho más receptivo. Esto es crucial para operaciones sensibles al tiempo, como en un sistema de reservas en tiempo real.
  • Reducción de la Complejidad: Fusionar servicios relacionados en módulos más grandes simplifica la arquitectura en general, reduciendo la carga cognitiva en los desarrolladores. Los equipos ya no tienen que gestionar cientos de servicios independientes con APIs separadas, canalizaciones de despliegue y dependencias. La reducción en el número de servicios también simplifica el monitoreo y la resolución de problemas, ya que hay menos servicios que rastrear y diagnosticar en caso de un problema.
  • Costos Operativos Más Bajos: La consolidación de servicios en módulos reduce los costos de infraestructura asociados con la ejecución y gestión de microservicios individuales. Menos servicios significan menos necesidad de escalado independiente y menor complejidad de orquestación.
  • Gestión de Datos Más Sencilla: Con menos servicios independientes que gestionar, se puede simplificar la estrategia de gestión de datos. Al reducir el número de servicios distribuidos que requieren sincronización, la complejidad de manejar arquitecturas impulsadas por eventos y consistencia eventual se minimiza. Esto mejora la capacidad de manejar transacciones y mantener la integridad de los datos en todo el sistema.

Impacto en la Cultura y la Colaboración del Equipo

Uno de los aspectos más importantes de la transición a un monolito modular es el impacto en la cultura del equipo y la colaboración. En un entorno de microservicios, los equipos a menudo trabajan de manera aislada en sus propios servicios, lo que puede llevar a una falta de comunicación y coordinación. Con un monolito modular, los equipos trabajan más estrechamente juntos, lo que fomenta una mejor colaboración y un entendimiento compartido del sistema completo. Esto puede resultar en ciclos de desarrollo más rápidos y una mayor cohesión del equipo.

Es comprensible que algunas personas puedan considerar que volver a una arquitectura monolítica es un paso atrás o un desprestigio, especialmente en una industria donde las modas y las tendencias pueden influir fuertemente en las decisiones arquitectónicas. Sin embargo, es importante recordar que elegir una arquitectura debe basarse en las necesidades específicas del proyecto y no en lo que está de moda.

Para aquellas personas que sienten presión al tomar decisiones arquitectónicas, es útil recordar que la experiencia y el conocimiento adquirido al trabajar con diferentes arquitecturas son valiosos. Es fundamental compartir las lecciones aprendidas y los pros y contras de cada enfoque. Si has trabajado con microservicios y ahora estás considerando o ya has realizado una transición a un monolito modular, asegúrate de comunicar claramente los beneficios que has observado, así como las dificultades que has superado.

Si te encuentras en una posición donde la moda parece dictar las decisiones arquitectónicas, aquí hay algunas recomendaciones:

  • Compromiso con la Experiencia: Comparte tu experiencia previa con microservicios y monolitos modulares. Explica cómo cada enfoque ha funcionado en diferentes contextos y qué desafíos y beneficios has encontrado.
  • Enfoque en los Beneficios Reales: Destaca los beneficios prácticos que has observado con el monolito modular, como la reducción de la complejidad operativa, la mejora del rendimiento y la mayor colaboración del equipo.
  • Evitar la Presión de las Modas: Recuerda y comunica que la arquitectura de software no debe ser dictada por modas. Lo más importante es elegir la solución que mejor resuelva los problemas específicos y se adapte a las necesidades del proyecto y del equipo.
  • Evaluación Continua: Fomenta una cultura de evaluación continua y adaptación. Lo que funciona hoy puede necesitar ajustes mañana, y estar abierto a cambiar de enfoque según las necesidades evolutivas del negocio y la tecnología es crucial.
  • Documentación y Educación: Mantén una documentación clara de las decisiones arquitectónicas y las razones detrás de ellas. Educa a tu equipo sobre los diferentes enfoques y sus implicaciones para que todos estén alineados y comprendan por qué se han tomado ciertas decisiones.

Al final del día, la arquitectura de software debe ser una herramienta para resolver problemas de manera eficiente y efectiva, no una cuestión de seguir las tendencias del momento. La clave es encontrar el equilibrio adecuado que permita a tu equipo trabajar de la manera más productiva y armoniosa posible, sin dejarse abrumar por las modas.

Conclusión: ¿Es el Monolito Modular la Opción Correcta para Tu Aplicación?

La elección entre microservicios y un monolito modular depende de las necesidades específicas de tu proyecto y organización, no es una moda como explico en el apartado anterior.

En mi experiencia, he visto que los monolitos modulares pueden ofrecer una solución más equilibrada para muchos casos de uso, especialmente cuando la complejidad y los costos operativos de los microservicios se vuelven inmanejables.

Un monolito modular proporciona la simplicidad de un monolito con la modularidad y flexibilidad de los microservicios. Para muchas organizaciones, representa un enfoque más pragmático y rentable para lograr agilidad y escalabilidad sin la complejidad de gestionar un sistema distribuido.

Entonces, ¿Cómo elijo la arquitectura adecuada?

La clave para una arquitectura de software es elegir el enfoque que mejor se adapte a las necesidades y desafíos específicos de tu proyecto. Tanto los microservicios como los monolitos modulares tienen sus propios beneficios y limitaciones. Al comprender profundamente las características y requisitos de tu sistema, podrás tomar una decisión informada sobre qué arquitectura adoptar. No te dejes llevar por las modas; lo importante es lo que funcione mejor para tu situación particular.

En última instancia, la flexibilidad y la disposición para adaptarse a medida que evolucionan las necesidades del negocio y la tecnología son cruciales. No hay una solución única para todos, y lo que funciona hoy puede necesitar ajustes mañana. La capacidad de evaluar continuamente y ajustar tu arquitectura será un factor determinante en el éxito a largo plazo de tus proyectos de software.

Además, cabe destacar que actualmente existe una tendencia de moverse a soluciones on-premise en lugar de la nube para muchas organizaciones, debido a los costos asociados con el uso del cloud. Esto subraya aún más la importancia de no dejarse llevar por las modas y de elegir la arquitectura y la infraestructura que mejor se adapten a las necesidades y al presupuesto de tu organización.