Módulo 1: Por qué no reescribir

La metáfora de la higuera estranguladora

Descripción

La lección anterior justificó lo incremental con números: más valor acumulado, menos riesgo por paso. Esta lección le pone nombre e imagen —una imagen tan buena que se volvió el nombre técnico de la estrategia—. En 2004, Martin Fowler viajó a Queensland, en el noreste de Australia, y quedó impresionado por unas plantas llamadas higueras estranguladoras (strangler figs). Estas higueras crecen de una forma peculiar: su semilla germina en lo alto de otro árbol —en una rama, en una grieta de la corteza— y desde ahí lanza raíces hacia el suelo que van envolviendo el tronco del árbol anfitrión. Con los años, la higuera crece alrededor del árbol, lo va cubriendo, y eventualmente lo reemplaza por completo: el árbol original muere y se descompone, y queda en su lugar la higuera, con un tronco hueco donde antes estaba el otro. Fowler vio en eso la metáfora perfecta para modernizar un sistema legacy, y la llamó Strangler Fig Application.

Fíjate en lo que la metáfora captura, porque cada detalle importa. La higuera no tala al árbol anfitrión y luego planta uno nuevo en el hueco —eso sería el big rewrite: cortar todo y quedarse dos años con un tocón—. La higuera crece alrededor del árbol vivo, tomando su lugar gradualmente, y en ningún momento hay un claro sin árbol: el anfitrión sigue vivo, dando sombra y sosteniendo el ecosistema, hasta que la higuera puede sostenerlo sola. Ese es el principio de modernizar en su lugar: construyes lo nuevo alrededor de lo viejo, desvías responsabilidades de a poco, y el sistema nunca deja de funcionar durante la transición. Esta lección instala la metáfora y su porqué —por qué el reemplazo gradual con el viejo siempre vivo evita el apagón del corte big-bang—. La mecánica de cómo se hace ese desvío (el router, el facade, el reparto de tráfico paso a paso) es el módulo 3; aquí, la imagen y la razón.

Conexión con el módulo. La lección 5 midió por qué lo incremental gana; esta le da la metáfora canónica que da nombre a toda la técnica de la guía y que vas a encontrar en cada módulo que sigue. El strangler fig es la respuesta concreta a la pregunta "¿cómo modernizo sin apagar el negocio?": envuelve, desvía, reemplaza, retira. Aquí trabajamos la metáfora y el porqué; el cómo —el strangler_router que reparte traffic_percent entre legacy y modern con fallback— es el corazón del módulo 3. La frontera es estricta: si esta lección te deja con ganas de ver el router funcionando, esa es exactamente la señal de que estás listo para el módulo 3.

Una analogía: reemplazar el puente sin cerrar el río

Un pueblo tiene un puente viejo sobre el río, el único cruce, por el que pasa todo: gente al trabajo, camiones de mercancía, ambulancias. El puente está deteriorado y hay que reemplazarlo. Hay dos formas de hacerlo.

Forma 1 — demoler y reconstruir. Cierras el puente, lo demueles, y construyes uno nuevo en el mismo lugar. Durante los dos años de obra, no hay cruce: la gente da un rodeo de una hora, los camiones no pasan, las ambulancias tampoco. El pueblo se paraliza a la espera del puente nuevo. Es el big rewrite: apagas lo viejo, y hasta que lo nuevo esté listo, no hay servicio.

Forma 2 — construir el nuevo al lado y mudar el tráfico de a poco. Construyes el puente nuevo junto al viejo, sin tocar el viejo, que sigue cargando todo el tráfico mientras tanto. Cuando el nuevo está listo, no cierras el viejo de golpe: primero desvías por el nuevo solo a los peatones, y observas —¿aguanta?, ¿algo falla?—. Si todo va bien, desvías también los autos ligeros. Luego los camiones. Y si en cualquier momento el puente nuevo da problemas, devuelves ese tráfico al viejo, que sigue ahí, en un instante. Cuando el 100% del tráfico cruza por el nuevo sin problemas durante un tiempo, entonces retiras el viejo. En ningún momento el pueblo se quedó sin cruce.

