Saltar al contenido
Inicio / Blog / No era el monolito: era la ausencia de límites
· 6 min lectura · Marc J. Cabrer

No era el monolito: era la ausencia de límites

Durante años creí que el problema era el monolito. No lo era: era la falta de límites claros. Cómo estabilizamos un sistema legado sin reescribirlo todo.

arquitecturasistemas-legadosmonolito-modularrefactor

Durante mucho tiempo pensé que nuestro problema era “tener un monolito”.

Con los años entendí que no era eso. El problema real era otro: la ausencia de límites claros.

Entré en 2018 a un backend con historia: varios equipos encima, integraciones con terceros y flujos de negocio que casi nadie había documentado del todo. En 2016 se había intentado separarlo en plugins para darle algo de orden —el WAR final empaquetaba los JARs de cada uno.

Sobre el papel sonaba modular. En la práctica, no tanto.

Cómo se veía el caos en el día a día

No recuerdo un gran incidente concreto que lo resumiera todo. Recuerdo algo más incómodo: una acumulación de señales pequeñas que ya eran normales para el equipo.

  • Había 6 formas distintas de crear usuarios.
  • Las responsabilidades de cada plugin no estaban claras.
  • Las dependencias entre plugins eran fuertes y opacas.
  • Aparecían dependencias cíclicas al intentar evolucionar relaciones.
  • La documentación era mínima.
  • No existían tests que vigilaran la arquitectura.

Nada de esto explotaba siempre. Pero todo eso, junto, hacía que cada cambio sencillo tuviera riesgo alto.

Mi rol al principio: coser parches

Al entrar, mi trabajo era claro: resolver bugs, uno detrás de otro.

Y durante una etapa fue eso: parchear, desplegar, volver a parchear. Honestamente, los primeros meses pensé que el problema era que yo no conocía suficiente el sistema. Que si aprendía mejor el código, encontraría la forma “correcta” de arreglarlo todo sin tocar tanto.

No fue hasta que empecé a refactorizar zonas concretas de Java 6 a Java 8 que empecé a ver el patrón real. No era una migración épica, era una mejora incremental: más legibilidad, menos ruido y mejor rendimiento en partes críticas. Pero ese trabajo me obligó a seguir dependencias entre módulos y ahí fue donde vi que el problema no era mi falta de experiencia con el código.

El problema era que el código mismo no tenía una estructura clara. Y una vez lo ves, no puedes dejar de verlo.

El error de fondo

Mirando atrás, el error no fue usar un monolito.

Fue crecer sin definir fronteras de responsabilidad ni reglas de dependencia.

Cuando un sistema no tiene límites explícitos, aparecen dos efectos típicos:

  1. Todo depende de todo. Lo que hoy parece práctico, mañana bloquea cambios por acoplamiento.
  2. Cada equipo inventa su camino. Si no hay una forma preferida de hacer algo, terminas con 10. Y mantener 10 caminos cuesta mucho más que construir uno bueno.

Nos pasó justo eso.

El punto de inflexión: proponer un refactor serio

Hubo un momento en que la acumulación dejó de ser solo deuda técnica y se convirtió en conversación de negocio: los tiempos de entrega se alargaban, los bugs de alta prioridad llegaban antes de que cerráramos los anteriores. Ahí propuse un refactor con presupuesto y alcance definido.

No voy a mentir: no todos estaban convencidos. Hubo quien pensaba que con más disciplina en code review podríamos “arreglarlo desde dentro” sin parar desarrollo. Y tenían parte de razón. Pero el riesgo de seguir creciendo sobre esa base era cada vez más claro.

La propuesta era sencilla de explicar y difícil de ejecutar. No por complejidad técnica pura, sino porque exigía entender muy bien el negocio y los flujos críticos para no romper lo que sí funcionaba.

La opción más fácil de vender habría sido una reescritura total: nuevo stack, nueva arquitectura, empezar desde cero. Pero era también la de mayor riesgo real: meses sin valor entregado, pérdida probable de conocimiento de negocio no documentado y sin garantía de no repetir los mismos errores de diseño. Optamos por otra vía.

En vez de intentar rehacer todo, empezamos por estabilizar:

  • Corregir problemas de concurrencia en base de datos.
  • Eliminar race conditions en procesos sensibles.
  • Agrupar flujos duplicados que generaban inconsistencias.
  • Reducir caminos alternativos para la misma operación.

Fue un enfoque menos vistoso, pero mucho más realista dado el contexto.

Qué cambió después

No hubo magia ni gran transformación visible de un día para otro. Lo que cambió fue más sutil: menos ruido operativo y más capacidad de decidir.

Pasamos de convivir con bugs diarios a tener incidencias puntuales y más trazables. Con el sistema más estable, también pudimos dedicar espacio a mejorar la experiencia del cliente: incorporamos herramientas en la interfaz para reportar problemas con más contexto, lo que elevó la calidad del feedback y nos dio más capacidad de respuesta.

Ese cambio tuvo un efecto cultural también: cuando el sistema deja de arder cada día, el equipo puede volver a pensar en diseño, prevención y calidad.

Trade-offs reales (y por qué igual valió la pena)

Este camino también tuvo costes:

  • Requirió invertir tiempo en entender negocio y código antes de hacer cosas visibles.
  • Hubo decisiones incómodas, como eliminar duplicidades que llevaban años normalizadas y que alguien, en algún momento, había construido con buena intención.
  • Algunas partes del sistema antiguo y nuevo convivieron más tiempo del que nos habría gustado.

Aun así, el beneficio fue claro: menos fragilidad, menos ambigüedad y más capacidad de evolución.

Lo más valioso que aprendí

Si tengo que resumir esta experiencia en una idea, sería esta:

Un monolito puede escalar muy bien cuando es modular de forma estricta y con responsabilidades mínimas por módulo.

Esto no significa que los microservicios estén mal. Significa que el problema de fondo —límites difusos, responsabilidades mezcladas— no desaparece solo por cambiar la forma de despliegue. Puedes tener un monolito limpio o microservicios acoplados. La diferencia está en qué tan claros son los contratos entre módulos: qué expone cada uno, qué no, y la disciplina para respetarlo.

Ahora bien, esto solo tiene sentido en sistemas de cierta escala y con equipos que pueden mantener esa disciplina. En proyectos pequeños o equipos sin cultura de arquitectura, añadir toda esta estructura puede ser más peso que beneficio.

De vuelta al principio

Durante años pensé que el problema era el monolito. Y durante años, en conversaciones de equipo, alguien repetía la misma frase cada vez que algo se rompía.

Hoy mi lectura es otra: muchas veces el problema no es la forma de despliegue, sino la falta de límites de diseño.

Cuando cada módulo sabe qué debe hacer y qué no, las dependencias dejan de ser accidentes y se convierten en decisiones conscientes. Eso, por sí solo, cambia mucho.

Si tuviese que dejarte una sola pregunta para aplicar mañana sería esta: ¿cuántas formas tiene tu sistema de hacer lo mismo? Si la respuesta supera tres, probablemente ya tienes el problema. Y si alguien dice “depende de qué equipo lo haya hecho”, definitivamente ya lo tienes.

¿Te ha resultado útil?

Contacto

Reserva la conversación adecuada, no una reunión cualquiera.

Si necesitas contraste técnico, entra por disponibilidad. Si todavía estás ordenando el problema, escríbeme primero y decidimos qué formato encaja mejor.

Prefieres escribir antes?