El patrón de higo estrangulador: una forma segura de migrar aplicaciones monolíticas

El patrón de higo estrangulador: una forma segura de migrar aplicaciones monolíticas

En la ingeniería de software moderna, las aplicaciones monolíticas heredadas son un desafío común. Con el tiempo, una base de código exitosa crece y se interconecta tanto que realizar cambios simples se vuelve riesgoso, las implementaciones toman horas y escalar funciones individuales es prácticamente imposible.

Cuando los equipos deciden modernizar sus sistemas migrando a microservicios, se enfrentan a una pregunta de alto riesgo: ¿Cómo reescribimos el sistema sin arruinar nuestro negocio actual?

Una opción es una reescritura tipo “Big Bang”: construir el nuevo sistema desde cero a puerta cerrada y cambiarlo todo en un solo día. Sin embargo, esto es increíblemente arriesgado y frecuentemente conduce al fracaso.

Afortunadamente, existe una alternativa más segura y confiable: el Patrón de Higo Estrangulador. En esta guía, exploraremos qué es el patrón de la higuera estranguladora, por qué funciona y cómo aplicarlo paso a paso utilizando diagramas claros y código del mundo real.


La analogía del mundo real: la planta del higo estrangulador

El patrón lleva el nombre del higo estrangulador, una planta originaria de las selvas tropicales.

Una semilla de higuera estranguladora germina en las ramas superiores de un árbol “huésped” existente. En lugar de crecer desde el suelo hacia arriba, el higo crece hacia abajo:

  1. Envía raíces por el tronco del árbol huésped hasta que llegan al suelo del bosque y se anclan en el suelo.
  2. Con el tiempo, crecen más raíces, se envuelven alrededor del huésped y se fusionan.
  3. Al higo le crecen hojas que impiden que la luz llegue al árbol huésped.
  4. Con el tiempo, el árbol huésped muere y se pudre, dejando una higuera estranguladora hueca que se alza con fuerza en su lugar.

En la arquitectura de software, el monolito heredado es el árbol anfitrión y los nuevos microservicios son la figura estranguladora. Construimos los nuevos servicios alrededor de los bordes del monolito, alejando gradualmente el tráfico del sistema heredado hasta que el monolito pueda cerrarse por completo.


Por qué fallan las reescrituras de “Big Bang”

Antes de sumergirnos en la mecánica del patrón Strangler Fig, comprendamos por qué la alternativa (una reescritura completa) es tan peligrosa:

  • Sin valor durante meses (o años): los desarrolladores dedican mucho tiempo a escribir código, pero nada se activa hasta que se completa todo el proyecto.
  • Ampliación del alcance: durante una reescritura de dos años, las necesidades del negocio cambian. El objetivo se mueve y el nuevo sistema debe admitir características que no existían cuando comenzó la reescritura.
  • Comportamiento implícito faltante: los monolitos contienen años de correcciones de errores no documentados y manejos de casos extremos. Una reescritura desde cero a menudo olvida estos detalles.
  • Alto riesgo de implementación: apagar un sistema heredado masivo y encender uno nuevo al mismo tiempo crea un radio de explosión masivo si algo sale mal.

Cómo funciona el patrón del higo estrangulador

La idea central del patrón Strangler Fig es la migración incremental. En lugar de migrar todo el sistema, migra una pequeña característica o “porción” a la vez.

Diagrama de etapas de migración del patrón de higuera estranguladora

El proceso de migración se ejecuta en cinco etapas clave:

1. Identificar un contexto acotado

Mire su monolito e identifique una capacidad empresarial única e independiente que sea fácil de extraer. Los buenos candidatos incluyen:

  • Funciones que cambian con frecuencia (para que el equipo se beneficie rápidamente de implementaciones independientes).
  • Funciones simples y de bajo riesgo (como una sección estática de preguntas frecuentes o preferencias del usuario) para probar el proceso de migración.
  • Funciones con límites de base de datos limpios y bien definidos.

2. Implementar el nuevo microservicio

Desarrolle la capacidad identificada como un microservicio nuevo y moderno. Este servicio tiene su propia base de datos, su propio proceso de implementación y está construido utilizando tecnologías modernas. Lo más importante es que la antigua característica del monolito permanece activa y sin cambios por ahora.

3. Introducir la capa de intercepción

Para que la migración sea transparente para sus usuarios, introduzca una Capa de interceptación (como una puerta de enlace API o un proxy inverso) delante de la aplicación. Todo el tráfico de clientes ahora va primero a esta puerta de enlace.

Inicialmente, la puerta de enlace enruta el 100 % de todas las solicitudes al monolito heredado.

4. Transición del tráfico de forma incremental

Una vez que el nuevo microservicio esté completamente probado y listo, actualice las reglas de enrutamiento en la capa de intercepción. En lugar de enrutar solicitudes para la función migrada (por ejemplo, /api/users) al monolito, la puerta de enlace las redirige al nuevo microservicio.