La forma 2 es la higuera estranguladora, y es el patrón que da nombre a esta guía. El puente viejo es tu sistema legacy; el nuevo, el moderno; el tráfico que mudas de a poco es el traffic_percent que en el módulo 3 vas a repartir con un router. Los dos puentes coexisten durante la transición —cuesta un poco más tener dos puentes que uno, sí—, pero a cambio el río nunca se cierra: el pueblo cruza todos los días, y el riesgo de cada paso está acotado a quienes desviaste, con el puente viejo siempre listo como respaldo. Esta lección mide justo esa diferencia: el pueblo que nunca se quedó sin cruce contra el pueblo paralizado dos años.

Ejemplo trabajado: el sistema siempre vivo vs el corte big-bang

Vamos a modelar dos cosas. Primero, el desvío gradual de tráfico del legacy al moderno —el traffic_percent que sube del 0 al 100— y verificar la propiedad clave: en cada paso, el sistema sigue vivo. Segundo, comparar qué pasa cuando ocurre un incidente serio (un bug latente en el código nuevo) en cada estrategia: el big-bang lo expone al 100% de los usuarios sin red; el strangler lo expone a una fracción pequeña, con el viejo como fallback instantáneo. Medimos el impacto esperado de ese incidente:

STEPS = 10  # el trafico al nuevo servicio sube 10% por paso

print("Desvio gradual de trafico (legacy -> modern), el sistema NUNCA se apaga:")
print(f"{'semana':>7}{'legacy%':>9}{'modern%':>9}{'sistema vivo?':>15}")
print("-" * 40)
for step in range(0, STEPS + 1):
    modern = step * 100 // STEPS
    legacy = 100 - modern
    print(f"{step:>7}{legacy:>9}{modern:>9}{'si':>15}")

# Un incidente serio durante la migracion: mismo bug latente en el codigo nuevo.
P_FAIL = 0.30            # probabilidad de que el codigo nuevo esconda un bug serio
MTTR_BIGBANG = 8.0       # horas para revertir un corte total (el viejo ya se apago)
MTTR_STRANGLER = 0.25    # horas: el fallback al viejo es casi instantaneo
FIRST_STEP_TRAFFIC = 0.10  # con strangler el bug asoma al 10% y ahi lo atrapas

# "horas-usuario de impacto" = probabilidad * duracion * fraccion de trafico golpeado
bigbang_impact = P_FAIL * MTTR_BIGBANG * 1.00
strangler_impact = P_FAIL * MTTR_STRANGLER * FIRST_STEP_TRAFFIC

print("\nUn incidente serio durante la migracion:")
print(f"{'estrategia':<14}{'trafico afectado':>18}{'downtime forzado':>18}"
      f"{'horas-usuario':>16}")
print("-" * 66)
print(f"{'big-bang':<14}{'100%':>18}{'si (corte)':>18}{bigbang_impact:>16.3f}")
print(f"{'strangler':<14}{'10% (y pausas)':>18}{'no (fallback)':>18}"
      f"{strangler_impact:>16.3f}")

print(f"\n  El big-bang expone al 100% de los usuarios en un solo momento.")
print(f"  El strangler expone {FIRST_STEP_TRAFFIC:.0%}, cae al viejo al instante y "
      f"pausa el avance.")
print(f"  Impacto esperado {bigbang_impact / strangler_impact:.0f}x menor con el "
      f"reemplazo gradual - y cero apagones.")

Qué esperar. Al correr el archivo, la salida es exactamente esta:

Desvio gradual de trafico (legacy -> modern), el sistema NUNCA se apaga:
 semana  legacy%  modern%  sistema vivo?
----------------------------------------
      0      100        0             si
      1       90       10             si
      2       80       20             si
      3       70       30             si
      4       60       40             si
      5       50       50             si
      6       40       60             si
      7       30       70             si
      8       20       80             si
      9       10       90             si
     10        0      100             si

Un incidente serio durante la migracion:
estrategia      trafico afectado  downtime forzado   horas-usuario
------------------------------------------------------------------
big-bang                    100%        si (corte)           2.400
strangler         10% (y pausas)     no (fallback)           0.007

  El big-bang expone al 100% de los usuarios en un solo momento.
  El strangler expone 10%, cae al viejo al instante y pausa el avance.
  Impacto esperado 320x menor con el reemplazo gradual - y cero apagones.

