Be Software Architecture Wise
Be Wise Apps

Read in English · Lire en français · Auf Deutsch lesen

Sección 5.8 de 5.8 · Intermedio · 24 min de lectura

Cuándo un monolito es la respuesta correcta

Videolección

5 min · narrado en inglés, con subtítulos
Solo escuchar (audio)
Leer la transcripción

Antes de que el Capítulo seis cruce la red, merece la pena preguntarse directamente: ¿cuándo es un monolito la respuesta correcta? Verás los argumentos, hasta dónde puede escalar un monolito y las pruebas que indican que ha llegado el momento de dividir.

Un restaurante nuevo suele empezar con una sola cocina, en la que cada cocinero puede ver y ayudar a todos los demás. Abrir cinco cocinas separadas por toda la ciudad el primer día, cada una con su propio personal, sus entregas y su encargado, costaría mucho más y convertiría cada cambio en la carta en una negociación. Solo cuando esa única cocina está realmente desbordada, o un plato necesita un equipo especial, tiene sentido abrir otra. Con el software pasa algo parecido. Y recuerda: monolito describe el despliegue, no la calidad.

En 2015, Martin Fowler esbozó la prima de los microservicios. Es solo ilustrativo, sin datos reales. En el eje horizontal está la complejidad; en el vertical, la productividad. Los microservicios traen costos propios: desplegar muchas unidades, monitorización, fallos parciales, API versionadas. Por debajo de cierta complejidad, eso es una prima que no aporta nada. Es cierto que un monolito se vuelve más lento a medida que crece. Solo más allá del cruce compensan los microservicios. Fowler también observó que casi todos los sistemas de microservicios exitosos empezaron como un monolito que creció demasiado, y que casi todos los construidos como microservicios desde cero acabaron en serios problemas. Es difícil encontrar buenos límites antes de entender el dominio.

David Heinemeier Hansson, creador de Ruby on Rails, defendió los equipos pequeños en The Majestic Monolith: no distribuyas tu computación salvo que de verdad tengas que hacerlo. Stefan Tilkov defendió la postura contraria: dividir un monolito más adelante suele ser más difícil de lo esperado, porque sus partes acaban fuertemente acopladas. Las dos posturas están más cerca de lo que parece. Ambas dicen que lo difícil son los límites, y un monolito cuyos módulos se hacen cumplir desde el primer día responde a la mayor parte de la inquietud de Tilkov.

Entonces, ¿cuándo es adecuado un monolito? Con un equipo pequeño: el costo de comunicación que eliminan los microservicios es bajo, pero su costo operativo no. Con un dominio incierto o un producto en fase temprana. Mover un límite entre módulos es una refactorización; moverlo entre servicios es una migración. Cuando necesitas consistencia fuerte. Una única transacción de base de datos que abarca pedidos y pagos es sencilla y correcta en un monolito. Cuando la capacidad de operaciones es limitada, porque cada servicio necesita su propio pipeline, su monitorización y sus conocimientos para las guardias. Y cuando las partes del dominio se comunican mucho entre sí. Las llamadas dentro del proceso tardan de nanosegundos a microsegundos; las llamadas de red tardan milisegundos y pueden fallar. En todos los casos, que sea un monolito modular.

Una creencia extendida es que los monolitos no pueden escalar. Escalan más de lo que la mayoría de los sistemas llegan a necesitar. Ejecuta muchas copias idénticas detrás de un balanceador de carga, lo que solo funciona si la aplicación es sin estado. Así, las sesiones y las cachés están en un almacén compartido, y cualquier réplica puede atender cualquier solicitud. Todas las escrituras van a la base de datos principal, mientras que las réplicas de lectura, un poco por detrás, atienden el historial de pedidos y los informes. Y el trabajo lento, como los correos electrónicos y las liquidaciones, va a una cola. Los procesos en segundo plano se encargan de él a partir de ahí. Ejecutan el mismo código con un comando de arranque distinto, así que los roles web y worker escalan por separado.

