Arquitectura de software: cuándo el monolito gana

Cuándo un monolito modular conviene más que microservicios en Kubernetes, y cómo dejar abierta la opción de separar.

7 min de lectura

Dos filas de bloques redondeados con una marca de verificación en el último, como un pipeline que llegó al final y un paso que espera

Para la mayoría de los equipos, el monolito modular es el mejor punto de partida. Se despliega como una sola unidad y el build protege los límites entre módulos. Los microservicios sobre Kubernetes se justifican cuando varios equipos necesitan publicar por separado y cada uno puede operar su servicio. Antes de eso, esa infraestructura suma sistemas para mantener.

Esta elección toca el código y también la plataforma que lo corre. En la página de ingeniería de plataforma está descrito el trabajo que rodea esta decisión.

¿Qué diferencia hay entre un monolito modular y los microservicios?

La diferencia está en dónde viven los límites cuando el código ya está corriendo. Los dos estilos dividen la aplicación por capacidad de negocio. Lo que cambia es si esa división también se despliega por separado.

La guía de arquitectura de Microsoft define los microservicios como componentes pequeños, independientes y poco acoplados. Un solo equipo chico puede escribirlos y mantenerlos. Cada servicio debería implementar una sola capacidad de negocio dentro de un contexto delimitado. Cada uno vive en su propia base de código. El servicio guarda sus propios datos y habla con los demás por APIs bien definidas. Así sus detalles internos quedan ocultos para el resto.

El monolito modular usa la misma idea de contextos delimitados. La diferencia es que todos los módulos salen en un solo artefacto. Los módulos se llaman entre sí por interfaces explícitas, dentro del mismo proceso. El build es el que hace cumplir el límite. Por ejemplo, con una regla de dependencias que falla cuando un módulo importa el interior de otro.

Los dos estilos deciden cómo se organiza el código. Los microservicios además te comprometen hoy a desplegar cada pieza por separado. También te comprometen a operar todo lo que da seguridad a ese despliegue separado. El monolito modular toma la primera decisión ahora y deja la segunda abierta.

¿Por qué los equipos eligen microservicios?

Los eligen porque los beneficios que describe Microsoft son reales, y el primero es la agilidad. Como cada servicio se despliega solo, puedes actualizarlo sin volver a desplegar toda la aplicación. Si algo sale mal, puedes hacer rollback de ese cambio puntual. La guía lo compara con las aplicaciones tradicionales. Ahí un bug en una parte puede frenar todo el proceso de release. Las features que no tienen nada que ver quedan esperando mientras el fix pasa por integración y pruebas.

El segundo beneficio es el tamaño del equipo. Un servicio con su propia base de código, a cargo de un equipo chico, es algo que ese equipo puede manejar bien. Lo puede cambiar sin negociar con nadie. La guía también menciona que los servicios pueden ser políglotas. No necesitan compartir el mismo stack tecnológico ni las mismas librerías.

Ahora mira lo que suponen esos beneficios. Cada uno rinde cuando los releases de varios equipos se pisan entre sí. Un solo equipo con un solo producto casi nunca tiene el release bloqueado por el bug de otro equipo. Simplemente no hay otro equipo. Para ese equipo, el despliegue independiente resuelve un problema que todavía no tiene. La libertad de usar varios lenguajes también cuesta, dado que las mismas pocas personas tienen que mantener cada stack.

¿Qué implica operar la infraestructura extra?

Implica sumar sistemas nuevos que alguien tiene que operar y actualizar. Microsoft avisa desde el arranque que el cambio va más allá del código. Dice que una arquitectura de microservicios exitosa pide un cambio de fondo en la forma de pensar. No alcanza con partir la aplicación en servicios más chicos.

Después lista los componentes que aparecen al lado de los servicios. La orquestación programa y despliega servicios entre nodos. También se recupera de fallas y escala según la demanda. Normalmente eso lo da una plataforma de contenedores como Kubernetes. Un API gateway pasa a ser la puerta de entrada para los clientes. Se ocupa de temas transversales como la autenticación y el logging. Proxies como Envoy y Nginx llevan el tráfico entre servicios. Plataformas de mensajería como Apache Kafka o Azure Service Bus llevan los eventos asincrónicos. La observabilidad necesita logging centralizado y tracing distribuido, que sigue cada request entre servicios. Y los datos se descentralizan, porque cada servicio es dueño de sus datos y su esquema.

Cada ítem de esa lista es un sistema que alguien tiene que mantener al día. Alguien también tiene que atender las alertas cuando algo se rompe. Así se ven los dos estilos lado a lado.