Lee primero la tabla de arriba, la del desvío gradual, porque su columna más importante es la última.

De la semana 0 a la 10, el tráfico se muda del legacy al moderno de a 10% por paso: 100/0, 90/10, 80/20... hasta 0/100. Es la higuera creciendo alrededor del árbol, o el tráfico del puente mudándose de a poco. Pero mira la columna sistema vivo: en todas las filas dice "si". En ningún momento —ni en la semana 0, ni en la 5, ni en la 10— el sistema estuvo apagado. Esa es la propiedad que la metáfora promete y que el big-bang no puede dar: la transición ocurre con el sistema en producción todo el tiempo. No hay un sábado a medianoche con todo apagado; hay diez semanas de reparto gradual con el negocio funcionando cada día. El río nunca se cerró.

Ahora la segunda tabla, la del incidente, que mide por qué eso importa cuando algo sale mal —y en un sistema nuevo, algo siempre sale mal—. Supón que el código moderno esconde un bug serio (probabilidad 0.30, la misma para ambas estrategias: el código nuevo es igual de inmaduro en los dos casos).

En el big-bang, cuando ese bug se manifiesta, golpea al 100% del tráfico —porque en el corte todo pasó al nuevo de una vez—, y revertir tarda 8 horas, porque el viejo ya se apagó y volver atrás implica reencenderlo y reconciliar lo que se procesó. El impacto esperado: 0.30 × 8 × 1.00 = 2.4 horas-usuario, con downtime forzado y el 100% de los usuarios afectados. Es el pueblo entero sin cruce mientras arreglan el puente nuevo que falló.

En el strangler, el mismo bug asoma en el primer paso, cuando el nuevo carga apenas el 10% del tráfico. Lo detectas rápido (el volumen pequeño hace fácil notar la anomalía), devuelves ese 10% al viejo —que sigue vivo— en 0.25 horas, y pausas el avance hasta entender qué pasó. El impacto esperado: 0.30 × 0.25 × 0.10 = 0.007 horas-usuario, sin downtime forzado, con solo el 10% de los usuarios rozados. El resultado: 320 veces menos impacto, y cero apagones. No es que el strangler tenga menos bugs —tiene los mismos—; es que cuando un bug aparece, lo encuentra temprano, con poca gente expuesta y una salida de emergencia (el viejo) siempre disponible.

Junta las dos tablas y tienes la esencia de la metáfora: el sistema nunca se apaga (primera tabla) y cuando algo falla, falla pequeño y reversible (segunda tabla). El big-bang apuesta a que el corte salga perfecto a la primera sobre el 100% del sistema; el strangler no necesita que nada salga perfecto, porque cada paso es chico, observable y reversible. Esa es la diferencia entre reemplazar el puente con el río abierto y cerrarlo dos años.

Profundización: por qué el viejo como fallback lo cambia todo

El detalle de la metáfora que más gente pasa por alto es que el árbol anfitrión sigue vivo mientras la higuera crece. Traducido al software: durante toda la migración strangler, el sistema legacy sigue funcionando y sirviendo el tráfico que no has desviado. No es un sistema muerto que estás reemplazando; es un sistema vivo que sigue siendo tu red de seguridad. Y esa red cambia por completo el perfil de riesgo, por tres razones.

Primero, el fallback es instantáneo y barato. Si el moderno falla en el 10% que le diste, devolver ese tráfico al viejo es cambiar un número en el router (el traffic_percent de vuelta a 0) —no es reconstruir nada—. En el big-bang no hay fallback: apagaste el viejo, así que "volver atrás" significa reencenderlo y lidiar con los datos que ya se escribieron en el nuevo. Por eso el MTTR del ejemplo es 0.25 horas contra 8: no es que el equipo del strangler sea más rápido arreglando; es que su reversión es trivial y la del big-bang es una operación mayor.

Segundo, descubres los problemas con poca gente expuesta. Los bugs del conocimiento tácito (lección 4) no se ven en el código: se ven cuando un cliente real hace algo raro. Con el strangler, esos casos raros golpean primero al 10% del tráfico, donde los detectas y corriges antes de subir al 20%. Con el big-bang, todos los casos raros del 100% del tráfico llegan a la vez, el primer día, sin margen para aprender de uno antes del siguiente.