Pongámoslo a prueba con cifras ilustrativas. Una start-up de reparto de comida con siete ingenieros espera un pico de mil doscientas solicitudes por segundo en un plazo de dos años. Una réplica atiende ciento ochenta dentro de su objetivo de tiempo de respuesta. Mil doscientas entre ciento ochenta es aproximadamente seis punto siete, así que siete réplicas. Con alrededor de un cincuenta por ciento de margen de capacidad, suficiente para sobrevivir a la caída de una zona de disponibilidad, son unas once en el pico. Alrededor del quince por ciento de las solicitudes escriben en la base de datos, cada una con unas tres escrituras. Eso son unas quinientas cuarenta escrituras por segundo, muy dentro de lo que admite una única base de datos principal PostgreSQL. Una caché para las cartas absorbe la mayoría de las lecturas, y dos réplicas de lectura se encargan del historial de pedidos y los informes. Así que un único código base, ejecutado como unas once réplicas web más los workers, cumple el objetivo. El presupuesto de arquitectura se dedica a los límites de los módulos y a la ausencia de estado, no a dividir.

¿Cuándo ha llegado el momento de dividir? Cuando hay pruebas de que una unidad de despliegue es la restricción: los equipos se esperan unos a otros y las pequeñas correcciones hacen cola durante días detrás de trabajo no relacionado. O cuando un módulo, como el seguimiento de repartidores en tiempo real, necesita en el pico cincuenta veces la capacidad del resto, o debe seguir funcionando cuando todo lo demás está caído. O cuando una parte tiene necesidades distintas, como los datos de tarjetas, que justifican una unidad separada y estrictamente controlada. El código lento no es una razón; dividir no lo arreglará. Después, divide de forma incremental, un módulo cada vez, siguiendo los contextos delimitados, empezando por el que tenga el límite más claro y la razón más fuerte para salir.

Con esto termina el Capítulo cinco. La sección completa incluye una guía de decisión, una comparación de todos los estilos del capítulo y una lista de comprobación para un monolito sano. Cuando estés listo, haz la prueba opcional del capítulo y después pasa al Capítulo seis, donde llevamos estas preguntas a través de una red. Bien hecho.

Lo que necesitas saber

La pregunta que hay detrás del capítulo

Todos los estilos de este capítulo se despliegan como una sola unidad. El Capítulo 6 lleva las mismas preguntas a través de una red, donde cada llamada puede fallar, ser lenta o llegar dos veces. Antes de cruzar esa línea, merece la pena preguntarse directamente: ¿cuándo es un monolito la respuesta correcta? Durante buena parte de la década de 2010, la respuesta por defecto del sector fue "rara vez", y muchos equipos dividieron sistemas jóvenes en microservicios porque grandes empresas famosas lo habían hecho. Una década de experiencia ha producido una visión más equilibrada, y esta sección la expone.

La palabra monolito requiere cuidado. Como explicó la Sección 5.1, describe el despliegue (una unidad que se compila, se prueba y se lanza en conjunto), no la calidad interna. Un monolito puede ser un sistema modular bien estructurado o una gran bola de barro, y lo mismo vale para un conjunto de servicios. Muchos de los problemas que se achacan a los monolitos son en realidad problemas de mala modularidad, y dividir en servicios un sistema mal modularizado produce una gran bola de barro distribuida, que es peor.

MonolithFirst y la prima de los microservicios

En mayo de 2015, Martin Fowler describió la prima de los microservicios (microservice premium): los microservicios traen costos reales propios (despliegue automatizado de muchas unidades, monitorización, gestión de fallos parciales, consistencia eventual, API versionadas entre equipos), y esos costos frenan a un equipo a menos que el sistema sea lo bastante complejo como para que los microservicios los compensen. Su consejo era partir por defecto de un único monolito bien modularizado y pasar a microservicios solo cuando la complejidad lo exija.

Un mes después, en un artículo titulado MonolithFirst (junio de 2015), añadió dos observaciones de los proyectos que había visto: casi todos los sistemas de microservicios exitosos habían empezado como un monolito que creció demasiado y luego se dividió, y casi todos los sistemas construidos como microservicios desde cero habían acabado en serios problemas. Una razón es que es difícil encontrar buenos límites entre servicios antes de entender el dominio, y un límite equivocado entre servicios es mucho más caro de mover que un límite equivocado entre módulos. Describió varias vías: construir un monolito e ir desgajando servicios de sus bordes más adelante; construir un monolito deliberadamente desechable; o empezar con unos pocos servicios de grano grueso y dividirlos más cuando los límites se asienten.

