Módulo 1: Por qué no reescribir

El caso a favor de lo incremental

Descripción

Las tres lecciones anteriores construyeron el caso contra el rewrite: el negocio no se detiene, el segundo sistema infla el alcance, el conocimiento tácito se pierde. Pero derribar una opción no basta —hay que mostrar que la alternativa es de verdad mejor, y por qué—. Esta lección construye el caso a favor de lo incremental, y lo hace con números, no con eslóganes. La tesis es que transformar un sistema por rebanadas gana por dos razones medibles y distintas: entrega valor temprano y arriesga poco en cada paso.

La primera razón es sobre el tiempo del valor. En una migración incremental, cada rebanada que modernizas entra a producción y empieza a pagar de inmediato: la primera rebanada da valor desde el primer periodo, no espera al final. En un big rewrite, en cambio, no hay valor hasta el corte final —todo el beneficio se concentra en un punto lejano en el futuro, y el valor que llega tarde vale menos que el que llega temprano, porque durante toda la espera no estuvo trabajando para ti—. La segunda razón es sobre el riesgo. En cada despliegue incremental, lo que puede salir mal está acotado a una rebanada: si falla, reviertes una pieza pequeña. En un big rewrite, el corte cambia el sistema entero de una vez, así que el riesgo en juego en ese único momento es máximo: si falla, cae todo. Esta lección mide las dos cosas —los valor-periodos acumulados (el área bajo la curva de valor entregado) y el riesgo en juego por despliegue— para que la ventaja del incremental deje de ser una creencia y sea una medición.

Conexión con el módulo. Esta es la bisagra del módulo: cierra el caso contra el rewrite (lecciones 2-4) y abre el caso a favor de la alternativa. Las dos métricas que ejecutas aquí —valor-periodos y riesgo en juego— son la contraparte cuantitativa de la ventaja incremental. La lección 6 le pone nombre e imagen a esta alternativa con la metáfora del strangler fig, y la 7 delimita cuándo el incremental es de verdad la opción correcta (casi siempre) y cuándo no. La mecánica de cómo se entrega una rebanada sin apagar el sistema es el módulo 3 en adelante; aquí, el porqué medido.

Una analogía: dos formas de pagar una casa

Imagina dos maneras de tener casa propia. En la primera, ahorras durante veinte años sin tocar el dinero, y al final del año veinte compras la casa de contado. En la segunda, das un enganche hoy y te mudas esta semana, y pagas el resto poco a poco mientras ya vives en ella. Supón que el costo total es idéntico en ambas. ¿Son equivalentes? Para nada. En la primera, pasas veinte años sin casa —rentando, esperando— y solo el año veinte empiezas a disfrutarla. En la segunda, disfrutas la casa desde la primera semana: tienes veinte años de "vivir en tu casa" que la otra opción no tiene. El mismo dinero, pero uno te da el beneficio ahora y el otro te lo da al final, y el "ahora" acumulado durante veinte años vale muchísimo más.

El valor del software funciona igual. Modernizar por rebanadas es mudarte esta semana: cada pieza modernizada empieza a dar beneficio (mejor rendimiento, features desbloqueadas, menos mantenimiento) desde que entra a producción, y ese beneficio se acumula durante todo el tiempo que falta para terminar el resto. El big rewrite es ahorrar veinte años: no disfrutas nada hasta el corte final, y todo el "tiempo de valor" que la migración incremental fue acumulando, el rewrite simplemente lo perdió. Y hay una segunda diferencia, la del riesgo: en la casa a plazos, si un mes no puedes pagar, ajustas una cuota; en la compra de contado, todo tu patrimonio de veinte años está en una sola transacción, y si esa transacción sale mal, lo pierdes todo de golpe. Vamos a medir las dos diferencias.

Ejemplo trabajado: valor-periodos y riesgo en juego

Vamos a modelar un sistema de 8 rebanadas modernizables sobre un horizonte de 12 periodos. El "valor moderno vivo" en cada periodo es cuántas rebanadas ya están modernizadas y sirviendo. El incremental moderniza una rebanada por periodo, así que su valor vivo sube de a poco desde el periodo 1. El big rewrite entrega las 8 de golpe en el corte —optimista en el periodo 8, o corrido al 12 si se atrasa—. Sumamos el valor vivo de cada periodo (el área bajo la curva) y comparamos:

