Módulo 1: Por qué no reescribir
Modernizar en su lugar vs empezar de cero
Descripción
Este módulo ha construido un caso fuerte contra la reescritura y a favor de lo incremental. Pero hay un riesgo en un mensaje tan contundente: convertirlo en dogma. "Nunca reescribas" es tan falso como "reescribe siempre" —y un buen ingeniero no cambia una regla simplista por otra—. Esta lección consolida la tesis del módulo con honestidad: reescribir no es siempre malo. Hay una región, estrecha pero real, donde empezar de cero es la opción correcta, y saber reconocerla es tan importante como saber evitar el rewrite cuando no toca. La diferencia entre un ingeniero con criterio y uno con eslogan es justamente esa: el del eslogan aplica la misma respuesta a todo; el del criterio sabe cuándo aplica cada una.
La pregunta operativa, entonces, no es "¿reescribir o modernizar?" en abstracto, sino "¿qué tiene este sistema que hace que reescribirlo sea seguro o suicida?". Y esa pregunta se puede responder con criterios medibles. Un sistema es candidato seguro a reescritura cuando es chico (poco que reimplementar), sin usuarios en producción (nadie sufre si el corte falla), bien entendido (poco conocimiento tácito enterrado), poco crítico para el negocio (un fallo no cuesta caro) y —clave— bien probado (una red de tests que atrapa las regresiones). Cuando un sistema cumple esas condiciones, los cuatro modos de falla de las lecciones anteriores se desactivan, y reescribir de una vez puede ser incluso lo más simple. Cuando no las cumple —y Mercado no cumple ninguna—, reescribir es la trampa que todo el módulo describió. Esta lección puntúa varios sistemas en esos cinco ejes y ubica a cada uno en el mapa, para que la decisión deje de ser ideológica y sea una medición.
Conexión con el módulo. Es la lección de consolidación: recoge los cuatro modos de falla (lecciones 2-4) y el caso a favor de lo incremental (lección 5) y los convierte en un criterio único y medible —el rewrite_score— que dice cuándo cada camino es el correcto. El eje de la cobertura de tests conecta directo con el módulo 2: la red de seguridad que hace más seguro cualquier cambio (rewrite o modernización) es justo lo que el módulo 2 construye para Mercado con characterization tests. Con esta lección cierras el "por qué"; el mini-proyecto (lección 8) aplica todo el criterio a Mercado, y los módulos 2 en adelante enseñan el "cómo".
Una analogía: reparar el coche viejo vs comprar uno nuevo
Tu coche tiene quince años y algo falla. ¿Lo reparas o compras uno nuevo? La respuesta correcta no es una regla fija ("siempre repara" o "siempre cambia"): depende del coche y de tu situación, y la das evaluando unos pocos factores. Si es un clásico bien cuidado, con historial de servicio completo, del que conoces cada detalle, y la falla es acotada —una pieza que cambiar—, reparar es sensato: sabes lo que tienes. Pero si es un coche del que ignoras el historial, con problemas en cascada, que usas todos los días para trabajar y del que dependes para comer, y encima no tienes forma de saber qué más está a punto de fallar, la cosa cambia: cada reparación destapa otra, y no puedes quedarte sin coche mientras lo arreglas.
Fíjate en que la decisión depende de factores concretos: qué tan bien conoces el coche (¿historial completo o una caja negra?), qué tan crítico es para tu vida (¿un segundo coche o tu única forma de trabajar?), qué tan grande es el problema (¿una pieza o el motor entero?), y si puedes probar el resultado antes de confiar en él. Reescribir software es idéntico. Un script de fin de semana que solo tú usas es el coche clásico que conoces al detalle: reescribirlo es de bajo riesgo. El monolito de Mercado es el coche del que dependes para comer, con historial desconocido y fallas en cascada: aquí no demueles, reparas en su lugar, con cuidado y con red. Esta lección convierte esos "factores concretos" en cinco ejes que puedes puntuar, para que la decisión no dependa de la corazonada sino de la evidencia.
Ejemplo trabajado: el rewrite_score de varios sistemas
Vamos a puntuar cinco sistemas en cinco ejes de 1 a 5. Cuatro ejes suben el peligro de reescribir (tamaño, usuarios en producción, conocimiento tácito, criticidad); el quinto, la cobertura de tests, es la red de seguridad que lo baja. El rewrite_score resta el peligro de la red: alto y positivo cuando reescribir es seguro, muy negativo cuando es suicida:
# Ejes (1-5). Los primeros cuatro suben el PELIGRO de reescribir; el ultimo
# (cobertura de tests) es la RED de seguridad que lo baja.
SYSTEMS = [
# (nombre, size, users_in_prod, tacit_knowledge, criticality, test_coverage)
("throwaway_prototype", 1, 1, 1, 1, 3),
("internal_admin_tool", 2, 2, 2, 2, 4),
("greenfield_service", 3, 1, 1, 2, 3), # aun no esta en produccion
("well_tested_module", 4, 4, 3, 4, 5), # grande pero CON red de seguridad
("mercado_monolith", 5, 5, 5, 5, 1), # el caso de esta guia
]
THRESHOLD = 3 # rewrite_score >= 3 => reescribir es viable
def rewrite_score(size, users, tacit, criticality, coverage):
danger = size + users + tacit + criticality # 4..20 (mas = mas peligroso)
safety_net = coverage * 4 # 4..20 (mas = mas seguro)
return safety_net - danger
ranked = sorted(SYSTEMS, key=lambda s: rewrite_score(*s[1:]), reverse=True)
print(f"{'sistema':<22}{'peligro':>8}{'red':>5}{'score':>7} veredicto")
print("-" * 62)
for name, size, users, tacit, crit, cov in ranked:
danger = size + users + tacit + crit
score = rewrite_score(size, users, tacit, crit, cov)
verdict = "reescribir viable" if score >= THRESHOLD else "MODERNIZAR EN SU LUGAR"
print(f"{name:<22}{danger:>8}{cov * 4:>5}{score:>7} {verdict}")
print("-" * 62)
mercado = next(s for s in SYSTEMS if s[0] == "mercado_monolith")
print(f"\n Mercado puntua {rewrite_score(*mercado[1:])}: el peor de la lista, "
f"en la esquina opuesta")
print(f" a donde reescribir es seguro. Grande, en produccion, lleno de")
print(f" conocimiento tacito, critico para el negocio y SIN tests.")
print(f"\n Nota el 'well_tested_module': grande y critico, pero su cobertura 5")
print(f" (red de seguridad) lo vuelve viable. Esa red es justo lo que el")
print(f" Modulo 2 construye para Mercado antes de tocar una sola linea.")
Qué esperar. Al correr el archivo, la salida es exactamente esta:
sistema peligro red score veredicto
--------------------------------------------------------------
throwaway_prototype 4 12 8 reescribir viable
internal_admin_tool 8 16 8 reescribir viable
greenfield_service 7 12 5 reescribir viable
well_tested_module 15 20 5 reescribir viable
mercado_monolith 20 4 -16 MODERNIZAR EN SU LUGAR
--------------------------------------------------------------
Mercado puntua -16: el peor de la lista, en la esquina opuesta
a donde reescribir es seguro. Grande, en produccion, lleno de
conocimiento tacito, critico para el negocio y SIN tests.
Nota el 'well_tested_module': grande y critico, pero su cobertura 5
(red de seguridad) lo vuelve viable. Esa red es justo lo que el
Modulo 2 construye para Mercado antes de tocar una sola linea.
Lee la tabla de arriba hacia abajo, del más seguro al más suicida.
Arriba están los candidatos seguros a reescritura. El throwaway_prototype puntúa 8: peligro mínimo (4, todo en 1) y una red modesta (12). Es el prototipo del fin de semana —chico, sin usuarios, que acabas de escribir (nada de conocimiento tácito, está fresco en tu cabeza), sin criticidad—. Reescribirlo para "hacerlo bien" antes de que tenga usuarios es perfectamente razonable. El internal_admin_tool también da 8: un poco más grande y con algunos usuarios, pero con buena cobertura (red 16) que compensa. El greenfield_service da 5: aún no está en producción, así que aunque sea mediano, no hay nadie sufriendo si el corte falla —de hecho no hay "corte", porque no hay nada vivo que reemplazar—.
El cuarto caso es el más instructivo. El well_tested_module tiene un peligro alto —15, casi tanto como Mercado: es grande (4), con usuarios (4), algo de conocimiento tácito (3) y crítico (4)—. Y sin embargo su veredicto es "reescribir viable", con score 5. ¿Por qué? Por la columna red: cobertura de tests 5, que da una red de 20, la máxima. La red de seguridad sola levantó un sistema peligroso hasta la zona viable. Este caso es la lección dentro de la lección: lo que hace segura o suicida una reescritura no es solo el tamaño o la criticidad; es, sobre todo, si tienes una red que atrape las regresiones. Un sistema grande y crítico pero bien probado puede reescribirse con relativa seguridad, porque los tests gritan cuando rompes algo (incluidas las reglas tácitas de la lección 4).
Y hasta abajo, solo, está mercado_monolith con un score de -16 —no un poco peor que el resto, sino en otra categoría—. Peligro máximo (20: grande, con muchos usuarios, lleno de conocimiento tácito, crítico para el negocio) y red mínima (4: cobertura 1, casi sin tests). Es la combinación exacta de todo lo que este módulo describió como trampa: los cuatro modos de falla activados a la vez y sin ninguna red que los atrape. Mercado no está "cerca del límite"; está en la esquina opuesta a donde reescribir es seguro. Para Mercado, el veredicto medido es inequívoco: modernizar en su lugar.
Profundización: la cobertura de tests es la palanca que puedes mover
De los cinco ejes, cuatro son en buena medida dados: el tamaño del sistema, cuántos usuarios tiene en producción, cuánto conocimiento tácito acumuló y qué tan crítico es para el negocio no los cambias fácilmente —son propiedades de lo que el sistema es hoy—. Pero el quinto, la cobertura de tests, sí lo puedes mover, y el ejemplo mostró cuánto pesa: fue lo único que separó al well_tested_module (viable) de Mercado (suicida), a pesar de que su peligro es casi el mismo. Esa es la observación más útil de la lección para la práctica.
Piénsalo así: Mercado puntúa -16 hoy, con cobertura 1. ¿Qué pasaría si, sin cambiar nada más, llevaras su cobertura de 1 a 5? El peligro sigue en 20, pero la red sube de 4 a 20, y el score pasa de -16 a 0 —todavía no "viable" (sigue por debajo del umbral de 3), pero ya no en territorio de desastre—. La red de seguridad no vuelve a Mercado un buen candidato a reescritura (sigue siendo enorme, crítico y lleno de conocimiento tácito), pero sí vuelve cualquier cambio sobre Mercado —incluida una modernización incremental— muchísimo más seguro. Ese es exactamente el trabajo del módulo 2: no para habilitar un rewrite, sino porque antes de tocar el legacy con cualquier estrategia, hay que tender la red.
Aquí es donde las piezas del módulo encajan. El conocimiento tácito de la lección 4 —las cinco reglas ocultas que un rewrite a ciegas rompía— es justo lo que una red de tests captura y protege. Los characterization tests del módulo 2 son la herramienta concreta: fijan el comportamiento actual del legacy (rarezas incluidas) para que cualquier cambio que lo altere salte al instante. Con esa red tendida, modernizar Mercado por rebanadas (el strangler de la lección 6) deja de ser "cambiar a ciegas un sistema sin tests" y se vuelve "cambiar con red un sistema caracterizado". La secuencia del resto de la guía no es arbitraria: primero se tiende la red (M2), después se estrangula (M3+), precisamente porque la cobertura es la palanca que baja el riesgo de todo lo demás.
flowchart TD
Q{"¿Cómo puntúa el sistema<br/>en los 5 ejes?"}
Q -->|"score alto: chico, sin usuarios,<br/>entendido, no crítico, probado"| REW["Reescribir de cero<br/>puede ser lo correcto<br/>(la región estrecha)"]
Q -->|"score bajo: grande, en prod,<br/>tácito, crítico, sin tests"| MOD["Modernizar en su lugar<br/>(Mercado está aquí)"]
MOD --> NET["Primero: tender la red<br/>(characterization tests, M2)"]
NET --> STR["Después: estrangular<br/>por rebanadas (M3+)"]
Errores comunes
Convertir "no reescribas" en dogma. Qué pasa: alguien absorbe el mensaje del módulo y lo aplica como regla universal —"reescribir siempre está mal"— y bloquea una reescritura que en su caso era la opción correcta (un prototipo, un script chico, un servicio sin usuarios). Por qué pasa: los eslóganes son cómodos y ahorran pensar. Cómo detectarlo: si rechazas una reescritura sin haber puntuado el sistema en los cinco ejes, estás aplicando dogma, no criterio. Cómo corregirlo: la respuesta correcta depende del sistema, y se mide. Puntúa los cinco ejes; si el sistema es chico, sin usuarios, entendido, poco crítico y (idealmente) probado, reescribir puede ser lo más simple y sensato. El módulo no dice "nunca reescribas"; dice "reescribir un sistema como Mercado —grande, vivo, crítico, tácito, sin tests— casi siempre fracasa". La condición importa tanto como la conclusión.
Ignorar la cobertura de tests al decidir. Qué pasa: la decisión de reescribir o modernizar se toma mirando solo el tamaño y la criticidad ("es grande e importante, no lo toquemos" o "es chico, reescribámoslo"), sin considerar si hay red de tests. Por qué pasa: el tamaño y la criticidad son visibles; la cobertura es un dato que hay que ir a buscar. Cómo detectarlo: si en la discusión de rewrite-vs-modernizar nadie menciona "¿qué tan bien probado está?", falta el eje que más pesa. Cómo corregirlo: la cobertura de tests puede voltear el veredicto —el well_tested_module del ejemplo era casi tan peligroso como Mercado y salió viable solo por su red—. Y como es el único eje que puedes mover, es también tu principal palanca: antes de decidir la estrategia, pregunta si tender una red cambia la ecuación. Para Mercado, tenderla no habilita un rewrite, pero sí es el requisito previo de cualquier modernización segura (módulo 2).
Puntuar el sistema con optimismo en vez de con honestidad. Qué pasa: al evaluar los ejes, el equipo subestima el conocimiento tácito ("no, si el sistema es bastante directo") o sobreestima la cobertura ("tenemos varios tests"), y el score sale artificialmente favorable a reescribir. Por qué pasa: reescribir es tentador, y es fácil ajustar la evaluación para justificar lo que ya quieres hacer. Cómo detectarlo: si el eje de conocimiento tácito está bajo pero nadie puede explicar qué hacen ciertas partes del código, o si la cobertura está alta pero los tests no comparan contra el comportamiento real (solo contra la doc), la puntuación es optimista. Cómo corregirlo: puntúa con evidencia, no con deseo. El conocimiento tácito se mide reproduciendo el comportamiento real (como en la lección 4) y viendo cuántas reglas ocultas aparecen; la cobertura se mide por si los tests atraparían una regresión real, no por cuántos hay. Un score honesto para Mercado da -16; uno optimista podría maquillarlo, y ese maquillaje es justo lo que lleva a la reescritura desastrosa que el módulo entero previene.
Ejercicios
Ejercicio 1 — Puntúa un sistema. Una startup tiene un servicio de recomendaciones que escribió un solo ingeniero hace seis meses, todavía en beta con 50 usuarios de prueba, con lógica que el ingeniero entiende bien y documentó, y con una suite de tests decente. El servicio no es crítico (si falla, la app funciona igual, solo sin recomendaciones). Puntúa los cinco ejes (justifica cada uno), calcula el rewrite_score con la fórmula del ejemplo, y da el veredicto.
Ver solución
Una puntuación razonable:
- size = 2: un solo servicio de recomendaciones, escrito por una persona en seis meses; es mediano-chico, no un monolito.
- users_in_prod = 2: 50 usuarios de prueba en beta; hay algunos usuarios, pero pocos y advertidos de que es beta, así que el impacto de un fallo es bajo.
- tacit_knowledge = 2: el ingeniero que lo escribió lo entiende bien y lo documentó, y es reciente (seis meses); poco conocimiento enterrado, aunque nunca es cero.
- criticality = 1: no es crítico —si falla, la app funciona igual, solo sin recomendaciones—. Un fallo no cuesta caro.
- test_coverage = 4: tiene una suite de tests decente; buena red de seguridad, aunque no perfecta.
danger = 2 + 2 + 2 + 1 = 7. safety_net = 4 × 4 = 16. rewrite_score = 16 - 7 = 9. Como 9 ≥ 3, el veredicto es reescribir viable.
Interpretación: este servicio está claramente en la región estrecha donde reescribir es una opción legítima. Es chico, poco crítico, bien entendido, bien probado y con pocos usuarios que además saben que es beta. Ninguno de los cuatro modos de falla del módulo tiene fuerza aquí: el negocio no depende de él (puede "detenerse"), el conocimiento tácito es mínimo, y la red de tests atrapa regresiones. Es el opuesto exacto de Mercado. La conclusión del módulo (no reescribas) no aplica a este sistema, y aplicarla por dogma sería un error —justo el primer error común de la lección—.
Ejercicio 2 — La palanca de la cobertura. Toma el mercado_monolith del ejemplo (peligro 20, cobertura 1, score -16). Sin cambiar ninguno de los otros cuatro ejes, calcula qué score tendría con cobertura 3 y con cobertura 5. ¿Alguna cobertura lo vuelve "reescribir viable" (score ≥ 3)? ¿Qué te dice eso sobre para qué sirve tender la red en Mercado?
Ver solución
El peligro de Mercado es fijo en 20 (grande + muchos usuarios + tácito + crítico, todos en 5). Solo movemos la cobertura:
- Cobertura 1 (actual): red = 4, score = 4 - 20 = -16. Suicida.
- Cobertura 3: red = 12, score = 12 - 20 = -8. Sigue muy negativo.
- Cobertura 5: red = 20, score = 20 - 20 = 0. Ya no es un desastre, pero sigue por debajo del umbral de 3.
Ninguna cobertura vuelve a Mercado "reescribir viable": ni siquiera con la red máxima (cobertura 5) el score llega a 3, porque su peligro de 20 es demasiado alto. Un sistema enorme, con muchísimos usuarios, lleno de conocimiento tácito y crítico para el negocio no se vuelve un buen candidato a reescritura solo por tener tests —sigue siendo enorme, vivo y crítico—.
Qué dice eso sobre tender la red en Mercado: la red no sirve para habilitar un rewrite (no lo habilita). Sirve para algo distinto y más importante: bajar el riesgo de cualquier cambio sobre Mercado, incluida la modernización incremental. Pasar de -16 a 0 no convierte el rewrite en buena idea, pero sí convierte "tocar Mercado a ciegas" en "tocar Mercado con red". Por eso el módulo 2 va antes que el módulo 3: la red no es opcional ni es un paso hacia el rewrite; es el requisito previo de modernizar con seguridad. La cobertura es la única palanca que puedes mover, y moverla es lo primero que se hace —no para reescribir, sino para poder modernizar sin volar en pedazos—.
Ejercicio 3 — Defiende el matiz. Un colega, tras leer el módulo, declara en una reunión: "aprendí que reescribir siempre es un error, así que voto en contra de cualquier reescritura, punto". Corrige su conclusión sin darle la razón al extremo opuesto ("reescribe cuando quieras"). ¿Cuál es la formulación con criterio?
Ver solución
La conclusión del colega es dogma, y el dogma —aunque apunte en la dirección correcta— falla en los casos de la región estrecha. Corregirla sin caer en el extremo opuesto:
Lo que el colega tiene bien: la intuición de desconfiar de las reescrituras es sana, porque la mayoría de los sistemas que la gente quiere reescribir son sistemas vivos, grandes y críticos —como Mercado—, y para esos el rewrite casi siempre fracasa por los cuatro modos de falla del módulo. En el caso típico, su voto en contra sería el correcto.
Dónde falla: "siempre es un error" es falso. El módulo no demostró que reescribir sea malo en abstracto; demostró que reescribir un sistema con ciertas propiedades (grande, en producción, crítico, tácito, sin tests) es una trampa. Un prototipo de fin de semana, un script chico sin usuarios, un servicio en beta bien probado (como el del ejercicio 1) son candidatos legítimos a reescritura, y bloquearlos por dogma desperdicia la opción correcta.
La formulación con criterio: "reescribir no es ni bueno ni malo por sí mismo; depende del sistema, y se puede medir. Antes de decidir, puntuemos el sistema en cinco ejes —tamaño, usuarios en producción, conocimiento tácito, criticidad y cobertura de tests—. Si sale con score alto (chico, sin usuarios, entendido, no crítico, probado), reescribir puede ser lo más simple. Si sale con score bajo, como Mercado (-16), modernizamos en su lugar. La regla no es 'nunca reescribas'; es 'no reescribas este tipo de sistema, y aquí está cómo saber de qué tipo es el nuestro'". Esa es la diferencia entre el ingeniero con eslogan y el ingeniero con criterio: el segundo lleva una medición a la reunión, no una consigna.
Resumen y siguiente paso
En esta lección consolidaste la tesis del módulo sin caer en dogma: modernizar en su lugar vs empezar de cero es una decisión que depende del sistema y se mide. Viste, con el coche viejo, que la respuesta correcta no es una regla fija sino una evaluación de factores concretos, y lo convertiste en el rewrite_score sobre cinco ejes. Reescribir es viable en una región estrecha —sistemas chicos, sin usuarios, entendidos, poco críticos, bien probados—, y Mercado cae en la esquina opuesta, con un score de -16, porque activa los cuatro modos de falla y no tiene red. Y viste la palanca clave: la cobertura de tests es el único eje que puedes mover, y aunque para Mercado no habilita un rewrite, es el requisito previo de cualquier modernización segura —por eso el módulo 2 va primero—.
Antes de avanzar deberías poder: puntuar un sistema en los cinco ejes y dar un veredicto medido; explicar por qué la cobertura de tests es la palanca que más pesa y la única que mueves; distinguir la región estrecha donde reescribir es correcto de la mayoría de casos donde no lo es; y corregir tanto el dogma "nunca reescribas" como su extremo opuesto.
Con esto cierras el "por qué" del módulo entero. La lección 8 es el mini-proyecto: vas a aplicar todo el criterio a Mercado de punta a punta —clasificar sus módulos por valor y riesgo para elegir la primera rebanada, modelar el costo/valor de rewrite vs incremental, y escribir la recomendación de migración que justifique, con los números, por qué incremental gana—. Es el paso 0 de la guía completa, y el puente directo a la mecánica que empieza en el módulo 2.
Recursos
- Martin Fowler, "Who Needs an Architect?" y su trabajo sobre modernización — martinfowler.com/architecture. El marco de por qué las decisiones difíciles de revertir (como reescribir un sistema vivo) merecen un criterio explícito, no una corazonada. En inglés.
- Michael Feathers, Working Effectively with Legacy Code (Prentice Hall, 2004) — la tesis de que la red de tests es lo que hace seguro cualquier cambio sobre el legacy; el eje de cobertura de esta lección, desarrollado como técnica en el módulo 2. En inglés.
- Sam Newman, Monolith to Microservices (O'Reilly, 2019), cap. 1, "Is Your Migration Going to Work?" — los criterios para decidir cuándo una migración (o reescritura) tiene sentido y cuándo no; el complemento directo del
rewrite_score. En inglés. - Joel Spolsky, "Things You Should Never Do, Part I" (2000) — joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i. El título es un absoluto deliberado, pero el argumento es matizado: aplica a sistemas vivos y grandes, no a todo. Buen ejercicio de leer el matiz detrás del eslogan. En inglés.