La prima de los microservicios

Boceto conceptual de la prima de los microservicios: la productividad del monolito cae más rápido con la complejidad, pero los microservicios parten más abajo; solo se cruzan con alta complejidadComplejidad base del sistema y de la organizaciónProductividadMonolitoMicroservicioscrucePrima: costo de operar muchosservicios cuando no aporta nadaMonolito lentocuando creceSolo ilustrativo, según el boceto de Martin Fowler (2015); sin datos reales
Un boceto conceptual: los microservicios solo compensan a partir de cierto nivel de complejidad; por debajo de él, su costo operativo es una prima que no aporta nada.

El monolito majestuoso y la postura contraria

En febrero de 2016, David Heinemeier Hansson, creador de Ruby on Rails, publicó "The Majestic Monolith" en el blog Signal v. Noise. Describió Basecamp, construido entonces por un equipo de una docena de programadores, como una aplicación integrada que servía a clientes web, móviles, de escritorio y de correo electrónico, y sostuvo que los equipos pequeños deberían apostar por un monolito bien hecho en lugar de copiar la arquitectura de organizaciones con miles de ingenieros. Su frase clave fue ¡No distribuyas tu computación!, salvo que de verdad tengas que hacerlo.

No todos los profesionales están de acuerdo. También en junio de 2015, Stefan Tilkov sostuvo en el sitio de Fowler, en "Don't start with a monolith", que dividir un monolito más adelante suele ser más difícil de lo esperado, porque sus partes acaban fuertemente acopladas a través de bibliotecas compartidas, objetos de dominio y la base de datos. Si el sistema es claramente lo bastante grande como para justificar partes separadas y el dominio se entiende bien, recomendaba diseñar subsistemas separados desde el principio. Las dos posturas están menos alejadas de lo que parece: ambas dicen que lo difícil son los límites, y un monolito cuyos módulos se hacen cumplir desde el primer día (Sección 5.3) responde a la mayor parte de la inquietud de Tilkov.

Los casos reales apuntan en ambas direcciones, pero comparten una lección. Segment describió en 2018 cómo había consolidado más de 140 servicios pequeños de nuevo en un único servicio después de que la sobrecarga operativa y unas bibliotecas compartidas cada vez más divergentes frenaran la entrega; Amazon Prime Video pasó en 2023 una carga de trabajo de monitorización de componentes serverless distribuidos a un único proceso (consulta la Sección 1.3). Del mismo modo, las organizaciones con cientos de equipos, como los casos a gran escala de la Sección 6.3, obtienen una independencia real de los servicios. La lección es el encaje: el estilo de despliegue debe corresponder a la organización, a la madurez del dominio y a las cualidades que se exigen.

Cuándo un monolito es la respuesta correcta

Un equipo pequeño. Con uno o unos pocos equipos, el costo de comunicación que eliminan los microservicios es bajo, mientras que su costo operativo es el mismo que para una organización grande. Un monolito permite que todos entiendan y cambien el sistema completo.

Un dominio incierto o un producto en fase temprana. Cuando aún estás descubriendo qué es el producto, los límites se moverán. Mover un límite entre módulos es una refactorización; moverlo entre servicios es una migración con datos, API y despliegues.

Necesidades de consistencia fuerte. Una única transacción de base de datos que abarca pedidos, pagos y existencias es sencilla y correcta en un monolito. Entre servicios necesita sagas, bandejas de salida y compensaciones (Sección 6.7).

Capacidad de operaciones limitada. Cada servicio necesita su propio pipeline, su monitorización, sus alertas, sus reglas de escalado y sus conocimientos para las guardias. Un equipo sin una plataforma para todo esto dedicará su tiempo a la fontanería.

