Read in English · Lire en français · Auf Deutsch lesen
Sección 11.6 de 11.8 · Avanzado · 25 min de lectura
Modernizar sistemas heredados: strangler fig y migración incremental
Videolección
5 min · narrado en inglés, con subtítulosSolo escuchar (audio)
Leer la transcripción
Todo sistema de éxito acaba convirtiéndose en un sistema heredado. En esta lección aprenderás por qué las grandes reescrituras fracasan tan a menudo y cómo modernizar pieza a pieza en su lugar.
Imagina un pueblo que necesita un puente nuevo. Derribar primero el antiguo dejaría al pueblo aislado durante años. Así que los ingenieros construyen el puente nuevo junto al antiguo. Lo abren carril a carril y desvían el tráfico poco a poco. Si un carril nuevo tiene un problema, el tráfico simplemente vuelve al puente antiguo durante un tiempo. Y solo derriban el puente antiguo cuando ya nada lo usa. Modernizar software antiguo funciona mejor de la misma manera.
Un sistema heredado sigue haciendo algo valioso, pero se ha vuelto difícil, arriesgado o caro de cambiar. La mayoría de los sistemas heredados son sistemas de éxito. La respuesta obvia es empezar de nuevo, y eso suele ser un error. En una reescritura big-bang, el valor solo llega al final, así que el negocio espera meses o años y pierde la paciencia. El sistema antiguo sigue cambiando mientras se construye el nuevo, así que el objetivo se mueve. Se pierde comportamiento oculto. El código antiguo parece desordenado en parte porque contiene años de correcciones para situaciones que nadie recuerda. Joel Spolsky lo señaló en 2000, al escribir sobre la reescritura de Netscape. Y mover los datos y pasar al sistema nuevo quedan para el final, cuando es más difícil. En 2018, la migración de plataforma del banco británico TSB salió muy mal, y más tarde los reguladores le impusieron una multa de cuarenta y ocho punto seis cinco millones de libras.
El strangler fig, bautizado por Martin Fowler, sustituye un sistema pieza a pieza mientras sigue funcionando. Primero, intercepta: coloca una fachada de enrutamiento delante del sistema heredado. Al principio, lo envía todo al sistema antiguo. Después reconstruye una porción de comportamiento, aquí el seguimiento de pedidos, como un componente nuevo, y cambia una regla de enrutamiento para enviarla allí. Si se comporta mal, vuelve a cambiar la regla. Repite, porción a porción, con una sincronización de datos temporal, hasta que en el sistema antiguo solo quede la facturación. Por último, se apaga el sistema heredado. La fachada, los adaptadores y los trabajos de sincronización son arquitectura de transición, construida para tirarse. Así que mide el progreso por lo que se ha apagado.
Los datos son la parte más difícil. En cada etapa, exactamente un sistema debe ser el sistema de registro. Al principio, el sistema heredado es dueño de los pedidos, y la captura de datos de cambios copia sus filas al almacén nuevo, a través de una capa anticorrupción que las traduce. Más adelante, el sentido se invierte. El nuevo servicio de pedidos es dueño de los pedidos, y sus eventos se traducen de vuelta a filas heredadas para los módulos que aún no se han trasladado, como la facturación. Los datos fluyen en un solo sentido cada vez.
Así es como la plataforma sacó su módulo de pedidos del monolito. Primero, fija los resultados: lanzamientos de pedidos diarios e independientes, el triple del pico actual de los viernes y ningún pedido perdido ni duplicado. Las solicitudes de producción grabadas se convirtieron en pruebas que capturan el comportamiento actual, peculiaridades incluidas. Segundo, coloca un API gateway delante del monolito que lo enrute todo hacia él. No cambia ningún comportamiento, y el equipo practica el cambio de rutas. Tercero, construye el servicio nuevo en la sombra, mientras el sistema heredado sigue siendo el sistema de registro. En una ejecución en paralelo, la tasa de discrepancias empieza en torno al dos por ciento y se reduce por debajo del cero punto cero uno por ciento antes de seguir adelante. Cuarto, mueve las lecturas de seguimiento de pedidos: el cinco por ciento del tráfico, después el veinticinco y después todo. El rollback es una regla de enrutamiento. Quinto, mueve las escrituras, ciudad por ciudad: una ciudad piloto y después todas las ciudades a lo largo de seis semanas. Un adaptador convierte los eventos del servicio nuevo en filas heredadas, para que la facturación y los informes sigan funcionando. Por último, migra tres años de histórico. Cuando las tablas de pedidos heredadas lleven treinta días sin lecturas, elimina el adaptador, el pipeline y el código antiguo. Solo entonces se completa la migración.
El strangler fig funciona en el borde, donde las solicitudes pueden enrutarse. Branch by abstraction funciona en lo más profundo de una base de código. Coloca una interfaz delante del componente antiguo, mueve los llamadores a ella, construye la implementación nueva detrás, haz el cambio de forma gradual y después borra el código antiguo. Una ejecución en paralelo demuestra que el código nuevo se comporta como el antiguo. Ambos reciben las mismas entradas, pero al usuario se le sigue devolviendo el resultado antiguo, y se registran las diferencias. La ruta nueva no debe tener efectos secundarios, como cobrar dos veces una tarjeta.
La sección completa trata las siete R, el dark launching y cómo migrar datos de forma segura. A continuación, en la Sección once punto siete, veremos el liderazgo y la influencia. Nos vemos allí.
Lo que necesitas saber
- Un sistema heredado sigue aportando valor, pero es difícil, arriesgado o caro de cambiar; moderniza por motivos de negocio, como un cambio bloqueado, la pérdida de soporte, la escasez de competencias o el costo, no por moda.
- Las reescrituras big-bang fracasan porque el valor llega tarde, el objetivo se mueve, se pierde comportamiento oculto y la migración de datos y el cambio definitivo (cutover) quedan para el final; el ensayo de Spolsky de 2000 y la migración de TSB de 2018 son advertencias clásicas.
- Las siete R (retirar, retener, realojar, reubicar, recomprar, cambiar de plataforma, y refactorizar o rediseñar la arquitectura) dan a cada aplicación de una cartera una estrategia deliberada; reconstruir es solo una opción.
- El strangler fig (Fowler, 2004) hace pasar el tráfico por una fachada y traslada el comportamiento porción a porción a componentes nuevos hasta que el sistema heredado puede apagarse; branch by abstraction hace lo mismo dentro de una única base de código.
- Las ejecuciones en paralelo comparan en producción los resultados antiguos y nuevos mientras el resultado antiguo sigue siendo el que cuenta; el dark launching ejercita rutas nuevas con carga real sin que los usuarios las vean.
- Los datos necesitan un único sistema de registro en cada etapa; la captura de datos de cambios, la intercepción de eventos y las capas anticorrupción mantienen sincronizados los sistemas, y el histórico se migra por cohortes ensayadas y conciliadas.
- La arquitectura de transición es un costo deliberado y temporal; una migración solo termina cuando se han eliminado el sistema antiguo y el código de transición.
Qué hace que un sistema sea heredado
Un sistema heredado (legacy) no es simplemente un sistema antiguo. Es un sistema que sigue haciendo algo valioso, a menudo algo sin lo que la organización no podría funcionar, pero que se ha vuelto difícil, arriesgado o caro de cambiar. Michael Feathers, en Working Effectively with Legacy Code (2004), dio una definición deliberadamente provocadora: el código heredado es código sin pruebas, porque sin pruebas cada cambio es una apuesta. Otras causas habituales son la escasez de competencias (un lenguaje o una plataforma que ya pocos conocen), la tecnología sin soporte (un sistema operativo o una base de datos que han superado el fin de soporte de su proveedor), el conocimiento perdido (las personas que entendían el diseño se han ido) y la deuda técnica acumulada en la propia estructura, el tipo costoso descrito en la Sección 1.7.
Vale la pena decirlo con claridad: la mayoría de los sistemas heredados son sistemas de éxito. Sobrevivieron porque funcionaban y generaban dinero. Ese éxito es también la razón por la que son difíciles de sustituir: años de uso real han incorporado miles de pequeñas decisiones, correcciones y reglas de negocio que no están escritas en ninguna parte salvo en el código y en los hábitos de las personas que lo usan.
Por tanto, la modernización necesita un motivo que pueda expresarse en términos de negocio. Entre los buenos motivos están: el costo o el riesgo del cambio está bloqueando objetivos de negocio importantes; la plataforma está perdiendo el soporte del proveedor o los parches de seguridad; las competencias para mantenerla están dejando de estar disponibles; los costos de operación son desproporcionados respecto al valor; o el sistema no puede satisfacer nuevas exigencias de escala, disponibilidad o regulación. Entre los motivos débiles están la moda, el aburrimiento y la creencia de que la tecnología nueva es automáticamente mejor. La Sección 11.8 muestra cómo convertir un buen motivo en un caso de negocio.
Por qué fracasan las reescrituras
La respuesta obvia a un sistema antiguo problemático es empezar de nuevo. En abril de 2000, Joel Spolsky publicó un ensayo, "Things You Should Never Do, Part I", en el que sostenía que la decisión de reescribir desde cero es uno de los peores errores estratégicos que puede cometer una empresa de software. Su ejemplo era Netscape, cuyo navegador pasó casi tres años entre dos versiones principales mientras se reescribía el código, tiempo durante el cual los competidores se quedaron con el mercado. Su argumento central era sobre el conocimiento: el código antiguo parece desordenado en parte porque contiene años de correcciones de bugs para situaciones que nadie recuerda, y tirarlo supone tirar también esas correcciones.
Hoy se entienden bien las razones por las que fracasa una reescritura big-bang. El valor solo llega al final, así que el negocio espera meses o años y pierde la paciencia. El sistema antiguo sigue cambiando mientras se construye el nuevo, así que el objetivo se mueve y la organización o bien congela el sistema antiguo (y el negocio), o bien paga por hacer cada cambio dos veces. Se pasa por alto comportamiento oculto, porque nadie puede enumerar todas las reglas que impone el sistema antiguo. Las estimaciones son optimistas, porque las funcionalidades visibles son una fracción del trabajo real. La migración de datos y el cambio definitivo se dejan para el final, cuando son más difíciles y arriesgados. Y el equipo se divide en un grupo prestigioso del sistema nuevo y un grupo desmoralizado del sistema antiguo. El efecto del segundo sistema de Fred Brooks, de The Mythical Man-Month (1975), añade otro riesgo: los diseñadores que sustituyen un sistema que conocen tienden a cargar el nuevo con todas las ideas que el antiguo no podía acomodar.
Las grandes migraciones que cambian de sistema en un solo paso también pueden fracasar de forma muy pública. En abril de 2018, el banco británico TSB trasladó los datos y servicios de sus clientes a una nueva plataforma informática; la plataforma tuvo graves problemas de inmediato, todas sus sucursales y una proporción significativa de sus 5.2 millones de clientes se vieron afectadas, y el banco no volvió a funcionar con normalidad hasta diciembre de 2018. En diciembre de 2022, la Financial Conduct Authority y la Prudential Regulation Authority impusieron a TSB multas por un total de £48.65 millones, al concluir que no había planificado, organizado ni controlado adecuadamente la migración ni gestionado los riesgos derivados de su proveedor externo.
No todos los profesionales están de acuerdo en que las reescrituras sean siempre un error. Una reescritura puede ser la opción correcta cuando el sistema es pequeño, su comportamiento está bien especificado y cubierto por pruebas, la plataforma está realmente en un callejón sin salida, o el propio negocio ha cambiado tanto que el comportamiento antiguo ya no se quiere. Incluso entonces, las reescrituras más seguras se entregan de forma incremental, con los sistemas antiguo y nuevo funcionando uno junto al otro, que es el tema del resto de esta sección.
Estrategias de migración: las R
Cuando una organización revisa toda una cartera de aplicaciones, por ejemplo antes de abandonar un centro de datos, necesita un vocabulario para decidir qué hacer con cada una. Gartner describió cinco opciones de este tipo a principios de la década de 2010. En 2016, Stephen Orban, de AWS, publicó seis estrategias, y AWS añadió más tarde una séptima, lo que dio lugar a las siete R (Seven Rs) que se usan hoy en su guía de migración. Otros proveedores de nube y consultoras usan listas parecidas con nombres ligeramente distintos. La lista es más útil como recordatorio de que reconstruir es solo una opción entre varias, y normalmente la más cara.
Las siete R (según AWS Prescriptive Guidance)
| Estrategia | Qué significa | Encaja cuando | Cambio de arquitectura |
|---|---|---|---|
| Retirar (retire) | Apagar la aplicación y archivar sus datos | Nadie la usa, o su función está duplicada en otro lugar | Ninguno; eliminar las dependencias de ella |
| Retener (retain) | Dejarla donde está por ahora y revisarla más adelante | No hay un motivo urgente para moverla, u otro trabajo debe ir primero | Ninguno por ahora |
| Realojar (rehost, lift and shift) | Moverla sin cambios a una infraestructura nueva, como máquinas virtuales en la nube | El principal impulsor es abandonar rápidamente un centro de datos | Ninguno; los problemas se mudan con ella |
| Reubicar (relocate) | Mover plataformas enteras, como un parque virtualizado, sin cambiar las aplicaciones | Existe una plataforma compatible en el destino | Ninguno |
| Recomprar (repurchase) | Sustituirla por un producto, a menudo software como servicio | La capacidad es genérica y existe un buen producto | Integración y migración de datos; pérdida de personalización |
| Cambiar de plataforma (replatform) | Moverla con unas pocas optimizaciones específicas, como una base de datos gestionada | Hay mejoras baratas disponibles sin rediseñar | Pequeño y local |
| Refactorizar o rediseñar la arquitectura (refactor o re-architect) | Rediseñarla, a menudo de forma incremental, para satisfacer nuevas necesidades de calidad o de negocio | La capacidad es central, cambia a menudo y su estructura bloquea el cambio | Grande; usar los patrones incrementales que se describen a continuación |
Guía de decisión
Guía de decisión: elegir una estrategia para una aplicación
Hazte estas preguntas para cada aplicación de la cartera, en este orden. Las respuestas salen de los datos de uso, del responsable de negocio y de la arquitectura, no de las preferencias tecnológicas.
- ¿Alguien sigue necesitando lo que hace esta aplicación?SíPasa a la siguiente pregunta.NoRetírala, después de archivar los datos que la ley te obligue a conservar.
- ¿Hay un producto que cubra la necesidad, para una capacidad que no diferencia al negocio?SíPlantéate recomprar, y presupuesta la integración y la migración de datos.NoPasa a la siguiente pregunta.
- ¿Hay un motivo urgente para actuar ahora, como el fin del soporte, la salida de un centro de datos, el costo o un cambio que está bloqueado?SíPasa a la siguiente pregunta.NoRetenla y fija una fecha para revisar la decisión.
- ¿El problema principal es dónde se ejecuta y no cómo está construida?SíRealójala o reubícala, o cámbiala de plataforma cuando un servicio gestionado ofrezca mejoras baratas.NoPasa a la siguiente pregunta.
- ¿Es una capacidad central cuya estructura está bloqueando cambios frecuentes y valiosos?SíRefactorízala o rediseña su arquitectura de forma incremental, con un strangler fig y branch by abstraction.NoCámbiala de plataforma y contenla: añade pruebas, corrige los peores hotspots y evita un gran rediseño.
El strangler fig
Martin Fowler bautizó el patrón incremental más usado en honor a las higueras estranguladoras que vio en las selvas tropicales de Queensland en 2001: enredaderas que germinan en las ramas de un árbol hospedador, crecen hacia el suelo y rodean poco a poco al hospedador hasta que este muere y la higuera se sostiene por sí sola. Lo describió por primera vez como strangler application en 2004, más tarde lo rebautizó como strangler fig application y revisó a fondo el artículo en 2024. La versión de software, normalmente llamada simplemente strangler fig (higuera estranguladora), mantiene en funcionamiento el sistema antiguo mientras crecen a su alrededor componentes nuevos que asumen su comportamiento pieza a pieza, hasta que el sistema antiguo ya no hace nada y puede apagarse.
El mecanismo tiene tres partes. Primero, se coloca una capa de interceptación delante del sistema heredado: un proxy inverso, un API gateway o una fachada de enrutamiento por la que pasan todas las solicitudes. Al principio lo envía todo al sistema antiguo y no cambia nada. Segundo, se elige una porción de comportamiento a lo largo de una juntura (un lugar donde el comportamiento puede redirigirse sin editar mucho código antiguo, en palabras de Feathers), se reconstruye como un componente nuevo y se activa cambiando una regla de enrutamiento, normalmente primero para una pequeña parte del tráfico. Tercero, el proceso se repite hasta que el sistema heredado no gestiona nada, momento en el que se retira. En todo momento, la capa de enrutamiento hace que cada paso sea reversible: si el componente nuevo se comporta mal, se vuelve a cambiar la regla.
El código que permite que lo antiguo y lo nuevo coexistan (la fachada de enrutamiento, los adaptadores, los trabajos de sincronización de datos) es arquitectura de transición: software construido para tirarse. Los equipos a menudo se resisten a escribirlo porque parece un desperdicio. El argumento de Fowler, y la experiencia que lo respalda, es que este costo compra un menor riesgo y un valor mucho más temprano, lo que casi siempre es un buen intercambio. El peligro real es el contrario: una migración que se estanca a medio camino y deja ambos sistemas y todo el código de transición en producción indefinidamente. Por eso cada porción debe eliminar algo del sistema antiguo, y el progreso debe medirse por lo que se ha apagado, no solo por lo que se ha construido.
Ian Cartwright, Rob Horn y James Lewis, de Thoughtworks, han documentado una familia de técnicas relacionadas como Patterns of Legacy Displacement en martinfowler.com (desde 2021). Plantean el trabajo como cuatro actividades que no siguen una secuencia fija: entender los resultados que quieres, dividir el problema en partes, entregar esas partes de forma incremental y cambiar la organización para que el sistema nuevo no se deteriore como lo hizo el antiguo. También cuestionan el instinto de reproducir todas las funcionalidades: puede que gran parte del comportamiento de un sistema heredado ya no se quiera, y averiguarlo es más barato que reconstruirlo.
Una migración strangler fig en cuatro etapas
Branch by abstraction (ramificación por abstracción)
El strangler fig funciona en el borde de un sistema, donde las solicitudes pueden enrutarse. Algunas sustituciones deben hacerse en lo más profundo de una base de código: cambiar un framework de persistencia, un motor de precios o una capa de mensajería de fabricación propia que usan cientos de puntos de llamada. Branch by abstraction, un nombre que introdujo Paul Hammant mientras defendía el desarrollo basado en trunk y que Martin Fowler describió en 2014, lo hace sin una rama de control de versiones de larga duración. El sistema sigue siendo lanzable en cada paso, así que el cambio puede repartirse a lo largo de semanas o meses mientras continúa otro trabajo en la misma línea principal.
Branch by abstraction, paso a paso
- Introduce una abstracciónCrea una interfaz delante del componente que se va a sustituir, con una implementación que simplemente delega en el código existente. El comportamiento no cambia en nada.
- Mueve los llamadores a la abstracciónCambia los puntos de llamada, poco a poco, para que usen la interfaz en lugar del componente antiguo directamente. Cada cambio es pequeño y se lanza con normalidad.
- Construye la implementación nuevaEscribe la sustitución detrás de la misma interfaz y pruébala con las mismas pruebas e, idealmente, contra el comportamiento de producción en una ejecución en paralelo.
- Haz el cambio de forma gradualUsa una feature flag o la configuración para enviar a algunos llamadores o a algunos clientes a la implementación nueva, aumentando la proporción a medida que crece la confianza.
- Elimina la implementación antiguaCuando nada use ya el código antiguo, bórralo, y elimina también la abstracción si ya no justifica su lugar.
Demostrar la equivalencia: ejecución en paralelo y dark launching
La pregunta más difícil de cualquier migración es si la implementación nueva se comporta realmente como la antigua. Una ejecución en paralelo la responde con evidencia de producción: ambas implementaciones reciben las mismas entradas, la antigua sigue siendo la que cuenta y su respuesta es la que se devuelve al usuario, y los dos resultados se comparan y se registra cualquier diferencia. GitHub publicó su biblioteca Scientist en 2016 exactamente con este fin: ejecuta un control y un candidato uno junto al otro e informa de las discrepancias; existen herramientas parecidas para muchos lenguajes, y la técnica es sencilla de escribir a mano, como muestra el esbozo siguiente.
El dark launching (lanzamiento oculto), que Fowler describe como llamar a un comportamiento de backend nuevo en producción sin que los usuarios vean sus efectos, está estrechamente relacionado. Se usa sobre todo para probar el rendimiento y la estabilidad de la ruta nueva con carga real antes de que ningún usuario dependa de ella, mientras que una ejecución en paralelo se centra en la corrección. Ambos se diferencian de un canary release, en el que una pequeña parte de los usuarios recibe de verdad el comportamiento nuevo.
Ambas técnicas tienen aristas peligrosas. El candidato no debe tener efectos secundarios visibles desde fuera: no debe enviar un segundo correo electrónico, cobrar dos veces una tarjeta ni escribir en la base de datos compartida, así que las ejecuciones en paralelo son más fáciles para lecturas y cálculos, y las escrituras necesitan un sandbox o un almacén aparte. Las comparaciones deben ignorar las diferencias legítimas, como las marcas de tiempo, el orden y el formato de los números de coma flotante, o el informe de discrepancias se ahoga en ruido. Y ejecutar ambas rutas consume capacidad, así que a menudo se limita la proporción del tráfico que se muestrea.
def quote_delivery_fee(order):
old = legacy_pricing.quote(order) # still authoritative
try:
new = new_pricing.quote(order) # must have no side effects
if new.amount_pence != old.amount_pence:
metrics.increment("pricing.mismatch")
log.info("pricing mismatch", order_id=order.id,
old=old.amount_pence, new=new.amount_pence)
else:
metrics.increment("pricing.match")
except Exception:
metrics.increment("pricing.candidate_error") # never hurts the user
return oldLos datos: la parte más difícil
Enrutar las solicitudes es relativamente fácil; mover los datos y mantenerlos consistentes mientras dos sistemas comparten la responsabilidad sobre ellos es donde más migraciones tropiezan. La primera regla es la del Capítulo 7 sobre la propiedad de los datos: para cada tipo de datos, en cada etapa de la migración, el equipo debe poder decir qué sistema es el sistema de registro, qué copias existen y cuán desactualizada puede estar cada una. El diagrama siguiente muestra el cambio típico: al principio el sistema heredado es dueño de los datos y el componente nuevo lee una copia; más adelante el componente nuevo pasa a ser el dueño y el sistema heredado recibe una copia para los módulos que todavía la necesitan.
La captura de datos de cambios (CDC) es la forma habitual de copiar datos de una base de datos heredada sin cambiar el código heredado: una herramienta como Debezium lee el registro de transacciones de la base de datos y publica cada cambio como un evento, el mismo mecanismo que la Sección 6.7 usó para retransmitir una bandeja de salida (outbox). La intercepción de eventos, uno de los patrones de desplazamiento de sistemas heredados, actúa en el otro extremo: captura las solicitudes o mensajes que cambian el estado en su camino hacia el sistema heredado y reenvía copias (o, más adelante, los originales) al componente nuevo. En cualquier caso, nunca permitas que ambos sistemas acepten escrituras sobre los mismos datos de forma independiente con una sincronización bidireccional, salvo que no tengas alternativa; en ese caso los conflictos están casi garantizados.
Los datos heredados rara vez coinciden con el modelo nuevo. Los códigos de estado son enteros con significados no documentados, una tabla sirve para tres propósitos y las fechas se guardan en hora local. Una capa anticorrupción, el patrón del diseño guiado por el dominio para proteger un modelo del de un vecino, traduce entre ambos para que las peculiaridades del sistema heredado no se filtren al código nuevo. Forma parte de la arquitectura de transición y debe desaparecer con el sistema heredado.
La migración final de los datos, mover el histórico y hacer el cambio definitivo, merece su propio plan. Perfila primero los datos heredados para encontrar duplicados, registros huérfanos y valores no válidos. Escribe la correspondencia de forma explícita y pruébala con una copia completa del tamaño de producción. Concilia después de cada ejecución con recuentos de filas, sumas de las columnas de importes y checksums, no con comprobaciones puntuales. Ensaya el cambio definitivo, cronométralo y pon por escrito el rollback. Siempre que sea posible, migra por cohortes (una región, un segmento de clientes, una línea de producto) en lugar de todo a la vez, para que un problema afecte a una fracción de los clientes y te enseñe algo antes de la siguiente cohorte.
El sistema de registro cambia durante la migración
Lecciones de Kill It with Fire
Kill It with Fire: Manage Aging Computer Systems (and Future Proof Modern Ones) (No Starch Press, 2021), de Marianne Bellotti, se basa en su experiencia modernizando sistemas gubernamentales y comerciales, incluidos parques de mainframes. Varios de sus temas merecen trasladarse a cualquier modernización.
La modernización debe justificarse por el valor que aporta y el riesgo que elimina, no por la antigüedad de la tecnología; una tecnología antigua que se entiende bien y funciona puede ser la parte menos arriesgada del parque de sistemas. Las elecciones tecnológicas van por ciclos, así que un equipo que sustituye un sistema solo porque su diseño ha pasado de moda probablemente esté construyendo el sistema heredado de la próxima generación. La mejora incremental del sistema existente suele ser más segura que la sustitución, y una reescritura completa necesita una justificación excepcionalmente sólida. Por último, la modernización es un problema organizativo tanto como técnico: necesita éxitos tempranos y visibles para mantener el impulso y la moral, criterios claros para saber cuándo ha terminado y atención a los incentivos que hicieron que el sistema antiguo se deteriorara, o el nuevo seguirá el mismo camino.
Ejemplo práctico
Ejemplo práctico: estrangular el módulo de pedidos para sacarlo del monolito en seis pasos
Este ejemplo repasa cómo obtuvo la plataforma de reparto de comida el servicio de pedidos separado que se evaluó en la Sección 11.1. En una etapa anterior de su vida, el monolito original de la plataforma contenía un módulo de pedidos que gestionaba la realización, la modificación, la cancelación y el seguimiento de los pedidos. Los cambios en los pedidos se habían convertido en el principal cuello de botella: exigían desplegar todo el monolito, y los picos de los viernes por la tarde ralentizaban todas las demás funcionalidades. Otros catorce módulos, entre ellos los de facturación, informes y las herramientas de atención al cliente, leían directamente las tablas de pedidos. El equipo planificó una migración incremental a un servicio de pedidos separado.
| 1. Fijar los resultados y encontrar la juntura | Resultados: cambios en los pedidos desplegables a diario y de forma independiente; el triple del pico actual de los viernes sin afectar a otras funcionalidades; ningún pedido perdido ni duplicado. El análisis de los logs de consultas confirma que solo el módulo de pedidos escribe en las tablas de pedidos y que todo el tráfico de pedidos entra por los endpoints /api/orders. El equipo graba varias semanas de solicitudes de producción y las convierte en pruebas de caracterización que capturan el comportamiento actual, peculiaridades incluidas. |
|---|---|
| 2. Insertar la fachada de enrutamiento | Se coloca un API gateway delante del monolito y al principio lo enruta todo hacia él. Lanzado por sí solo, no cambia ningún comportamiento; el equipo comprueba la latencia añadida (unos pocos milisegundos en el percentil 95) y practica el cambio de rutas. Rollback: quitar el gateway del camino. |
| 3. Construir el servicio nuevo en la sombra | El nuevo servicio de pedidos tiene su propio almacén. El sistema heredado sigue siendo el sistema de registro: la captura de datos de cambios copia las filas de pedidos a través de una capa anticorrupción que traduce los códigos de estado enteros y las fechas en hora local al modelo nuevo. Los endpoints de lectura funcionan como una ejecución en paralelo frente a las respuestas del sistema heredado; la tasa de discrepancias empieza en torno al 2% (redondeo de comisiones, husos horarios) y se reduce por debajo del 0.01% antes de seguir adelante. |
| 4. Mover las lecturas | Las lecturas de seguimiento de pedidos se enrutan al servicio nuevo para el 5%, después el 25% y después todo el tráfico, vigilando las tasas de error y la latencia en cada etapa. Rollback: una regla de enrutamiento. |
| 5. Mover las escrituras, ciudad por ciudad | El servicio nuevo pasa a ser el sistema de registro de los pedidos hechos en una ciudad piloto y después en todas las ciudades a lo largo de seis semanas. Publica los eventos OrderPlaced y OrderCancelled mediante una bandeja de salida transaccional (transactional outbox); un adaptador de transición los traduce a filas con el formato heredado para que la facturación y los informes sigan funcionando sin cambios. Una conciliación diaria compara los recuentos y los importes totales entre los dos almacenes. Después, esos módulos pasan a los eventos o a la API de pedidos durante los trimestres siguientes. |
| 6. Migrar el histórico y retirar | Tres años de pedidos históricos se copian en lotes limitados y se concilian mediante recuentos y checksums. Cuando los logs de auditoría de la base de datos no muestran ninguna lectura de las tablas de pedidos heredadas durante 30 días, el equipo elimina el adaptador, el pipeline de captura de datos de cambios y las reglas de enrutamiento antiguas, y después borra del monolito el código y las tablas de pedidos. Solo en este punto se completa la migración. |
Cada paso entrega algo utilizable o elimina riesgo, y todos los pasos salvo el último tienen un rollback barato.
El sistema de registro de los pedidos no es ambiguo en ninguna etapa, y los datos fluyen en un solo sentido cada vez.
La arquitectura de transición se planifica, se mide y se elimina deliberadamente; el éxito se mide por lo que se ha apagado.
Comprueba lo que has entendido
¿Por qué una reescritura big-bang tiende a perder comportamiento del que dependen los usuarios?
Porque años de correcciones de bugs y reglas de negocio solo existen en el código antiguo y en los hábitos de los usuarios; nadie puede enumerarlos todos, así que una reescritura a partir de una especificación pasa por alto algunos.
¿Qué aporta la fachada de enrutamiento a una migración strangler fig?
Permite trasladar el tráfico porción a porción, y devolverlo si algo sale mal, sin editar el sistema heredado en cada paso.
¿Qué es la arquitectura de transición y por qué hay que seguir su eliminación?
Código temporal, como reglas de enrutamiento, adaptadores y trabajos de sincronización, que permite que lo antiguo y lo nuevo coexistan; seguir su eliminación protege frente a una migración que se estanca con ambos sistemas funcionando indefinidamente.
¿Cuándo puede ser recomprar una opción mejor que refactorizar?
Cuando la capacidad es genérica en lugar de diferenciadora y existe un buen producto, de modo que reconstruirla supondría invertir esfuerzo donde el negocio no compite.
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: “Nuestro sistema central es un monolito de 15 años que solo entienden dos personas. ¿Cómo decido si reescribirlo y, si no, por dónde debería empezar una migración incremental?”