SLICES = 8       # el monolito de Mercado tiene 8 rebanadas modernizables
HORIZON = 12     # periodos que observamos


def live_value(strategy, t):
    # "valor moderno vivo" en el periodo t: rebanadas ya modernizadas y sirviendo.
    if strategy == "incremental":
        return min(t, SLICES)                 # una rebanada nueva cada periodo
    if strategy == "rewrite_ok":
        return SLICES if t >= 8 else 0        # todo junto en el corte (optimista)
    if strategy == "rewrite_slip":
        return SLICES if t >= 12 else 0       # el corte se corre al final


strategies = ["incremental", "rewrite_ok", "rewrite_slip"]

print(f"{'periodo':>8}{'incremental':>13}{'rewrite_ok':>12}{'rewrite_slip':>14}")
print("-" * 47)
totals = {s: 0 for s in strategies}
for t in range(1, HORIZON + 1):
    row = {s: live_value(s, t) for s in strategies}
    for s in strategies:
        totals[s] += row[s]
    print(f"{t:>8}{row['incremental']:>13}{row['rewrite_ok']:>12}"
          f"{row['rewrite_slip']:>14}")
print("-" * 47)
print(f"{'TOTAL':>8}{totals['incremental']:>13}{totals['rewrite_ok']:>12}"
      f"{totals['rewrite_slip']:>14}")

print(f"\n  Valor-periodos acumulados (area bajo la curva) en {HORIZON} periodos:")
print(f"    incremental : {totals['incremental']:>3}")
print(f"    rewrite_ok  : {totals['rewrite_ok']:>3}  "
      f"({totals['incremental'] / totals['rewrite_ok']:.1f}x menos que incremental)")
print(f"    rewrite_slip: {totals['rewrite_slip']:>3}  "
      f"({totals['incremental'] / totals['rewrite_slip']:.1f}x menos)")

# Riesgo "en juego": el cambio mas grande no validado que se despliega de una vez.
print("\n  Riesgo en juego por despliegue (rebanadas que cambian de golpe):")
print(f"    incremental : 1 rebanada  -> si falla, se revierte 1/{SLICES} del sistema")
print(f"    big rewrite : {SLICES} rebanadas -> si falla, cae el sistema entero")

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

 periodo  incremental  rewrite_ok  rewrite_slip
-----------------------------------------------
       1            1           0             0
       2            2           0             0
       3            3           0             0
       4            4           0             0
       5            5           0             0
       6            6           0             0
       7            7           0             0
       8            8           8             0
       9            8           8             0
      10            8           8             0
      11            8           8             0
      12            8           8             8
-----------------------------------------------
   TOTAL           68          40             8

  Valor-periodos acumulados (area bajo la curva) en 12 periodos:
    incremental :  68
    rewrite_ok  :  40  (1.7x menos que incremental)
    rewrite_slip:   8  (8.5x menos)

  Riesgo en juego por despliegue (rebanadas que cambian de golpe):
    incremental : 1 rebanada  -> si falla, se revierte 1/8 del sistema
    big rewrite : 8 rebanadas -> si falla, cae el sistema entero

Lee las columnas como tres formas de gastar el mismo tiempo.

La columna incremental empieza a dar valor desde el periodo 1: 1, 2, 3, 4... cada periodo hay una rebanada más viva y sirviendo. Para el periodo 8 el sistema está completamente modernizado (valor 8), y de ahí en adelante mantiene 8. La suma de toda la columna —el área bajo la curva— es 68 valor-periodos. Eso es el "vivir en la casa desde la primera semana": cada rebanada acumuló valor durante todos los periodos que estuvo viva.