Interacciones sensibles al rendimiento. Las llamadas dentro del proceso tardan de nanosegundos a microsegundos; las llamadas de red tardan milisegundos y pueden fallar. Las interacciones muy frecuentes entre partes del dominio son mucho más baratas dentro de un mismo proceso.

En todos estos casos, la forma recomendada es un monolito modular, no uno sin estructura. Mantiene abierta la opción de extraer servicios, como explica la Sección 5.3.

Escalar un monolito

Una creencia extendida es que los monolitos no pueden escalar. Escalan más de lo que la mayoría de los sistemas llegan a necesitar, usando el eje X del cubo de escalado descrito por Martin Abbott y Michael Fisher (ejecutar muchas copias idénticas) junto con unas pocas tácticas estándar. El Capítulo 9 trata cada una en profundidad (Sección 9.1).

Réplicas horizontales detrás de un balanceador de carga. Ejecuta muchas copias idénticas de la aplicación y reparte las solicitudes entre ellas. Esto solo funciona si la aplicación es sin estado (stateless): las sesiones, los archivos subidos y las cachés deben estar en almacenes compartidos, para que cualquier réplica pueda atender cualquier solicitud (Sección 9.2). También aporta redundancia: que falle una réplica ya no detiene el servicio.

Réplicas de lectura. La mayoría de los sistemas leen mucho más de lo que escriben. Las réplicas de lectura de la base de datos copian los cambios de la principal y atienden lecturas como el historial de pedidos y los informes, a costa del retardo de replicación (replication lag): una réplica puede ir una fracción de segundo por detrás (Sección 7.4).

Caché. Las cartas, las páginas de producto y la configuración cambian rara vez y se leen constantemente; guardarlas en caché en memoria o en una caché compartida elimina la mayor parte de la carga de la base de datos (Sección 7.6). Los recursos estáticos van a una CDN.

Procesos en segundo plano. El trabajo lento o a ráfagas (correos electrónicos, facturas en PDF, importaciones, liquidaciones) va a una cola y lo procesan procesos en segundo plano (workers). Los workers suelen ejecutar el mismo código base con un comando de arranque distinto, así que el sistema sigue siendo un único código base, pero los roles web y worker escalan por separado (Sección 9.3).

Máquinas más grandes y particionamiento. El escalado vertical de la base de datos suele ser el siguiente paso más sencillo. En sistemas muy grandes, los datos pueden particionarse por cliente (tenant) o por región, con una copia completa del monolito por partición (el eje Z del cubo de escalado). Stack Overflow es un ejemplo conocido de hasta dónde puede llegar un diseño mayoritariamente monolítico: según el informe de sus propios ingenieros, un día de febrero de 2016 sus balanceadores de carga gestionaron unos 209 millones de solicitudes HTTP, con la aplicación principal de Q&A (una aplicación multicliente para todos sus sitios de Q&A) funcionando en nueve servidores web principales, y cuatro máquinas SQL Server atendiendo a toda la red.

Un monolito escalado horizontalmente

Escalar un monolito: réplicas idénticas sin estado detrás de un balanceador de carga, una caché y un almacén de sesiones compartidos, una BD principal con réplicas de lectura y workers alimentados por una cola, todo con el mismo código baseBalanceadorMisma compilación, copias sin estadoRéplica 1rol webRéplica 2rol webRéplica 3rol webWorkersmismo código, rol workerCaché + sesionesp. ej. RedisBD principalescriturasRéplicas lect.informes, listasCola tareascorreos, liquid.replicación (retrasada)encolaconsumeMás réplicas para mássolicitudes; más workerspara más tareas de fondo
Un código base, muchas copias: réplicas web sin estado detrás de un balanceador de carga, caché y sesiones compartidas, una base de datos principal con réplicas de lectura y workers alimentados por una cola.

Ejemplo práctico

Ejemplo práctico: ¿hasta dónde llega un monolito?

Una nueva start-up de reparto de comida tiene 7 ingenieros y espera, para finales del segundo año, un pico de 1200 solicitudes HTTP por segundo a la hora de la cena del viernes. Una prueba de carga del monolito modular muestra que una réplica (4 vCPU) atiende 180 solicitudes por segundo dentro del objetivo de p95 de 300 ms. Alrededor del 85% de las solicitudes son lecturas (cartas, seguimiento de pedidos). Las cifras son ilustrativas.