Tercero, el avance es reversible en cada punto. Puedes subir a 30%, ver un problema, bajar a 20%, corregir, y volver a subir. La migración no es una flecha de un solo sentido hacia un corte irreversible; es un dial que giras en ambas direcciones según lo que midas. Esa reversibilidad es justo lo que un sistema crítico necesita, y justo lo que el corte big-bang no tiene.

flowchart LR
    subgraph Strangler["Strangler fig: el viejo vivo como red"]
      C["cliente"] --> R["router<br/>(traffic_percent)"]
      R -->|"90%"| L["legacy (vivo)"]
      R -->|"10%"| M["modern (nuevo)"]
      M -. "si falla, vuelve a" .-> L
    end

Una aclaración de frontera, para no adelantarnos: todo lo que este diagrama muestra —el router, el reparto de porcentaje, el fallback— es la mecánica del módulo 3. Esta lección no te pide construirlo; te pide entender por qué funciona: porque mantiene el viejo vivo como red mientras crece lo nuevo. El nombre técnico completo (facade, traffic_percent, branch_by_abstraction, retirar el legacy al 100%) y su implementación ejecutada llegan en los módulos siguientes. Aquí te quedas con la imagen —la higuera, el puente— y la razón —el sistema siempre vivo, el fallback siempre listo—.

Errores comunes

Confundir la metáfora con un big-bang lento. Qué pasa: alguien dice "sí, hacemos strangler" pero en realidad construye el sistema nuevo entero por meses y luego lo enciende de golpe —solo que llamándolo "migración gradual"—. Por qué pasa: la palabra "strangler" suena bien y se adopta sin su esencia. Cómo detectarlo: pregunta "¿en qué momento el sistema nuevo empieza a servir tráfico real de producción?". Si la respuesta es "al final, cuando esté completo", no es strangler: es un big-bang con otro nombre, y hereda todo el riesgo del corte único. Cómo corregirlo: la esencia del strangler es que el nuevo sirve tráfico desde temprano y de a poco, con el viejo vivo al lado. Si no hay reparto gradual de tráfico real, con fallback al viejo, no estás estrangulando: estás reescribiendo con un discurso más moderno. La primera rebanada tiene que ir a producción con tráfico real pronto, aunque sea al 5%.

Apagar el viejo antes de tiempo. Qué pasa: apenas el tráfico del moderno llega a un porcentaje alto (digamos 80%), el equipo decide "ya casi está" y apaga el legacy para ahorrarse el costo de mantener dos sistemas. Por qué pasa: mantener el viejo vivo cuesta, y la tentación de "cerrar el capítulo" es fuerte. Cómo detectarlo: si se propone retirar el legacy antes de que el moderno haya servido el 100% del tráfico de forma estable durante un tiempo, se está quitando la red antes de tiempo. Cómo corregirlo: el viejo se retira solo cuando el nuevo ha cargado el 100% del tráfico sin problemas durante un periodo de observación —ese es el último paso de la higuera, cuando el árbol anfitrión ya puede morir porque la higuera se sostiene sola—. Apagarlo al 80% es quedarse sin fallback justo en el 20% de casos que aún no has validado, que —por la lección 4— suelen ser los raros y peligrosos. El costo de mantener el viejo un poco más es la prima que compra la reversibilidad hasta el final.

Tratar el porcentaje de tráfico como una flecha de un solo sentido. Qué pasa: el equipo sube el traffic_percent y, ante un problema, insiste en "seguir adelante para no perder el avance" en vez de bajarlo. Por qué pasa: bajar el porcentaje se siente como retroceder, como admitir fracaso. Cómo detectarlo: si ante un incidente en el moderno la reacción es "aguantemos y arreglemos en caliente" en vez de "devolvamos el tráfico al viejo y diagnostiquemos con calma", se está desperdiciando la mayor ventaja del patrón. Cómo corregirlo: el reparto de tráfico es un dial, no una palanca de un solo sentido. Su poder está justamente en que puedes bajarlo: ante un problema, devolver tráfico al viejo (que sigue vivo) es la jugada segura —los usuarios vuelven a un sistema que funciona mientras el equipo investiga sin presión—. Girar el dial hacia atrás no es fracasar; es usar la red que el patrón te dio. El módulo 3 y el módulo 7 (medir el progreso) muestran cómo distinguir un retroceso sano de un estancamiento.