La columna rewrite_ok es el escenario optimista del big rewrite: entrega las 8 rebanadas de golpe en el periodo 8 (justo cuando planeaba) y mantiene 8 hasta el final. Su área es 40 valor-periodos: 8 rebanadas × 5 periodos vivas (del 8 al 12). Fíjate que la cifra final —el sistema modernizado— es idéntica a la del incremental: ambos terminan con 8 rebanadas modernizadas. Pero el incremental acumuló 68 y el rewrite solo 40, una diferencia de 1.7x, y esa diferencia es puro tiempo de valor perdido: los siete periodos en que el rewrite entregó 0 mientras el incremental ya estaba dando 1, 2, 3... El rewrite no entrega menos al final; entrega lo mismo, pero más tarde, y llegar tarde cuesta.

La columna rewrite_slip es el escenario realista —el que las lecciones 2 y 3 hicieron inevitable—: el corte se atrasa al periodo 12. Su área es apenas 8 valor-periodos: entregó todo en el último periodo y no le quedó tiempo de acumular nada. Contra el incremental, eso es 8.5x menos valor. El mismo sistema modernizado, pero tan tarde que casi todo el tiempo de valor se perdió. Y recuerda que las lecciones 2 y 3 mostraron que el corte suele atrasarse más allá de la ventana —en cuyo caso el área sería 0, y el factor, infinito—.

Ahora el segundo bloque, el del riesgo en juego. Aquí la asimetría es todavía más brutal. En el incremental, cada despliegue cambia una rebanada, así que lo que puede fallar de golpe es 1/8 del sistema: si la rebanada sale mal, reviertes esa pieza y el otro 7/8 sigue intacto. En el big rewrite, el corte cambia las 8 rebanadas de una vez, así que el riesgo en juego en ese único momento es el sistema entero: si el corte falla, no cae una pieza, cae todo. El incremental no solo entrega antes: entrega con red, porque nunca pone más de una rebanada en riesgo a la vez. El rewrite apuesta el sistema completo en una sola tirada.

Junta las dos mediciones y tienes el caso a favor de lo incremental en su forma más clara: más valor acumulado (1.7x a 8.5x, según cuánto se atrase el corte) y menos riesgo por paso (1/8 vs 8/8). No es que el incremental sea "más bonito" o "más de moda": es que domina al rewrite en las dos dimensiones que importan, el valor y el riesgo, a la vez.

Profundización: por qué el valor temprano vale más (y por qué el riesgo acotado se compone)

El resultado de los valor-periodos captura una idea que en finanzas se llama el valor del dinero en el tiempo, y en producto se llama time to value: un beneficio que recibes hoy vale más que el mismo beneficio recibido dentro de dos años, porque durante esos dos años el beneficio de hoy estuvo trabajando —reduciendo costos, reteniendo clientes, habilitando otras cosas—. Cuando el incremental moderniza el catálogo en el periodo 1, ese catálogo modernizado no solo "está listo antes": está ahorrando costos de mantenimiento y habilitando mejoras durante los 11 periodos siguientes. El rewrite, al concentrar todo el valor al final, renuncia a ese trabajo compuesto. Los 68 contra 40 no son una diferencia de calidad del resultado —el resultado final es el mismo—; son una diferencia de cuándo empezó a rendir.

El resultado del riesgo captura algo complementario y quizá más importante para un sistema que no puede caerse. Un despliegue que cambia 1/8 del sistema tiene dos propiedades que uno que cambia 8/8 no tiene: es reversible barato (si falla, revertir una rebanada es rápido, contra revertir un sistema entero que a veces es imposible porque ya migraste los datos) y es diagnosticable (si algo se rompe justo después de desplegar una rebanada, sabes casi con certeza que fue esa rebanada; si algo se rompe después de cambiar el sistema entero, la causa está en cualquiera de mil lugares). El riesgo acotado no solo baja la probabilidad de un desastre: baja el costo de cada problema, porque lo hace pequeño, reversible y fácil de rastrear. Y como cada rebanada te enseña algo antes de la siguiente, el riesgo del incremental incluso baja con el tiempo —para la rebanada 8 ya dominas la mecánica—, mientras que el del rewrite se acumula callado hasta explotar en el corte.

                       Valor acumulado          Riesgo en juego
                       (mas es mejor)           (menos es mejor)
  incremental          ████████████████ 68      █ 1/8  (reversible, diagnosticable)
  rewrite (a tiempo)   █████████ 40             ████████ 8/8 (todo o nada)
  rewrite (atrasado)   ██ 8                     ████████ 8/8 (todo o nada)

