Módulo 1: Por qué no reescribir
El síndrome del segundo sistema
Descripción
La lección 2 mostró un modo de falla que viene de afuera: el negocio no se detiene y la paridad se aleja. Esta lección muestra uno que viene de adentro, del propio equipo, y que es tan fuerte que aparece incluso si el legacy se congelara por completo. Se llama el síndrome del segundo sistema (second-system effect), y lo nombró Fred Brooks en The Mythical Man-Month en 1975. La observación es esta: de todos los sistemas que un ingeniero diseña, el segundo es el más peligroso de todos. El primero se hizo con miedo y humildad —no sabías bien qué hacías, así que lo mantuviste simple—. Pero al hacer el segundo, ya "conoces" el dominio, y llegas cargado de todas las ideas que en el primero tuviste que dejar fuera: "esta vez lo hago genérico", "esta vez soporto todos los casos", "esta vez le pongo esa capa de configuración que siempre quise". El segundo sistema no se sobre-decora por error: se sobre-decora porque el "nuevo comienzo" se siente como el permiso perfecto para meterle todo.
Una reescritura es, por definición, un segundo sistema —el rewrite de Mercado sería el "Mercado 2"—, así que hereda el síndrome completo. Y el daño no es estético: es de calendario. Cada idea extra que se cuela al alcance es trabajo que no estaba planeado, y ese trabajo empuja la fecha de cierre. Peor: el trabajo extra se descubre durante la construcción, no antes, así que el alcance crece justo mientras intentas cerrarlo. Esta lección lo mide. Vamos a modelar una reescritura con una velocidad fija de trabajo, y a inyectarle distintos niveles de "gold-plating" —el porcentaje del trabajo de cada mes que reabre como alcance nuevo—, para ver cómo la fecha de cierre se corre del mes 20 al 50, y cómo, con inflación total, el sistema nunca queda listo.
Conexión con el módulo. Es el segundo de los cuatro modos de falla del big rewrite. La lección 2 midió la falla que viene del negocio (el blanco móvil); esta mide la que viene del equipo (la inflación de alcance). Son independientes y se suman: un rewrite real sufre las dos a la vez. La lección 4 cierra el trío con el conocimiento tácito perdido. La disciplina de alcance congelado que esta lección muestra como antídoto es, no por casualidad, la misma disciplina que el enfoque incremental impone de forma natural (una rebanada tiene un alcance pequeño y acotado, difícil de inflar) —lo veremos en la lección 5—.
Una analogía: la remodelación de la cocina que nunca termina
Contrataste una remodelación de tu cocina. El plan era claro: cambiar los gabinetes y la encimera, tres semanas de obra. Pero una vez que empezaron a demoler, pasó lo de siempre. "Ya que abrimos la pared, ¿no quieres mover el fregadero a la isla?" Bueno, sí, tiene sentido. "Y ya que movemos la plomería, sería tonto no cambiar también las tuberías viejas." Claro. "Oye, y con la cocina abierta, este es el momento de tirar el muro hacia el comedor, nunca vas a tener mejor oportunidad." Tienes razón, hagámoslo. Cada sugerencia es razonable por sí sola —de verdad es más eficiente hacerlo ahora que la pared está abierta—. Pero suma tras suma, las tres semanas se volvieron cuatro meses, y cada vez que crees que ya casi terminan, aparece una cosa más que "ya que estamos" conviene hacer. La obra no se atrasó por un solo error grande: se atrasó por cien decisiones pequeñas, cada una sensata, que inflaron el alcance mientras la obra corría.
Eso es exactamente el síndrome del segundo sistema en una reescritura. "Ya que estamos reescribiendo el catálogo, hagámoslo genérico para cualquier tipo de producto." "Ya que tocamos los pedidos, soportemos también los pedidos recurrentes que siempre quisimos." "Ya que rehacemos los pagos, agreguemos ese motor de reglas configurable." Cada "ya que estamos" es razonable en aislamiento y catastrófico en conjunto: reabre el alcance justo cuando intentas cerrarlo, y la fecha de entrega se aleja tanto como en la cocina. La diferencia con la remodelación es que la cocina, al menos, tiene paredes físicas que limitan cuánto puedes agregar. El software no tiene esa frontera natural —siempre cabe una feature más—, así que el síndrome es aún peor.
Ejemplo trabajado: la fecha de cierre que se aleja
Vamos a modelar una reescritura con un alcance inicial de 200 unidades de trabajo y un equipo que cierra 10 unidades por mes. Si el alcance estuviera congelado, cerrar tomaría exactamente 20 meses (200 / 10). Ahora inyectamos el gold-plating: una fracción del trabajo de cada mes reabre como alcance nuevo ("ya que estamos, hagámoslo bien"). Con 0% de inflación hay disciplina total; con más, el alcance crece mientras lo cierras:
VELOCITY = 10 # unidades de trabajo que el equipo cierra por mes
INITIAL_SCOPE = 200 # el alcance con el que arranca la reescritura
def months_to_finish(inflation_rate, cap=120):
# inflation_rate = fraccion del trabajo del mes que REABRE como nuevo
# alcance ("ya que estamos, hagamoslo bien"). Devuelve mes de cierre o None.
remaining = INITIAL_SCOPE
for month in range(1, cap + 1):
remaining -= VELOCITY # trabajo cerrado este mes
remaining += VELOCITY * inflation_rate # gold-plating que se cuela
if remaining <= 0:
return month
return None
scenarios = [
("alcance congelado (disciplina)", 0.0),
("gold-plating leve", 0.3),
("segundo sistema clasico", 0.6),
("'hagamoslo bien de una vez'", 1.0),
]
print(f"{'estrategia':<34}{'inflacion':>10}{'cierra en':>18}")
print("-" * 62)
for name, rate in scenarios:
m = months_to_finish(rate)
when = f"mes {m}" if m is not None else "NUNCA (>10 anios)"
print(f"{name:<34}{rate:>9.0%}{when:>18}")
# Trabajo restante mes a mes: disciplina (baja) vs segundo sistema (se estanca).
print("\nTrabajo restante (unidades) - disciplina vs segundo sistema:")
print(f"{'mes':>4}{'congelado':>12}{'2do sistema':>14}")
print("-" * 30)
frozen = INITIAL_SCOPE
second = INITIAL_SCOPE
for month in range(0, 25):
if month % 4 == 0:
f_txt = frozen if frozen > 0 else "hecho"
print(f"{month:>4}{str(f_txt):>12}{second:>14.0f}")
frozen = max(0, frozen - VELOCITY)
second = second - VELOCITY + VELOCITY * 0.6
print("\n El plan prometia cerrar en el mes 20 (200 / 10).")
print(f" Con inflacion del 60%, el progreso neto cae de 10 a 4 unidades/mes y el")
print(f" cierre real se corre al mes {months_to_finish(0.6)}: un deslizamiento de "
f"{months_to_finish(0.6) / 20:.1f}x.")
print(f" Con inflacion del 100% el progreso neto es 0: el sistema NUNCA queda listo.")
Qué esperar. Al correr el archivo, la salida es exactamente esta:
estrategia inflacion cierra en
--------------------------------------------------------------
alcance congelado (disciplina) 0% mes 20
gold-plating leve 30% mes 29
segundo sistema clasico 60% mes 50
'hagamoslo bien de una vez' 100% NUNCA (>10 anios)
Trabajo restante (unidades) - disciplina vs segundo sistema:
mes congelado 2do sistema
------------------------------
0 200 200
4 160 184
8 120 168
12 80 152
16 40 136
20 hecho 120
24 hecho 104
El plan prometia cerrar en el mes 20 (200 / 10).
Con inflacion del 60%, el progreso neto cae de 10 a 4 unidades/mes y el
cierre real se corre al mes 50: un deslizamiento de 2.5x.
Con inflacion del 100% el progreso neto es 0: el sistema NUNCA queda listo.
Lee la primera tabla como una escalera hacia el abismo, un escalón por fila.
El primer escenario, alcance congelado, es la disciplina perfecta: 0% de inflación, cero "ya que estamos". Cierra en el mes 20, exactamente como el plan prometía. Este es el mundo ideal —y fíjate que ni siquiera este mundo incluye el blanco móvil de la lección 2; aquí el legacy está congelado y aun así vamos a ver cómo se descarrila—.
Baja una fila. Gold-plating leve, apenas 30% de inflación: por cada 10 unidades que el equipo cierra, 3 reabren como alcance nuevo. El cierre se corre del mes 20 al 29 —casi un 50% más—, y todo por un nivel de "ya que estamos" que la mayoría de los equipos ni siquiera notaría como excesivo. Un 30% de scope creep suena moderado, casi sano; cuesta nueve meses.
Baja otra. Segundo sistema clásico, 60% de inflación: por cada 10 cerradas, 6 reabren. El progreso neto cae a 4 unidades por mes (cierras 10 pero se agregan 6), y cerrar 200 unidades a 4 netas por mes toma 50 meses —dos veces y media el plan—. La nota al pie lo dice: un deslizamiento de 2.5x, no por incompetencia, sino porque el 60% del esfuerzo se va en features que nadie pidió al inicio.
Y la última fila es el precipicio. "Hagámoslo bien de una vez", 100% de inflación: por cada 10 unidades cerradas, 10 reabren. El progreso neto es exactamente cero. El equipo trabaja a toda máquina, cierra 10 unidades cada mes, y el trabajo restante no baja ni una unidad, porque cada avance genera su propio retroceso. NUNCA queda listo. Esta es la reescritura que lleva cuatro años "casi terminada" y en la que cada demo revela tres features nuevas por hacer.
La segunda tabla muestra el mecanismo en cámara lenta. La columna congelado baja limpio y parejo: 200, 160, 120, 80, 40, "hecho" en el mes 20. La columna segundo sistema (60% de inflación) baja penosamente: 200, 184, 168, 152, 136... en el mes 20, cuando el disciplinado ya terminó, el del segundo sistema todavía tiene 120 unidades por hacer —más de la mitad del alcance original después de haber trabajado veinte meses—. No es que trabaje menos: la columna baja, sí, pero a 4 por mes en vez de 10, porque el 60% de su esfuerzo se evapora en gold-plating.
El punto de la lección es incómodo: este modo de falla no requiere mala fe ni pereza. Al contrario, requiere entusiasmo —el equipo está motivado, quiere hacer las cosas "bien", ve la reescritura como la oportunidad de arreglar todo lo que odiaba del sistema viejo—. Ese entusiasmo, sin la disciplina de un alcance congelado, es exactamente el combustible del síndrome. Y la ironía final: el sistema viejo, el que todos quieren reemplazar, fue simple precisamente porque se hizo sin ese entusiasmo, con la humildad del que no sabía. El segundo sistema es peligroso porque cree que ya sabe.
Profundización: por qué el incremental resiste el síndrome
Podrías pensar que la solución es "solo tener disciplina" —congelar el alcance y no ceder a los "ya que estamos"—. Es correcto en teoría y dificilísimo en la práctica, porque cada sugerencia individual es razonable, y decir que no a cada una se siente mezquino ("¿en serio no vas a soportar los pedidos recurrentes, ya que estás rehaciendo pedidos?"). La disciplina pura depende de una voluntad sostenida durante años contra una presión constante, y las voluntades ceden.
El enfoque incremental no depende de la voluntad: cambia la estructura para que el síndrome no tenga dónde crecer. Cuando modernizas una rebanada pequeña —digamos, solo la lectura del catálogo— el alcance de esa rebanada es diminuto y concreto: "hacer que la lectura del catálogo funcione igual que hoy, pero en el servicio nuevo". No hay espacio para "ya que estamos, soportemos también X", porque el objetivo explícito es paridad con lo que ya existe, no mejora. Y como cada rebanada se entrega en semanas y va a producción, el equipo ve valor real rápido, lo que reduce la ansiedad de "meter todo ahora porque no habrá otra oportunidad" —habrá muchas otras oportunidades, una por rebanada—.
Disciplina pura Estructura incremental
(frágil) (robusta)
┌───────────────────┐ ┌───────────────────┐
Alcance: │ enorme, abierto │ │ pequeño, cerrado │
│ (todo el sistema) │ │ (una rebanada) │
Antídoto: │ decir "no" mil │ │ el objetivo ES │
│ veces con fuerza │ │ paridad, no mejora│
Depende de: │ voluntad sostenida│ │ el tamaño del paso│
Falla cuando: │ la voluntad cede │ │ (casi no falla) │
└───────────────────┘ └───────────────────┘
Esto no significa que en una migración incremental nunca mejores nada —claro que sí, esa es media gracia de modernizar—. Significa que las mejoras se hacen después de alcanzar paridad, rebanada por rebanada, como decisiones conscientes y separadas, no como un "ya que estamos" que se cuela mientras intentas cerrar. Primero igualas, apagas lo viejo, y luego, con el sistema nuevo ya en producción y dando valor, decides si vale la pena agregar los pedidos recurrentes. La mejora deja de ser un polizón del alcance y se vuelve una decisión propia.
Errores comunes
Confundir "aprovechar la oportunidad" con "inflar el alcance". Qué pasa: cada feature extra se justifica con "es más eficiente hacerlo ahora que estamos aquí", y como cada justificación es cierta en aislamiento, nadie las frena. Por qué pasa: la eficiencia local (sí, es más barato mover el fregadero con la pared abierta) oculta el costo global (el proyecto entero se descarrila). Cómo detectarlo: si las reuniones de la reescritura generan más features de las que cierran, y frases como "ya que estamos" o "esta vez hagámoslo bien" aparecen seguido, el síndrome está activo. Cómo corregirlo: separa dos preguntas que el "ya que estamos" fusiona: "¿es más barato hacerlo ahora?" (a menudo sí) y "¿deberíamos hacerlo ahora?" (casi siempre no, si mueve la fecha de un sistema que el negocio espera). La eficiencia de una tarea aislada no justifica descarrilar el proyecto. Congela el alcance en paridad y agenda las mejoras como trabajo separado, después del apagado.
Medir el avance por features construidas en vez de por trabajo restante. Qué pasa: el reporte de la reescritura celebra "construimos 10 unidades este mes" y da sensación de progreso, aunque el trabajo restante no baje. Por qué pasa: lo construido es visible y satisfactorio; el alcance que se reabre es difuso y no se contabiliza con el mismo entusiasmo. Cómo detectarlo: compara mes contra mes el trabajo restante (la segunda tabla del ejemplo), no las unidades cerradas. Si cierras 10 al mes pero el restante baja 4, o no baja, el síndrome te está comiendo el 60% o el 100% del esfuerzo. Cómo corregirlo: la métrica honesta de una reescritura no es "cuánto llevamos hecho" sino "cuánto falta, y esa cifra ¿está bajando de verdad?". Un restante estancado con equipo trabajando a full es la firma exacta del segundo sistema. La lección 7 de la guía de decisiones (fitness functions) da la idea general de proteger una propiedad con una prueba automatizada; aquí basta con graficar el restante y exigir que baje.
Creer que la disciplina bastará "esta vez". Qué pasa: el equipo reconoce el síndrome pero cree que lo evitará por pura fuerza de voluntad —"vamos a congelar el alcance y no ceder"—. Por qué pasa: es más fácil prometer disciplina que cambiar la estructura del trabajo. Cómo detectarlo: si el único plan contra el scope creep es "tener disciplina", sin un mecanismo estructural que la haga barata, la disciplina va a ceder ante la milésima sugerencia razonable. Cómo corregirlo: no apuestes a la voluntad; cambia la estructura. El tamaño pequeño y el objetivo de paridad de cada rebanada incremental hacen que el "ya que estamos" no tenga dónde entrar —no porque el equipo sea más fuerte, sino porque el paso es tan chico que inflarlo es evidente y absurdo—. Es la diferencia entre resistir la tentación y no exponerse a ella.
Ejercicios
Ejercicio 1 — Calcula el deslizamiento. Una reescritura tiene un alcance inicial de 300 unidades y un equipo que cierra 15 por mes. Con alcance congelado, ¿en qué mes cierra? Ahora aplica un gold-plating del 40% (por cada 15 cerradas, reabren 6). ¿Cuál es el progreso neto por mes y en qué mes cierra aproximadamente? ¿Y con 100% de inflación?
Ver solución
- Alcance congelado (0%): cierre = 300 / 15 = mes 20.
- Gold-plating 40%: por cada 15 cerradas, reabren
15 * 0.40 = 6, así que el progreso neto es15 - 6 = 9unidades por mes. Cierre ≈300 / 9 = 33.3, es decir el mes 34 (redondeando hacia arriba, porque el mes 33 aún no llega a 0). El deslizamiento es de 34/20 ≈ 1.7x, y solo por un 40% de inflación que muchos equipos considerarían moderado. - Inflación 100%: reabren
15 * 1.0 = 15por cada 15 cerradas; progreso neto =15 - 15 = 0. El trabajo restante se queda clavado en 300 para siempre: NUNCA cierra. El equipo produce 15 unidades cada mes de trabajo real y no se acerca ni un paso a la meta, porque cada avance genera su propio retroceso.
La lección: el progreso que importa es el neto (cerrado menos reabierto), no el bruto (cerrado). Un equipo veloz con inflación alta puede tener un progreso neto lentísimo o nulo, sin que su velocidad bruta lo delate.
Ejercicio 2 — El "ya que estamos" de Mercado. Durante la reescritura del catálogo de Mercado, surgen estas tres propuestas: (a) "ya que rehacemos el catálogo, hagámoslo genérico para soportar servicios además de productos físicos"; (b) "ya que tocamos las imágenes, agreguemos soporte para video de producto que siempre quisimos"; (c) "ya que migramos la búsqueda, metámosle búsqueda semántica con IA". Para cada una, di si es scope creep del segundo sistema y cómo la manejarías sin descarrilar la reescritura.
Ver solución
Las tres son scope creep clásico del segundo sistema: ninguna es paridad con lo que el catálogo hace hoy; todas son mejoras nuevas que se cuelan bajo el "ya que estamos". El manejo correcto es el mismo para las tres, con matices:
- (a) Catálogo genérico para servicios. Es la más peligrosa porque suena a "buena arquitectura": generalizar. Pero el catálogo actual solo maneja productos físicos, así que soportar servicios es alcance nuevo puro. Manejo: congela la rebanada en "hacer lo que el catálogo hace hoy, pero en el servicio nuevo". Si el negocio de verdad quiere vender servicios, eso es una feature con su propio caso de negocio, que se agenda después de que el catálogo modernizado esté en producción —como decisión consciente, no como polizón—.
- (b) Video de producto. Mejora clara, no paridad. Mismo tratamiento: fuera del alcance de la migración; agéndala como feature separada post-paridad. Nota que meterla ahora también agranda el blanco móvil de la lección 2 (más features que igualar).
- (c) Búsqueda semántica con IA. La más tentadora y la más cara. Es un proyecto entero, no un "ya que estamos". Meterla en la reescritura del catálogo es garantía de descarrilamiento. Fuera; que compita como iniciativa propia con su propio presupuesto.
El principio: durante la migración, el objetivo es igualar, no mejorar. Las tres propuestas pueden ser buenas ideas —pero como decisiones separadas, después del apagado, no como inflación del alcance mientras intentas cerrar.
Ejercicio 3 — Por qué el primer sistema fue simple. Brooks observa que el primer sistema de un ingeniero suele ser simple y el segundo suele ser sobrecargado. Explica, con tus palabras, por qué la falta de conocimiento en el primer sistema termina siendo una ventaja, y por qué el conocimiento acumulado en el segundo termina siendo una trampa.
Ver solución
En el primer sistema, el ingeniero no conoce el dominio, así que se mueve con cautela: solo construye lo que es claramente necesario, porque no tiene la confianza para agregar generalizaciones especulativas ("no sé si esto se va a necesitar, mejor no lo hago"). Esa ignorancia funciona como un freno natural al alcance: al no saber qué podría hacer falta, hace solo lo que hace falta. El resultado es simple, no por virtud, sino por prudencia forzada.
En el segundo sistema, el ingeniero ya conoce el dominio, y con el conocimiento viene la confianza —y una lista mental de todo lo que en el primero tuvo que dejar fuera—. Ahora se siente autorizado a "hacerlo bien": generalizar, anticipar casos, agregar la flexibilidad que antes no se atrevió a poner. El problema es que gran parte de esa flexibilidad es especulativa (resuelve problemas que quizá nunca lleguen) y toda ella infla el alcance. El conocimiento se vuelve trampa porque convierte el "no sé si hará falta" en "sé que algún día podría hacer falta, así que lo pongo ahora" —y ese ahora es lo que descarrila el calendario—.
La moraleja para la modernización: la humildad del primer sistema es justo lo que el enfoque incremental recupera artificialmente. Al forzar el objetivo a "paridad con lo que ya existe", le quita al equipo el permiso de "hacerlo mejor de una vez", y con eso reintroduce la simplicidad que el conocimiento tiende a destruir. La lección 5 lo desarrolla como el caso a favor de lo incremental.
Resumen y siguiente paso
En esta lección abriste el segundo modo de falla del big rewrite: el síndrome del segundo sistema. Viste, con la remodelación de la cocina que nunca termina, que cada "ya que estamos" es razonable por sí solo y catastrófico en conjunto, porque reabre el alcance justo cuando intentas cerrarlo. Y lo mediste: un gold-plating del 30% corre el cierre del mes 20 al 29; el 60% lo lleva al 50 (un deslizamiento de 2.5x); y el 100% lo empuja al infinito, con el trabajo restante clavado a pesar de un equipo trabajando a toda máquina. Este modo de falla no viene del negocio ni de la incompetencia: viene del entusiasmo del propio equipo, y por eso la disciplina pura es frágil frente a él. El antídoto robusto es estructural: el alcance pequeño y el objetivo de paridad de cada rebanada incremental no le dejan espacio al síndrome.
Antes de avanzar deberías poder: explicar por qué el segundo sistema es el más peligroso; calcular cómo la inflación de alcance reduce el progreso neto y corre la fecha de cierre; distinguir "es más barato hacerlo ahora" de "deberíamos hacerlo ahora"; y argumentar por qué la estructura incremental resiste el síndrome mejor que la voluntad.
La lección 4 cierra el trío de modos de falla con el más sutil y el más peligroso: el conocimiento tácito enterrado en el legacy. Vas a ver que las partes "raras" del código viejo —las que un rewrite limpio querría tirar— casi nunca son bugs, sino reglas de negocio ganadas en años que nadie documentó, y vas a contar las regresiones silenciosas que una reescritura a ciegas introduce al ignorarlas.
Recursos
- Frederick P. Brooks, The Mythical Man-Month (Addison-Wesley, 1975), cap. 5 "The Second-System Effect" — la fuente original del concepto de esta lección. Brooks describe cómo el segundo sistema tiende a la sobre-ingeniería con todas las ideas que el primero, por prudencia, dejó fuera. Lectura obligada del oficio. 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. Conecta el segundo sistema con el fracaso concreto de la reescritura de Netscape. En inglés.
- Steve McConnell, Rapid Development (Microsoft Press, 1996), cap. sobre "Feature Creep" — el tratamiento clásico del scope creep como una de las causas principales de fracaso de proyectos, con estrategias para controlarlo. En inglés.
- Sam Newman, Monolith to Microservices (O'Reilly, 2019) — cómo el tamaño acotado de cada paso de migración limita estructuralmente la inflación de alcance; el antídoto de la profundización, desarrollado. En inglés.