Todas las demás solicitudes continúan yendo al monolito. Si el nuevo servicio falla o presenta errores, puede actualizar rápidamente la puerta de enlace para enrutar el tráfico de regreso al monolito, asegurando una interrupción mínima.

5. Desmantelamiento y repetición

Después de que el nuevo microservicio se ejecute de manera estable durante un período de tiempo, puede eliminar de forma segura el código correspondiente dentro del monolito heredado.

Luego selecciona la siguiente función y repite el proceso. Con el tiempo, el monolito se reduce hasta que ya no le queda tráfico y usted puede desmantelar el servidor heredado por completo.


La capa de interceptación: ejemplo de enrutamiento rápido

El corazón del patrón Strangler Fig es la Capa de Intercepción. Le permite redirigir solicitudes sin modificar las aplicaciones cliente (aplicaciones web, aplicaciones móviles).

A continuación se muestra un ejemplo práctico de Node.js que utiliza un proxy de puerta de enlace basado en Express. Enruta las solicitudes de forma dinámica: las solicitudes entrantes van a los nuevos servicios si coinciden con las rutas migradas; de lo contrario, vuelven al monolito heredado.

const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
const PORT = 8080;

// Configuration: Target server URLs
const LEGACY_MONOLITH_URL = 'http://legacy-monolith-server:3000';
const NEW_USER_SERVICE_URL = 'http://new-user-service:3001';
const NEW_PAYMENT_SERVICE_URL = 'http://new-payment-service:3002';

// Simple logging middleware to track traffic distribution
app.use((req, res, next) => {
    console.log(`[ROUTE LOG] Incoming request: ${req.method} ${req.url}`);
    next();
});

// 1. MIGRATED: User registration & profile requests route to the new microservice
app.use('/api/users', createProxyMiddleware({
    target: NEW_USER_SERVICE_URL,
    changeOrigin: true,
    pathRewrite: {
        '^/api/users': '/v1/users', // Translate path format if necessary
    }
}));

// 2. MIGRATED: Payment transactions route to the new payment microservice
app.use('/api/payments', createProxyMiddleware({
    target: NEW_PAYMENT_SERVICE_URL,
    changeOrigin: true
}));

// 3. FALLBACK: All other legacy routes automatically default to the Monolith
app.use('/', createProxyMiddleware({
    target: LEGACY_MONOLITH_URL,
    changeOrigin: true
}));

app.listen(PORT, () => {
    console.log(`Interception Gateway routing traffic successfully on port ${PORT}`);
});

Manejo de la base de datos: la parte más difícil

Si bien enrutar el tráfico API es relativamente fácil, administrar datos es el aspecto más desafiante de la migración monolítica. Un monolito suele tener una base de datos única y masiva donde las tablas están muy unidas.

Cuando extraes un servicio, también debes extraer sus datos. Hay dos enfoques comunes para manejar esto:

  1. Escrituras duales: la capa de interceptación o la aplicación escribe datos tanto en la base de datos heredada como en la nueva base de datos del servicio simultáneamente durante la fase de transición. Esto mantiene ambas bases de datos sincronizadas.
  2. Captura de datos de cambios (CDC): una herramienta como Debezium monitorea el registro de transacciones de la base de datos heredada y transmite automáticamente los cambios a la nueva base de datos de microservicio casi en tiempo real.

Una vez que esté seguro de que las bases de datos están completamente sincronizadas y que la nueva base de datos es correcta, cambia el tráfico de lectura al nuevo servicio y cierra las tablas heredadas.


Comparación: Big Bang Rewrite versus Strangler Fig

Característica / Métrica Reescritura del Big Bang Patrón de higo estrangulador
Nivel de riesgo Extremadamente alto Bajo y Gestionado
Bucle de retroalimentación Muy Lento (sólo al final) Rápido (pruebas de producción continua)
Estrategia de reversión Duro (requiere restaurar copias de seguridad) Fácil (cambiar reglas de ruta en la puerta de enlace)
Impacto empresarial Disruptivo Tiempo de inactividad cero
Complejidad del sistema Alto (durante la fase de construcción) Alta (durante la fase de migración)
Tiempo de implementación Lanzamiento masivo del single Actualizaciones pequeñas y frecuentes

Conclusión

Strangler Fig Pattern es el estándar de la industria para migrar monolitos a microservicios. Al reemplazar el código heredado de forma incremental en lugar de hacerlo todo a la vez, se elimina el riesgo de una falla “Big Bang”.

Mantiene las implementaciones pequeñas, proporciona retroalimentación instantánea del tráfico de producción real y permite a su equipo continuar brindando valor comercial durante todo el ciclo de vida de la migración.

Si bien administrar la migración de bases de datos y ejecutar dos sistemas paralelos agrega complejidad operativa, la seguridad, previsibilidad y estabilidad que ofrece la convierten en la opción preferida para las migraciones modernas a la nube.


Explore más conocimientos sobre desarrollo de software e ingeniería backend en el Blog de Ghaznix →