Hay una objeción honesta que vale la pena responder: "el incremental tiene un sobrecosto —el facade, la coexistencia de viejo y nuevo, la migración de datos por partes— que el rewrite no paga". Es cierto: modernizar por rebanadas exige montar andamiaje (el router del módulo 3, el anti-corruption layer del módulo 5, el dual-write del módulo 6). Ese andamiaje cuesta. Pero el ejemplo muestra por qué se paga solo: la diferencia de valor-periodos (28 a 60 unidades, según el atraso) y la reducción del riesgo de un desastre total compran ese andamiaje con holgura. El sobrecosto del incremental es un seguro con prima pequeña; el "ahorro" del rewrite es no comprar seguro justo en la operación más riesgosa que harás.

Errores comunes

Comparar solo el estado final, ignorando el camino. Qué pasa: alguien dice "al final los dos terminan con el sistema modernizado, así que dan lo mismo", y elige el rewrite porque "no tiene el sobrecosto del andamiaje". Por qué pasa: el estado final es fácil de imaginar; el valor acumulado durante el camino es invisible si no lo mides. Cómo detectarlo: si la comparación entre rewrite e incremental solo menciona el resultado ("un sistema moderno") y no el tiempo de valor ni el riesgo por paso, le falta el 90% del análisis. Cómo corregirlo: mide el área bajo la curva, no el punto final. El ejemplo lo hace explícito: mismo final (8 rebanadas), pero 68 vs 40 vs 8 valor-periodos según cuándo llegó cada uno. El camino es la diferencia, porque el negocio vive en el camino, no en el punto final.

Subestimar el costo de un despliegue "todo o nada". Qué pasa: el plan del rewrite trata el corte como un evento técnico más —"desplegamos y listo"— sin dimensionar que ese corte pone el sistema entero en riesgo simultáneo. Por qué pasa: el corte se ve como el final feliz, no como el momento más peligroso del proyecto. Cómo detectarlo: pregunta "si el corte falla, ¿cuánto del sistema cae, y cuánto cuesta revertir?". Si la respuesta es "todo" y "no estamos seguros de poder revertir" (porque ya se migraron los datos), el riesgo en juego es máximo. Cómo corregirlo: reconoce que el radio de impacto de un despliegue es una variable de diseño, no un dato fijo. El incremental la mantiene en 1/8 por construcción; el rewrite la lleva a 8/8. Un sistema crítico como Mercado no puede permitirse un despliegue que arriesgue el 100% de una vez —la lección 6 muestra cómo el strangler mantiene ese radio pequeño con el sistema siempre vivo—.

Descartar el incremental por su andamiaje sin medir lo que compra. Qué pasa: el equipo ve el costo del facade, la coexistencia y la migración por partes, y concluye que "es más trabajo que reescribir de una vez". Por qué pasa: el andamiaje es un costo visible y concreto; el valor que compra (tiempo de valor + riesgo acotado) es difuso y hay que calcularlo. Cómo detectarlo: si el argumento contra el incremental es "es más complejo / más piezas" sin poner enfrente los valor-periodos ganados ni el riesgo evitado, la cuenta está a medias. Cómo corregirlo: trata el andamiaje como lo que es —una prima de seguro— y compárala contra lo que evita: la ventana de silencio, el blanco móvil, las regresiones del conocimiento tácito, y el despliegue todo-o-nada. En un sistema vivo y crítico, esa prima casi siempre es un buen negocio; la lección 7 da el criterio de cuándo no lo es (sistemas chicos, sin usuarios, donde el andamiaje cuesta más de lo que protege).

Ejercicios

Ejercicio 1 — Calcula los valor-periodos. Un sistema tiene 4 rebanadas y un horizonte de 6 periodos. El incremental moderniza una rebanada por periodo (valor vivo = min(t, 4)). Un rewrite entrega las 4 de golpe en el periodo 4. Calcula los valor-periodos acumulados de cada uno y el factor de ventaja del incremental. Luego di qué pasa con el factor si el rewrite se atrasa al periodo 6.