Réplicas para el pico1200 / 180 = 6.7, así que 7 réplicas en el pico
Margen de capacidad (headroom)Mantén la utilización muy por debajo de la saturación (Sección 2.4) y sobrevive a la caída de una zona de disponibilidad: planifica alrededor de un 50% de margen de capacidad (headroom), así que 7 x 1.5 = unas 11 réplicas en el pico, con menos fuera de las horas punta
Escrituras en la base de datosEl 15% de 1200 = 180 solicitudes por segundo, cada una con unas 3 escrituras: unas 540 escrituras por segundo, muy dentro de lo que admite una única base de datos principal PostgreSQL gestionada en una instancia de tamaño medio
Lecturas de la base de datos1020 solicitudes de lectura por segundo; una caché para las cartas (que cambian rara vez) absorbe la mayoría, y dos réplicas de lectura se encargan del historial de pedidos y los informes, aceptando un segundo o así de retardo de replicación
Trabajo en segundo planoLos correos de recibo, las liquidaciones a los repartidores y los informes para restaurantes pasan a un grupo de workers alimentado por una cola, para que un proveedor de correo lento no pueda ralentizar el proceso de pago
ConclusiónUn único código base, desplegado como una sola unidad y ejecutado como unas 11 réplicas web más los workers, cumple el objetivo de dos años. El presupuesto de arquitectura se dedica a los límites de los módulos y a la ausencia de estado, no a dividir.

El límite que llega primero rara vez es la CPU. Lo más frecuente es la coordinación entre equipos a medida que crece el grupo de ingeniería, o un único módulo (como el despacho) con necesidades de escalado o de lanzamiento muy distintas.

Todas las cifras de aquí deberían sustituirse por mediciones de tus propias pruebas de carga; la planificación de capacidad se trata en la Sección 9.7.

Señales de que ha llegado el momento de dividir

Dividir debe ser una respuesta a las pruebas, no a las modas. Las señales de que una única unidad de despliegue se ha convertido en la restricción son sobre todo organizativas y operativas:

Contención entre equipos. Varios equipos modifican el mismo código y se esperan unos a otros; los conflictos de fusión, las reuniones de coordinación y las compilaciones rotas por otros equipos aumentan a medida que crece la organización. Si los módulos ya están bien delimitados y la contención persiste, quizá lo que falte sea la independencia de despliegue.

Colas de despliegue. Los lanzamientos se agrupan en trenes porque cada cambio exige volver a probar todo el sistema; una pequeña corrección espera días detrás de trabajo no relacionado; el cambio fallido de un equipo bloquea el lanzamiento de todos.

Necesidades de escalado o de disponibilidad muy distintas. Un módulo (por ejemplo, el seguimiento de repartidores en tiempo real) necesita en el pico cincuenta veces la capacidad del resto, o debe seguir funcionando cuando todo lo demás está caído. Escalar todo el monolito para las necesidades de un módulo resulta caro.

Distinto alcance de seguridad o de cumplimiento. Los datos de tarjetas o los historiales médicos pueden justificar una unidad separada y estrictamente controlada para mantener el resto del sistema fuera del alcance de las auditorías.

Distintas necesidades tecnológicas. Por ejemplo, un modelo de machine learning que es mejor servir desde Python dentro de un monolito en Java.

Algunas razones no son buenas razones por sí solas: "los monolitos son legado", el deseo de usar una tecnología nueva o un código lento (que es un problema de diseño que dividir no arreglará y que puede empeorar al añadir llamadas de red).

Cómo dividir cuando llegue el momento

Divide de forma incremental, un módulo cada vez, empezando por el módulo que tenga a la vez el límite más claro y la razón más fuerte para salir. Modulariza primero si el código todavía no es modular: extraer un servicio de una maraña arrastra la maraña consigo. Después, extrae siguiendo los contextos delimitados (Sección 5.7): pon una API de red delante de la API existente del módulo, mueve sus datos a su propia base de datos, sustituye los eventos dentro del proceso por un intermediario de mensajes (message broker) y sustituye cualquier transacción compartida por sagas explícitas. Dirige el tráfico al nuevo servicio de forma gradual y mantén el camino antiguo hasta que el nuevo haya demostrado su valor.