Tema Monolito modular Microservicios sobre Kubernetes
Deploy Un artefacto, un pipeline Un pipeline por servicio, más el orquestador
Puerta de entrada La aplicación misma Un API gateway delante de cada request
Llamadas entre partes Llamadas dentro del proceso por interfaces de módulo Llamadas a APIs entre servicios, a menudo por un proxy o un broker de mensajes
Datos Una base de datos, tablas con dueño por módulo Cada servicio es dueño de sus datos y su esquema
Seguir un request Logs y stack traces de un solo proceso Logging centralizado y tracing distribuido
Escalado Se escala la unidad entera Cada servicio escala solo según la demanda
Acople de releases Todos los módulos salen juntos Cada servicio sale con su propio calendario

Lo de la columna de la derecha es el precio de esa independencia. Si no la necesitas, estás pagando componentes cuyo trabajo principal es que el despliegue independiente no rompa nada.

¿Cuándo deja de convenir Kubernetes?

Deja de convenir cuando no hay varios equipos que se bloqueen entre sí. Una vez que tienes cluster, gateway, broker y tracing, el costo es casi fijo. El beneficio, en cambio, crece con la cantidad de equipos que de otro modo se trabarían. De ahí sale una prueba práctica.

Separar en servicios suele valer la pena cuando:

  • Varios equipos se traban los releases entre sí, con frecuencia, porque comparten el mismo código. Es el problema que ataca el argumento de agilidad de Microsoft.
  • Una parte del sistema tiene una carga muy distinta al resto y necesita escalar sola.
  • Cada equipo puede sostener el deploy y la guardia de lo que publica.
  • Alguien es dueño del orquestador y del stack de tracing como producto. Casi siempre es un equipo de plataforma, y en ingeniería de plataforma vs DevOps vs SRE está quién hace qué.

Deja de justificarse cuando un solo equipo es dueño de todo el producto. También cuando la mayoría de los cambios cruzan los límites entre módulos igual. Y cuando actualizar el cluster o configurar el gateway no es trabajo de nadie. En ese caso se hace tarde o directamente no se hace.

Una prueba rápida que puedes correr hoy: mira los últimos releases que se demoraron y pregúntate por qué. Si la causa fue el código de otro equipo, el argumento de agilidad aplica. Si fue tu propio código o tu propio pipeline, separar en servicios no lo arregla.

Hay un camino intermedio para cuando una sola pieza de verdad necesita estar separada. Microsoft menciona plataformas administradas como Azure Container Apps, con orquestación administrada y escalado incluido. Según la guía, estas herramientas bajan la complejidad del deploy y la carga operativa. Correr un servicio extraído en una plataforma así le da despliegue independiente a esa pieza. Y no tienes que operar un cluster de Kubernetes propio. Si quieres ver qué implica operar uno, qué es Kubernetes y cuándo no lo necesitas lo cubre.

¿Cómo dejar abierta la opción de separar después?

Escribe el monolito como si los límites entre módulos fueran límites entre servicios. La descripción de Microsoft de un servicio sirve como checklist para un módulo. Es dueño de una capacidad de negocio y de sus datos. Las otras partes llegan a él solo por una interfaz definida.

Primero que nada, dale a cada módulo una interfaz pública y deja todo lo demás interno. Mantén las tablas de cada módulo privadas, para que ningún otro módulo las consulte directo. Esto va en línea con la guía, que dice que ser dueño de los datos reduce las dependencias entre servicios. Después suma un chequeo en el build que falle cuando un módulo importa el interior de otro. Si ya tienes eso, extraer un módulo más adelante es ponerlo detrás de una API de red. No tienes que desenredar tablas compartidas antes.

Antes de separar nada, mide la entrega. Si el lead time y la tasa de fallas en cambios están sanos, probablemente no tienes el problema que resuelven los microservicios. En métricas DORA: cómo medirlas y mejorarlas está cómo tomar esos números. Si muestran equipos que se bloquean, yo extraería solo el módulo que lo causa. Y decidiría temprano quién es dueño de la plataforma que queda abajo, algo que cubre ¿construir o comprar tu plataforma interna de desarrollo?. Cuando ya corren varios servicios, promover releases entre ambientes con seguridad ya es un tema aparte. Para eso está Argo CD y Kargo: cómo promover releases con seguridad.

Fuentes

  • arquitectura de software
  • microservicios
  • Kubernetes
  • ingeniería de plataforma

Leer este artículo en inglésLeer este artículo en portugués

Nuevas publicaciones por email

Notas sobre tarifas, ingeniería de plataforma, DevOps, SRE, QA e ingeniería de IA, con los precios y las cifras de nuestro propio trabajo.

DX Clouditive LLC (7901 4th St N, Ste 300, St Petersburg, FL 33702, EE. UU., info@dxclouditive.com) te enviará los artículos nuevos y un resumen semanal cuando confirmes. Puedes retirar tu consentimiento cuando quieras con el enlace de baja de cualquier email. Lee nuestra política de privacidad. Puedes darte de baja cuando quieras desde cualquier email.

Sigue leyendo

Todos los artículos

¿Qué necesitas resolver?

Respondemos cada pedido en 1 día hábil. Firmamos un NDA antes de la llamada si lo pides.