Ver solución

Incremental (valor vivo = min(t, 4) por periodo, t de 1 a 6): 1 + 2 + 3 + 4 + 4 + 4 = 18 valor-periodos.

Rewrite en el periodo 4 (valor 0 en t=1,2,3; valor 4 en t=4,5,6): 0 + 0 + 0 + 4 + 4 + 4 = 12 valor-periodos. Factor de ventaja del incremental: 18 / 12 = 1.5x.

Rewrite atrasado al periodo 6 (valor 0 en t=1..5; valor 4 en t=6): solo 4 valor-periodos. Factor: 18 / 4 = 4.5x.

La lección: el estado final es idéntico en los tres casos (4 rebanadas modernizadas), pero el valor acumulado va de 18 a 12 a 4 según cuándo llegó. Y el factor de ventaja del incremental crece cuanto más se atrasa el rewrite —de 1.5x a 4.5x—, que es justo lo que las lecciones 2 y 3 predicen que va a pasar en un sistema vivo: los cortes se atrasan, y cada atraso agranda la ventaja del incremental.

Ejercicio 2 — El riesgo del corte. Mercado va a modernizar su sistema de pagos. El equipo A propone un big rewrite con un corte único: apagar el sistema viejo un sábado a medianoche y encender el nuevo. El equipo B propone desviar el 5% del tráfico de pagos al sistema nuevo, medir, y subir el porcentaje solo si todo va bien. Compara el "riesgo en juego" de cada propuesta y explica cuál preferirías para un sistema que maneja dinero.

Ver solución

Equipo A (corte único): el riesgo en juego es el 100% de los pagos, concentrado en un solo momento. Si el sistema nuevo tiene un bug —y las lecciones 3 y 4 mostraron que un rewrite casi siempre tiene reglas ocultas mal reimplementadas—, ese bug golpea a todos los clientes que intenten pagar el sábado a medianoche y hasta que se detecte y revierta. Y revertir puede ser durísimo: si en esas horas ya se procesaron pagos reales por el sistema nuevo (con datos migrados), volver al viejo implica reconciliar transacciones de dinero, no solo "apagar y encender". Es el escenario todo-o-nada en la operación más sensible posible: la que mueve dinero.

Equipo B (5% incremental): el riesgo en juego es el 5% de los pagos. Si el sistema nuevo falla, afecta a 1 de cada 20 clientes como máximo, se detecta rápido (el volumen pequeño y controlado hace fácil comparar contra el viejo), y se revierte devolviendo ese 5% al sistema viejo, que sigue vivo y manejando el otro 95%. Además, cada incremento (5% → 10% → 25%...) enseña algo antes del siguiente, así que el riesgo baja conforme sube la confianza.

Preferencia: para un sistema que maneja dinero, el equipo B, sin duda. La razón es exactamente la métrica de esta lección: el riesgo en juego. Un pago mal procesado no es un pixel torcido; es dinero real, disputas, y confianza rota. Poner el 100% de los pagos en riesgo en un solo corte es la peor jugada posible en el módulo más crítico. El incremental mantiene el radio de impacto en 5%, con el viejo como red, y esa es precisamente la mecánica del strangler fig que la lección 6 y el módulo 3 desarrollan. (La decisión formal de cuándo asumir cada riesgo, con su registro, es la guía de decisiones; aquí solo comparamos el riesgo en juego.)

Ejercicio 3 — Responde la objeción del andamiaje. Un compañero dice: "el incremental suena bien, pero montar el router, mantener el viejo y el nuevo a la vez, y migrar los datos por partes es un montón de trabajo extra que el rewrite no tiene. ¿No es más simple reescribir de una vez?". Responde usando las dos métricas de la lección y reconociendo lo cierto de su objeción.

Ver solución

Lo cierto de su objeción: sí, el incremental tiene un sobrecosto real. Montar el router (módulo 3), sostener el viejo y el nuevo coexistiendo, y migrar los datos por rebanadas (módulo 6) es andamiaje que el rewrite no paga. No hay que negarlo: el incremental es, paso a paso, más piezas móviles.