Este es el enfoque strangler fig (higuera estranguladora) y sus variantes, que se tratan en la Sección 11.6. El destino a menudo no es "todo microservicios", sino un monolito con unos pocos servicios extraídos allí donde las pruebas lo exigieron; la arquitectura basada en servicios de la Sección 6.2 es un estado final habitual y pragmático.

Los estilos del Capítulo 5 comparados

CaracterísticaEn capasMonolito modularTuberías y filtrosMicrokernelHexagonal / limpia
Particionamiento principalTécnicoPor dominioPasos de procesamientoNúcleo más plug-insDentro frente a fuera
SencillezAltoDe media a altaAltoMediaDe baja a media
Costo totalBaratoBaratoBaratoBaratoDe barato a medio
Modificabilidad ante cambios de negocioDe baja a mediaAltoAlta dentro del flujoAlta en las direcciones previstasAlta para la infraestructura
Capacidad de prueba (testabilidad)MediaDe media a altaAltoDe media a altaAlto
DesplegabilidadBajoDe baja a mediaDe baja a mediaMediaDepende del estilo de despliegue
EscalabilidadBajoDe baja a mediaDe baja a mediaBajoDepende del estilo de despliegue
Tolerancia a fallosBajoBajoDe baja a mediaDe baja a mediaDepende del estilo de despliegue
Encaje típicoApps pequeñas y medianas, un equipoProductos en crecimiento, varios equiposETL, multimedia, logs, compiladoresProductos con muchas variantesLógica que debe sobrevivir a los frameworks

Las valoraciones resumen los juicios hechos en cada sección y suponen implementaciones típicas. El diseño guiado por el dominio no aparece como columna porque es un método para encontrar límites, que cualquiera de estos estilos puede usar. Los sistemas reales combinan estilos: un monolito modular cuyos módulos son hexagonales por dentro, con un proceso de importación de tuberías y filtros y un microkernel para las reglas fiscales, es totalmente normal.

Guía de decisión

Guía de decisión: elegir entre los estilos del Capítulo 5

Úsala para un sistema nuevo o una reestructuración importante que vaya a ejecutarse como una sola unidad de despliegue. Recorre las preguntas de arriba abajo; varios estilos pueden aplicarse a distintos niveles.

  1. ¿El sistema es principalmente un flujo de datos a través de una serie de transformaciones (importar, limpiar, enriquecer, exportar), y no usuarios que interactúan con un estado compartido?
    SíUsa tuberías y filtros para ese flujo (Sección 5.4). Mantén cada filtro sin estado y el formato de datos entre filtros explícito.
    NoPasa a la siguiente pregunta.
  2. ¿El producto tiene un flujo de trabajo central estable, pero muchas variantes de pasos concretos (por país, cliente, proveedor o formato de archivo), o necesitan ampliarlo terceros?
    SíUsa un microkernel (Sección 5.5) para esos puntos de variación, idealmente después de construir dos o tres variantes, para que el contrato se base en casos reales.
    NoPasa a la siguiente pregunta.
  3. ¿Es pequeño (un equipo, unas pocas decenas de pantallas), con reglas sencillas y con pocas probabilidades de crecer mucho?
    SíUsa una arquitectura en capas (Sección 5.2) con capas cerradas que haga cumplir una prueba de arquitectura. No añadas más estructura de la que necesita el problema.
    NoPasa a la siguiente pregunta.
  4. ¿Trabajarán en él varios equipos, o el dominio abarca varias áreas con su propio lenguaje (cartas, pedidos, despacho)?
    SíUsa un monolito modular (Sección 5.3) con módulos trazados según los contextos delimitados (Sección 5.7), cada uno propietario de sus datos y su API.
    NoTanto una estructura en capas como una modular funcionan; si es probable que crezca, prefiere módulos por dominio, porque reestructurar más adelante es costoso.
  5. Dentro de cada módulo o aplicación, ¿la lógica de negocio es considerable, o depende de servicios externos que probablemente cambien?
    SíEstructura el interior con puertos y adaptadores (Sección 5.6): el dominio en el centro y adaptadores para la web, la base de datos y los proveedores.
    NoMantén dentro del módulo la estructura por defecto del framework; añade puertos solo en los límites que probablemente cambien.