Ejercicios

Ejercicio 1 — Desarma la metáfora. La higuera estranguladora captura la modernización en su lugar con varios detalles precisos. Para cada uno de estos elementos de la metáfora, di qué representa en la migración de un sistema legacy: (a) el árbol anfitrión que sigue vivo; (b) las raíces de la higuera que bajan envolviendo el tronco; (c) el momento en que el árbol anfitrión finalmente muere; (d) que la higuera nunca deja un claro sin árbol.

Ver solución
  • (a) El árbol anfitrión vivo representa el sistema legacy en producción, que sigue funcionando y sirviendo tráfico durante toda la migración. No es un sistema muerto que reemplazas; es tu red de seguridad activa, el fallback siempre disponible mientras crece lo nuevo.
  • (b) Las raíces que bajan envolviendo el tronco representan el sistema moderno tomando responsabilidades de a poco: cada raíz nueva es una rebanada de funcionalidad (o un porcentaje de tráfico) que se desvía del viejo al nuevo. La higuera no reemplaza todo de golpe; envuelve gradualmente, como el traffic_percent que sube paso a paso.
  • (c) El momento en que el anfitrión muere representa el retiro final del legacy, que ocurre solo cuando el moderno ya carga el 100% del tráfico de forma estable —el último paso, cuando la higuera se sostiene sola y el viejo ya no hace falta—. Es el apagado del sistema viejo, y llega al final, no al principio.
  • (d) Que nunca hay un claro sin árbol representa la propiedad central: el sistema nunca se apaga durante la transición. En ningún momento el negocio se queda sin servicio, a diferencia del big-bang (demoler y esperar dos años con un tocón). Es la columna "sistema vivo: si" en todas las filas de la primera tabla.

Ejercicio 2 — Calcula el impacto del incidente. Usando la fórmula del ejemplo (impacto = probabilidad × duración × fracción de tráfico afectado), compara dos migraciones ante un incidente con probabilidad 0.20. En la primera (big-bang), el incidente afecta al 100% del tráfico y tarda 6 horas en revertirse. En la segunda (strangler), afecta al 5% del tráfico y se revierte en 0.2 horas con fallback al viejo. Calcula el impacto de cada una y el factor de reducción.

Ver solución
  • Big-bang: impacto = 0.20 × 6 × 1.00 = 1.2 horas-usuario, con el 100% de los usuarios afectados y downtime forzado (el viejo ya se apagó).
  • Strangler: impacto = 0.20 × 0.2 × 0.05 = 0.002 horas-usuario, con solo el 5% de los usuarios rozados y sin downtime forzado (el viejo sigue vivo como fallback).
  • Factor de reducción: 1.2 / 0.002 = 600x menos impacto con el strangler.

Nota que la probabilidad del bug (0.20) es la misma para ambos: el código nuevo es igual de inmaduro en las dos estrategias. La reducción de 600x no viene de tener menos bugs, sino de los otros dos factores: el strangler afecta a mucha menos gente (5% vs 100%) y se revierte muchísimo más rápido (0.2 h vs 6 h, porque el fallback al viejo es trivial). El patrón no promete código sin fallos; promete que, cuando un fallo aparezca, sea pequeño y reversible en vez de total e irreversible.

Ejercicio 3 — El costo de mantener dos sistemas. Un gerente objeta: "el strangler me obliga a mantener el sistema viejo y el nuevo funcionando a la vez durante toda la migración; eso es más caro que solo mantener uno. ¿Por qué vale la pena ese sobrecosto?". Responde usando la metáfora y las mediciones de la lección, y di cuándo ese sobrecosto no valdría la pena.

Ver solución

El gerente tiene razón en el hecho: mantener el viejo y el nuevo en paralelo (los dos puentes sobre el río) cuesta más que mantener uno solo. Ese sobrecosto es real y hay que reconocerlo, no negarlo.