Por qué se paga solo, con las dos métricas:

  1. Valor-periodos. El ejemplo mostró que el incremental acumula 68 valor-periodos contra 40 (rewrite a tiempo) u 8 (rewrite atrasado). Esa diferencia —28 a 60 unidades de valor entregado antes— es beneficio real que fluye al negocio mientras el rewrite todavía no entrega nada. Ese valor temprano paga el andamiaje con holgura: el router cuesta, pero el catálogo modernizado que ya está en producción en el periodo 1 rinde durante 11 periodos.
  2. Riesgo en juego. El rewrite "más simple" pone el 100% del sistema en riesgo en el corte; el incremental, 1/8 por paso. El andamiaje del incremental (el viejo como fallback, el desvío gradual) es justo lo que compra esa reducción de riesgo. En un sistema crítico como Mercado, evitar un despliegue todo-o-nada no es un lujo: es la diferencia entre un problema acotado y un desastre.

La reformulación: el andamiaje del incremental no es "trabajo extra desperdiciado"; es una prima de seguro con prima pequeña. El "ahorro" del rewrite es no comprar seguro justo en la operación más riesgosa. La pregunta correcta no es "¿cuál tiene menos piezas?", sino "¿cuál entrega más valor con menos riesgo?", y en las dos, el incremental gana. (La única excepción —cuando el andamiaje cuesta más de lo que protege— es la región estrecha de la lección 7: sistemas chicos, sin usuarios, donde reescribir de una vez sí es lo simple y correcto. Mercado no es ese caso.)

Resumen y siguiente paso

En esta lección giraste el argumento del módulo: de derribar el rewrite a construir el caso a favor de lo incremental. Viste, con las dos formas de pagar una casa, que el mismo resultado entregado temprano vale mucho más que entregado al final, porque el "ahora" acumulado durante la espera es tiempo de valor que el rewrite pierde. Y lo mediste en dos dimensiones: el incremental acumula 68 valor-periodos contra 40 u 8 del rewrite (1.7x a 8.5x más valor, según cuánto se atrase el corte) y arriesga 1/8 del sistema por paso contra el 8/8 del corte único. El incremental domina al rewrite en las dos cosas que importan —valor y riesgo— a la vez, y su andamiaje es una prima de seguro que esas ventajas pagan con holgura.

Antes de avanzar deberías poder: explicar por qué el valor temprano vale más que el valor tardío; calcular los valor-periodos de una migración y el factor de ventaja del incremental; argumentar por qué un despliegue todo-o-nada es el momento más riesgoso de un proyecto; y responder la objeción del andamiaje con las dos métricas.

La lección 6 le pone nombre e imagen a esta alternativa que acabas de justificar con números. Es la metáfora que da título a toda la técnica de esta guía: la higuera estranguladora, el árbol que crece envolviendo a otro y lo reemplaza célula por célula sin talarlo —el sistema siempre vivo, el viejo como fallback—. Vas a ver por qué ese reemplazo gradual evita el apagón del corte big-bang, y a medir el impacto de un incidente en ambos caminos. (La metáfora y el porqué aquí; la mecánica del router, en el módulo 3.)

Recursos

  • Sam Newman, Monolith to Microservices (O'Reilly, 2019), cap. 3 "Splitting the Monolith" — el desarrollo completo de por qué la migración incremental entrega valor y controla el riesgo, con las técnicas que los módulos 3 al 6 detallan. La referencia central de esta lección. En inglés.
  • Martin Fowler, "StranglerFigApplication" (2004) — martinfowler.com/bliki/StranglerFigApplication.html. El reemplazo incremental como forma de entregar valor y reducir riesgo en cada paso. La metáfora de la lección 6. En inglés.
  • Don Reinertsen, The Principles of Product Development Flow (Celeritas, 2009) — el tratamiento riguroso del "costo del retraso" (cost of delay) y por qué el valor temprano vale más: la base económica de los valor-periodos de esta lección. En inglés.
  • Jez Humble y David Farley, Continuous Delivery (Addison-Wesley, 2010) — por qué los despliegues pequeños y frecuentes reducen el riesgo comparados con los grandes e infrecuentes; el fundamento del "riesgo en juego" acotado. En inglés.