Lista de comprobación: un monolito que se mantiene sano y divisible

La mayoría de estos puntos cuestan poco si se hacen pronto y muchísimo si se incorporan a posteriori.

  • Los módulos siguen los dominios de negocioLos paquetes de nivel superior llevan el nombre de los contextos delimitados (pedidos, despacho, pagos), no de capas técnicas.
  • Cada módulo tiene una API pública pequeñaTodo lo demás es interno; una prueba de arquitectura hace fallar la compilación ante una importación prohibida.
  • Cada tabla tiene un único módulo propietarioLos esquemas separados o las convenciones de nombres hacen visible la propiedad; ningún módulo lee las tablas de otro.
  • La aplicación es sin estadoLas sesiones, los archivos subidos y las cachés están en almacenes compartidos, para que cualquier réplica pueda atender cualquier solicitud y se puedan añadir réplicas a voluntad.
  • El trabajo lento se ejecuta en procesos en segundo planoLos correos electrónicos, los informes, las liquidaciones y las importaciones pasan por una cola, para que las réplicas web sigan siendo rápidas y ambas partes puedan escalarse por separado.
  • La compilación y las pruebas siguen siendo rápidasControla los tiempos de compilación y de pruebas; mantén el pipeline principal por debajo de unos 10 a 15 minutos probando los módulos por separado y en paralelo.
  • El despliegue es automatizado y frecuenteLanzamientos pequeños y frecuentes con rollback automatizado; los feature flags desacoplan el despliegue del lanzamiento.
  • Observabilidad por móduloLos registros, las métricas y las trazas se etiquetan con el módulo, para que puedas ver qué módulo es lento, falla o es caro.
  • Se miden las señales de tensiónEl tiempo de entrega, la longitud de la cola de despliegue, los conflictos de fusión por equipo y el uso de recursos por módulo se revisan con regularidad, para que la decisión de dividir se base en pruebas.

Comprueba lo que has entendido

¿Por qué un límite equivocado entre servicios es más caro que un límite equivocado entre módulos?

Mover el límite de un módulo es una refactorización dentro de un único código base y una única transacción de base de datos; mover el límite de un servicio cambia API de red, almacenes de datos, despliegues y a menudo la propiedad de los equipos, y debe hacerse sin tiempo de inactividad.

¿Qué debe cumplir un monolito antes de poder escalarlo añadiendo réplicas?

Debe ser sin estado: las sesiones, los archivos y las cachés deben estar en almacenes compartidos, para que cualquier réplica pueda atender cualquier solicitud.

Nombra dos señales de que un monolito se ha convertido en la restricción, y una razón para dividirlo que no basta por sí sola.

Señales: contención persistente entre equipos y colas de despliegue, o un módulo con necesidades de escalado o de cumplimiento muy distintas. No basta por sí sola: la moda, querer una tecnología nueva o un código lento.

¿En qué coinciden las posturas de MonolithFirst y de "Don't start with a monolith"?

Ambas dicen que el problema difícil es encontrar y mantener buenos límites; un monolito con límites entre módulos que se hacen cumplir responde a la inquietud de Tilkov y conserva el menor costo que defiende Fowler.

Fin del capítulo 5Hacer la prueba del capítuloOpcional: 20 preguntas de opción múltiple y 2 respuestas escritas, en la app.Ir a la prueba →

Fuentes y lecturas recomendadas

¿Tienes una pregunta sobre esta sección? ArchitectBot, el asistente de estudio con IA del curso, responde primero a partir del curso.

Pregunta: “Somos cinco desarrolladores creando un nuevo producto B2B de planificación de citas y los inversores no dejan de preguntar por los microservicios. ¿Cómo explico por qué empezamos con un monolito modular y qué nos haría cambiar?”