Por qué vale la pena, con la metáfora y las cifras:

  1. El río nunca se cierra. La primera tabla mostró "sistema vivo: si" en todas las filas: el negocio funciona cada día de la migración. La alternativa (un solo sistema) solo es más barata si aceptas el apagón del corte —los dos años con el pueblo sin cruce—. Para un sistema con clientes activos como Mercado, ese apagón no es una opción, así que la comparación honesta no es "un sistema vs dos", sino "dos sistemas con el negocio vivo vs un corte que arriesga apagarlo".
  2. El fallback reduce el impacto de los incidentes 320x. El viejo vivo es la red de seguridad que hace que un incidente afecte al 10% en vez del 100%, y que se revierta en minutos en vez de horas. El sobrecosto de mantener el viejo es, literalmente, el costo de esa red. La segunda tabla lo midió: sin el viejo como fallback (big-bang), el impacto esperado de un incidente es 2.4 horas-usuario; con él (strangler), 0.007. Ese sobrecosto compra una reducción de riesgo enorme.

Cuándo no valdría la pena: si el sistema fuera pequeño, sin usuarios en producción, o si un apagón fuera aceptable (un tocón por unos días no rompe nada). En ese caso, mantener dos sistemas es pagar por una red que no necesitas, y un reemplazo directo sería más simple. Esa es exactamente la región estrecha que la lección 7 identifica —y Mercado, con clientes comprando ahora y un sistema crítico, no está en ella—. El sobrecosto del strangler es una prima de seguro: sabia cuando el riesgo es alto, desperdicio cuando el riesgo es bajo.

Resumen y siguiente paso

En esta lección instalaste la metáfora que da nombre a toda la técnica de la guía: la higuera estranguladora. Viste cómo la higuera crece envolviendo al árbol anfitrión y lo reemplaza sin talarlo, con el árbol vivo todo el tiempo, y cómo eso se traduce en modernizar en su lugar: construir lo nuevo alrededor de lo viejo, desviar tráfico de a poco, y retirar el legacy solo al final. Y lo mediste: el desvío gradual mantiene el sistema vivo en cada paso (la columna "si" en todas las filas), y ante un incidente serio, el strangler tiene un impacto esperado 320x menor que el big-bang —no por tener menos bugs, sino porque los encuentra temprano, con poca gente expuesta y el viejo siempre listo como fallback—. El puente nuevo se construye al lado sin cerrar el río.

Antes de avanzar deberías poder: explicar cada detalle de la metáfora (el anfitrión vivo, las raíces, el retiro final, el claro que nunca queda vacío); argumentar por qué el viejo como fallback cambia el perfil de riesgo; calcular el impacto de un incidente en ambas estrategias; y distinguir un strangler real de un big-bang disfrazado.

La lección 7 cierra el módulo consolidando la tesis sin caer en dogma: modernizar en su lugar vs empezar de cero. Porque reescribir no es siempre malo —hay una región estrecha donde sí es la opción correcta—, y vas a puntuar varios sistemas en cinco ejes para ver exactamente dónde cae esa región, y por qué Mercado está en la esquina opuesta. Con eso quedarás listo para el mini-proyecto, donde armarás la defensa completa contra el rewrite de Mercado.

Recursos

  • Martin Fowler, "StranglerFigApplication" (2004) — martinfowler.com/bliki/StranglerFigApplication.html. La fuente original de la metáfora, con la historia de las higueras de Queensland que inspiraron el nombre. Lectura obligada de esta lección. En inglés.
  • Sam Newman, Monolith to Microservices (O'Reilly, 2019), cap. 3, sección "Strangler Fig Pattern" — la mecánica del patrón (el proxy, el desvío de tráfico, el retiro del legacy) que el módulo 3 de esta guía desarrolla. En inglés.
  • Paul Hammant, "Legacy Application Strangulation: Case Studies" — paulhammant.com/2013/07/14/legacy-application-strangulation-case-studies. Casos reales de estrangulamiento de sistemas legacy, con los patrones de desvío de tráfico en la práctica. En inglés.
  • microservices.io, "Pattern: Strangler Application" — microservices.io/patterns/refactoring/strangler-application.html. Ficha del patrón con su contexto, fuerzas y consecuencias. Referencia rápida para el módulo 3. En inglés.