Módulo 2: Cuándo NO abstraer
5. YAGNI: no lo vas a necesitar
Descripción
Al terminar esta lección vas a tener el principio que ataca la motivación de casi toda la sobre-ingeniería —construir para un futuro que imaginaste— y, más importante, vas a tener su matiz. Porque YAGNI se malinterpreta casi siempre, y las dos malinterpretaciones son caras: la de quien lo usa como excusa para no pensar, y la de quien lo rechaza creyendo que le pide programar sin previsión. Vas a salir con una prueba de tres preguntas que separa la preparación barata y reversible —que sí conviene— de la infraestructura especulativa —que no—, y con el inventario del costo de mantener algo que nadie usa.
Esto importa porque las tres lecciones anteriores describieron un daño y esta ataca su causa. La abstracción prematura no aparece por descuido; aparece por previsión mal calibrada. Quien montó el sistema de plugins de Boletia no estaba siendo perezoso ni presumido: estaba tratando de ahorrarle trabajo al equipo del futuro. La intención era buena. Lo que faltaba era la cuenta.
Y hay una segunda razón. En un equipo, YAGNI es la herramienta de conversación más usada de todo este módulo. Es la que se invoca en una revisión de código o en una reunión de diseño. Por eso vale la pena conocerla bien: un argumento mal usado se desgasta, y si YAGNI se convierte en tu muletilla para todo, la próxima vez que de verdad lo necesites nadie te va a escuchar.
Conexión con el módulo: la lección 2 puso el costo, la 3 el momento, y la 4 el daño de equivocarse. Esta lección se ocupa del origen: el impulso de preparar el terreno. Es también la lección que más matiza al módulo, porque establece una categoría entera de decisiones —las preparaciones baratas— que sí conviene tomar por adelantado, y eso evita que el criterio degenere en "nunca hagas nada". La lección 6 aplica todo lo acumulado al caso extremo: el sistema de plugins, que falla en las tres preguntas a la vez. Y la 7 muestra que la línea entre preparación e infraestructura es un punto en un espectro, no una frontera.
La mudanza
Te mudas a una casa nueva y tienes dos oportunidades de prepararte para el futuro.
La primera es la caja de cables. Ya sabes cuál: cargadores de teléfonos que ya no tienes, adaptadores raros, un cable de red, dos controles remotos huérfanos. La guardas "por si acaso". ¿Qué te cuesta? Un cajón. ¿Qué te cuesta mantenerla? Nada; está en el cajón. Y si en dos años no abriste esa caja, un domingo la tiras y no pasó nada. Costo bajo, mantenimiento cero, reversible en treinta segundos.
La segunda es el cuarto extra. Le pides al constructor una habitación más, "por si viene la familia". ¿Qué te cuesta? Dinero, semanas de obra, permisos. ¿Qué te cuesta mantenerla? Limpiarla, pintarla cuando toque, calentarla en invierno, pagar el predial de esos metros. Y si en dos años resulta que la familia nunca vino, no la puedes tirar: tirar un cuarto es otra obra.
La intención es idéntica en los dos casos: prepararse. La economía es opuesta.
Y fíjate en algo que no es obvio: la diferencia no está en qué tan probable es el futuro que imaginas. Puede ser igual de probable que necesites un cable raro o que venga la familia. La diferencia está en tres números completamente distintos:
- Cuánto cuesta hacerlo hoy.
- Cuánto cuesta que exista mientras tanto.
- Cuánto cuesta deshacerlo si te equivocaste.
Guarda las dos imágenes, porque las vamos a usar todo el resto de la lección. La caja de cables es la preparación barata y reversible. El cuarto extra es la infraestructura especulativa. Y buena parte del oficio consiste en saber, frente a una propuesta, cuál de las dos tienes enfrente.
Qué dice YAGNI exactamente
YAGNI son las iniciales de "You Aren't Gonna Need It" — no lo vas a necesitar. Viene de la comunidad de Extreme Programming, a finales de los noventa, y su formulación más citada es de Ron Jeffries:
Implementa las cosas siempre cuando de verdad las necesites, nunca cuando solo prevés que las vas a necesitar.
La palabra que hace todo el trabajo en esa frase es implementa. No dice "no pienses". No dice "no diseñes". No dice "no converses sobre el futuro". Dice: no lo construyas.
Esa distinción es la que salva al principio de sus dos caricaturas. Vale la pena hacerla explícita, porque las dos son comunes:
YAGNI no dice "no pienses en el futuro". Pensar en el futuro es gratis, es útil y es tu trabajo. Preguntarte "¿qué pasaría si mañana hay tres proveedores más?" es un ejercicio excelente: te dice si tu diseño actual se pintaría solo en una esquina. Lo que YAGNI pide es que el resultado de ese ejercicio sea información, no código.
YAGNI no aplica a la calidad interna. Este es el error de categoría más frecuente. Escribir tests, poner buenos nombres, no acoplar innecesariamente, extraer una función cuando hay complejidad real —nada de eso es "construir una capacidad presunta"—. Es hacer bien lo que estás haciendo hoy. Martin Fowler es explícito sobre este punto: YAGNI se refiere a capacidades presuntas, funcionalidades que el sistema todavía no necesita. Alguien que dice "no escribo tests porque YAGNI" no está aplicando el principio: está usando su nombre para otra cosa.
Con esas dos aclaraciones, la formulación operativa del principio queda así:
No construyas para el futuro que no está pedido.
Y "pedido" tiene un significado verificable: hay un requisito, con alguien que lo pide y una fecha. No una intuición, no un "seguramente", no "en el roadmap aparece algo parecido". Si no puedes señalar quién lo pidió y cuándo lo necesita, es un futuro imaginado.
Ejemplo trabajado: dos decisiones del mismo sprint en Boletia
Este ejemplo es el corazón de la lección, porque las dos decisiones las tomó la misma persona, la misma semana, con la misma intención. Una fue correcta y la otra no, y la diferencia no está en la disciplina de quien decidió.
Decisión A — poner el envío de correo detrás de una función.
En ese momento, el código del checkout hablaba SMTP directamente:
# Archivo: checkout/checkout.py (antes)
import smtplib
from email.mime.text import MIMEText
def checkout(order):
...
# Aviso de confirmación al cliente.
msg = MIMEText(body, "html")
msg["Subject"] = "Tu compra en Boletia"
msg["From"] = settings.SMTP_FROM
msg["To"] = customer.email
with smtplib.SMTP(settings.SMTP_HOST, settings.SMTP_PORT) as server:
server.starttls() # el servidor exige TLS
server.login(settings.SMTP_USER, settings.SMTP_PASSWORD)
server.send_message(msg)
...
Había un solo sitio de llamada. Y aun así, alguien propuso envolverlo:
# Archivo: notifications/email_channel.py
import smtplib
from email.mime.text import MIMEText
def send_email(to: str, subject: str, body: str) -> None:
"""Envía un correo en HTML. Único lugar del sistema que habla SMTP."""
msg = MIMEText(body, "html")
msg["Subject"] = subject
msg["From"] = settings.SMTP_FROM
msg["To"] = to
with smtplib.SMTP(settings.SMTP_HOST, settings.SMTP_PORT) as server:
server.starttls()
server.login(settings.SMTP_USER, settings.SMTP_PASSWORD)
server.send_message(msg)
# Archivo: checkout/checkout.py (después)
from notifications.email_channel import send_email
def checkout(order):
...
send_email(customer.email, "Tu compra en Boletia", body)
...
El argumento fue explícitamente especulativo: "el día que cambiemos de SMTP a un servicio transaccional, este es el único archivo que hay que tocar". Y ese día no estaba pedido por nadie.
Decisión B — el sistema de plugins de asientos.
La misma semana, la misma persona, el mismo argumento en su forma general: "el día que un organizador quiera su propio sistema de butacas, va a estar listo". Y salió de ahí la carpeta plugins/ con sus cinco archivos, su interfaz de cinco métodos, su registro y su descubrimiento dinámico.
Ahora las dos decisiones, medidas con los mismos tres números:
| A: envolver el correo | B: sistema de plugins | |
|---|---|---|
| Costo de hacerlo hoy | 15 minutos | 3 días |
| Costo de hacerlo el día que se necesite | 1 hora (extraer de un sitio) | 3 días (los mismos) |
| Costo de que exista mientras tanto | Un salto de un nivel, un nombre obvio | 4 archivos, 6 saltos, un concepto privado, y una caída de 40 minutos |
| Costo de deshacerlo | 5 minutos: pegar el cuerpo de vuelta | Un proyecto; y crece cada mes |
| ¿Mejora algo hoy? | Sí: el checkout deja de saber de TLS y MIME | No |
| Beneficio cobrado en 2 años | El correo se movió a un servicio transaccional: se tocó un archivo | Cero plugins nuevos |
Qué esperar de esta comparación. Cuatro cosas, y la última es la que quiero que te lleves.
Primero: la fila del "costo de hacerlo el día que se necesite" es la que casi nadie calcula, y es la que más decide. Mira B: hacerlo hoy cuesta tres días y hacerlo después cuesta los mismos tres días. Cuando esos dos números son iguales, anticiparse no compra absolutamente nada. Solo adelanta un gasto y agrega el costo de cargarlo mientras tanto. Anticiparse solo tiene sentido cuando hacerlo después es desproporcionadamente más caro.
Segundo: la fila de "¿mejora algo hoy?" separa las dos categorías con una limpieza sospechosa. La decisión A mejora el presente: el checkout deja de conocer los detalles de TLS, de MIME y de las credenciales, y eso lo hace más corto y más legible hoy, independientemente de lo que pase mañana. La decisión B no mejora nada hoy; su justificación entera vive en el futuro.
Ahí tienes una regla práctica muy útil: si una preparación solo se justifica por el futuro y no mejora nada en el presente, desconfía. Las buenas preparaciones casi siempre tienen un beneficio inmediato además del futuro. Cuando el único argumento es "el día que…", estás mirando un cuarto extra.
Tercero: la decisión A resultó ser una abstracción, y del tipo bueno. Vuelve a la prueba de la lección 2 —¿qué dejo de tener que saber gracias a esta capa?— y aplícala a send_email. Dejas de tener que saber: el servidor y el puerto, que hay que negociar TLS, cómo se autentica, y cómo se arma un mensaje MIME. Cuatro cosas reales. Oculta, no redirige. Y eso es cierto aunque solo haya un sitio de llamada, porque el valor no viene del número de implementaciones sino de la complejidad que esconde.
Cuarto, y es el punto: la intención era idéntica y la economía era opuesta. No hay ninguna diferencia de carácter, disciplina o inteligencia entre quien tomó A y quien tomó B. Es la misma persona. Lo que faltó en B fue hacer la cuenta antes de escribir la primera línea, y la cuenta se hace con tres preguntas que caben en un minuto de conversación.
La prueba de las tres preguntas
Este es el instrumento operativo de la lección. Se usa antes de escribir código, y funciona en una reunión de diseño o en un comentario de revisión.
Pregunta 1 — ¿Cuánto cuesta hacerlo hoy?
Minutos, horas o días. Es la única que la gente estima habitualmente, y es la menos informativa de las tres. Sirve sobre todo como filtro grueso: si la respuesta es "minutos", las otras dos preguntas casi siempre van a dar bien también.
Pregunta 2 — ¿Cuánto costaría hacerlo el día que de verdad se necesite?
Esta es la pregunta olvidada, y la que más cambia decisiones. Compárala con la primera:
- Si hacerlo después cuesta más o menos lo mismo, no hay ningún argumento para hacerlo hoy. Anticiparse no ahorra nada.
- Si hacerlo después cuesta muchísimo más —porque implicaría migrar datos, romper una interfaz pública, o coordinar con clientes que ya publicaron su aplicación— entonces sí hay un caso genuino para pensarlo hoy.
La mayoría de las abstracciones especulativas mueren en esta pregunta. El sistema de plugins costaba lo mismo hoy que dentro de dos años. La interfaz de moneda de la lección 2, lo mismo. La interfaz de cupones de la lección 4, lo mismo.
Pregunta 3 — ¿Cuánto cuesta deshacerlo si me equivoqué?
Esta es la que decide, y es la que conecta con toda la lección 4. La reversibilidad es la propiedad más importante de una decisión tomada con información incompleta, porque te permite equivocarte barato.
- Reversible en minutos → adelante, aunque no estés seguro. El costo de equivocarse es menor que el costo de deliberar.
- Irreversible o caro de revertir → espera hasta tener el requisito. Aquí sí conviene pagar el costo de pensar más.
Y una pregunta 4, de diagnóstico, que ya vimos y que sirve de desempate: ¿mejora algo hoy? Si la respuesta es no, estás frente a especulación pura, y las tres preguntas anteriores tienen que dar todas muy bien para que valga la pena.
La prueba aplicada a ocho casos
Vamos a pasar por la prueba un conjunto de decisiones reales, para que veas que el resultado no siempre es "no".
| Preparación | Hoy | Después | Deshacer | ¿Mejora hoy? | Veredicto |
|---|---|---|---|---|---|
Envolver el envío de correo en send_email() | 15 min | 1 h | 5 min | Sí | Sí |
| Leer la URL del proveedor de una variable de entorno en vez de una constante | 5 min | 10 min | 5 min | Sí: permite un ambiente de pruebas | Sí |
Que una función reciba order en vez de order_id | 0 | 0 | 0 | Sí: menos consultas | Sí (es diseño, no especulación) |
| Guardar las fechas en UTC desde el primer día | 10 min | migración de millones de filas | migración | Sí | Sí, y con ganas |
Agregar una columna metadata JSON "por si acaso" | 5 min | migración | migración + código que ya la usa | No | No (parece barata hoy y es cara de deshacer) |
Interfaz MoneyFormatter con una sola moneda | 1 h | 1 h | 30 min | No | No |
| Sistema de plugins con descubrimiento dinámico | 3 días | 3 días | Un proyecto | No | No |
| Escribir tests del código que estás escribiendo hoy | — | — | — | — | No aplica: no es una capacidad presunta |
Detente en dos filas.
La de UTC es el ejemplo canónico de cuándo YAGNI no aplica. Guardar las fechas en zona horaria local cuesta lo mismo hoy que guardarlas en UTC, pero corregirlo después implica migrar datos históricos con información que ya se perdió —no sabes en qué zona estaba el servidor cuando se escribió cada fila—. La pregunta 2 tiene respuesta catastrófica, y por eso aquí se piensa de más y está bien.
La de la columna metadata JSON es la más tramposa de la tabla, y por eso la incluí. Hoy cuesta cinco minutos: es una migración de una línea. Se siente como una caja de cables. Pero no lo es, y por dos razones. Primero, deshacerla exige otra migración —y en cuanto haya datos adentro, ya no es una migración, es una decisión de negocio sobre qué hacer con esos datos—. Segundo, y peor: una columna genérica invita a que le metan cosas. En seis meses tiene siete claves distintas puestas por cuatro personas, ninguna documentada, y el esquema real de tu tabla vive en un JSON que nadie valida. Es un cuarto extra disfrazado de caja de cables.
Los cuatro costos de construir lo que no se pidió
Martin Fowler desglosó el costo de una capacidad presunta en cuatro partes, y el desglose es útil porque las cuatro se olvidan en momentos distintos.
Costo de construir. El tiempo de hacerlo ahora. Se le resta directamente a algo que sí está pedido. Es el único que suele aparecer en una estimación.
Costo de retraso. Lo que no entregaste mientras construías esto. Es un costo de oportunidad, no aparece en ningún lado, y suele ser el más grande de los cuatro en un producto que compite. Los tres días del sistema de plugins fueron tres días que no se dedicaron al checkout, que ya estaba dando problemas.
Costo de carga. Lo que cuesta que exista mientras tanto. Son los cuatro costos de la lección 2 —salto, archivo, concepto, superficie de bug— multiplicados por el tiempo y por la gente. Es el que se paga en cuotas y por eso nadie lo suma.
Costo de reparación. Si construiste la versión equivocada de la capacidad —lo cual es lo más probable, porque no tenías un requisito real que la guiara— lo que cuesta corregirla. Y aquí entra todo lo de la lección 4: el costo de reparación no es solo rehacer la abstracción, es desmontar todo lo que se construyó encima del eje equivocado.
Ahora la observación que hace útil el desglose. Se suele razonar así: "si resulta que lo necesitamos, nos ahorramos el trabajo de hacerlo después". Cierto. Pero ese es un escenario de cuatro, y conviene verlos todos:
| Escenario | Resultado |
|---|---|
| Nunca se necesita | Pierdes construir + retraso + carga |
| Se necesita, pero distinto a como lo construiste | Pierdes construir + retraso + carga + reparación |
| Se necesita igual, pero mucho después | Ganas poco (hacerlo entonces habría costado casi lo mismo) y pagaste carga todo ese tiempo |
| Se necesita igual y pronto | Ganas. Este es el único escenario bueno |
Uno de cuatro. Y el segundo escenario —se necesita, pero distinto— es el más probable de todos, precisamente porque construir sin un requisito real significa construir a partir de una suposición sobre el requisito. Es el error de eje de la lección 3, pero peor: allá al menos tenías dos casos reales sobre la mesa.
En el sistema de plugins de Boletia, el escenario que ocurrió fue el primero. En la interfaz de pagos escrita con dos proveedores, el segundo.
El costo de mantener lo que nadie usa
Vale la pena inventariar el costo de carga, porque la intuición dice que el código que nadie ejecuta no molesta, y es falso.
El código que no se usa:
- Se revisa. Aparece en el analizador estático y en el chequeo de tipos, y produce advertencias que alguien tiene que atender o silenciar. Silenciarlas también es trabajo, y además entrena al equipo a ignorar advertencias.
- Se testea. El rincón
plugins/de Boletia tiene cuatro tests, sesenta y siete líneas, que prueban el registro y el descubrimiento. Ninguno prueba una funcionalidad de asientos: prueban el andamiaje. Dos de ellos se rompieron en la migración a Python 3.11 y costaron medio día arreglarlos. - Se migra. Cada actualización de lenguaje, de librería o de framework arrastra todo el código, use o no. La corrección de
pkgutil.iter_moduleses exactamente eso: medio día invertido en mantener vivo un mecanismo que nunca mecanizó nada. - Aparece en las búsquedas. Quien busca "seat" en el proyecto encuentra cinco archivos y tiene que decidir cuál importa. Ese es ruido permanente para todo el equipo.
- Entra en las auditorías. Si el código muerto importa una dependencia, esa dependencia hay que parchearla cuando salga un aviso de seguridad, aunque el código no se ejecute nunca. Nadie audita "solo lo que se usa"; se audita lo que está.
- Ocupa espacio en la cabeza. Cada persona que entra al equipo tiene que aprender qué es un
SeatingPluginy luego aprender que no importa. Las dos cosas cuestan.
Y el peor de todos, que es el que menos se ve:
- Bloquea decisiones. "¿Podemos cambiar la firma de
assign_seat?" — "No sé, el registro de plugins la usa." Ahora el equipo tiene que investigar un mecanismo que no sirve para nada, antes de poder hacer un cambio que sí sirve. Ese impuesto se cobra en cada decisión que roce el rincón, para siempre.
Junta las seis y sale un número incómodo: en dos años, el sistema de plugins de Boletia consumió los tres días de construcción, medio día de migración, cuarenta minutos de caída en producción más el tiempo de diagnóstico, y una cantidad difícil de contar de minutos de lectura repartidos entre seis personas. Todo eso por una capacidad que nunca se usó ni una vez.
Cuando YAGNI se usa mal
Un principio se desgasta cuando se usa fuera de su alcance. Estos son los cuatro casos donde invocarlo es un error, y conviene conocerlos para no perder credibilidad usándolo mal.
Cuando lo que está en discusión es calidad interna, no una capacidad. Tests, nombres, tamaño de funciones, manejo de errores, registros de actividad. Nada de eso es una capacidad presunta; es cómo se hace bien lo que ya estás haciendo. Un equipo que recorta calidad interna en nombre de YAGNI se hace más lento en semanas, no en años.
Cuando el requisito está pedido y con fecha. Si hay un contrato firmado que dice que en seis semanas Boletia soporta un tercer proveedor específico, ese proveedor no es presunto: es un requisito con dueño y fecha. Diseñar con él sobre la mesa no es especular, es tener la información completa. La prueba: ¿puedes señalar el documento y la fecha? Si sí, no apliques YAGNI. Si tu evidencia es "producto mencionó en una reunión", sí aplícalo.
Cuando la pregunta 2 tiene respuesta catastrófica. Esquema de base de datos con volumen, formato de una API pública con clientes ya publicados, zona horaria de almacenamiento, formato de un archivo que los usuarios ya tienen guardado, esquema de un evento que otros sistemas consumen. En todos esos casos, hacerlo después no cuesta un poco más: cuesta un orden de magnitud más, o directamente no se puede. Ahí conviene pensar de más y está bien. YAGNI es una herramienta para decisiones reversibles.
Cuando se usa para ganar una discusión en vez de para tomar una decisión. Si "eso es YAGNI" se convierte en tu respuesta refleja a toda propuesta de estructura, dejaste de razonar y empezaste a etiquetar. Y tiene un costo social concreto: la gente deja de proponer cosas, incluidas las buenas. Un uso sano se parece más a "hagamos las tres preguntas: ¿cuánto cuesta hoy, cuánto costaría después, cuánto cuesta deshacerlo?", que es una invitación a pensar juntos y no un veredicto.
Errores comunes
Confundir YAGNI con "no pienses en el futuro" (conceptual). Qué pasa: alguien adopta el principio y deja de hacerse preguntas sobre lo que viene. Toma decisiones irreversibles —el esquema de datos, el formato de la API pública, la zona horaria— sin considerar sus consecuencias, y las defiende diciendo que no hay que especular. Meses después, corregir una de esas decisiones cuesta una migración. Por qué pasa: el nombre del principio es una negación rotunda y no lleva su matiz encima; "no lo vas a necesitar" suena a "no mires adelante". Cómo detectarlo: si estás invocando YAGNI sobre una decisión que sería cara de revertir, lo estás usando fuera de su alcance. Cómo corregirlo: recuerda que YAGNI dice no lo construyas, no no lo pienses. Pensar produce información y la información es gratis. Y aplica el filtro de reversibilidad primero: si la decisión es difícil de deshacer, YAGNI no es la herramienta correcta.
Olvidar la segunda pregunta (de análisis). Qué pasa: alguien evalúa una preparación solo por lo que cuesta hoy, concluye "son solo dos horas" y la aprueba. Nunca se pregunta cuánto costaría hacerla el día que de verdad haga falta. Y en la enorme mayoría de los casos, la respuesta es "casi lo mismo", lo cual significa que anticiparse no compró nada y solo adelantó un gasto. Por qué pasa: la primera pregunta es concreta y familiar —estimar trabajo es lo que hacemos todo el tiempo— y la segunda exige imaginar un escenario. Cómo detectarlo: si en la discusión nadie dijo un número para "hacerlo después", falta la mitad del análisis. Cómo corregirlo: haz de la comparación un hábito verbal. "Hoy cuesta X, después cuesta Y." Cuando X e Y son parecidos, la conversación se acaba sola y sin necesidad de invocar ningún principio, que es la mejor forma de ganar una discusión de diseño.
Usar YAGNI como coartada para el descuido (de abuso). Qué pasa: alguien entrega código sin tests, con nombres opacos y con la lógica de negocio mezclada en el manejador HTTP, y cuando se lo señalan responde que no hay que sobre-diseñar. El principio se convierte en permiso. Por qué pasa: YAGNI y "hazlo simple" suenan parecido, y "simple" se confunde con "poco trabajo". Pero simple significa pocas cosas entrelazadas, no pocas horas invertidas. Cómo detectarlo: la pregunta que lo separa es ¿esto es una capacidad que el sistema todavía no necesita, o es la calidad de lo que estoy entregando hoy?. Los tests del código de hoy no son una capacidad del mañana. Cómo corregirlo: sé explícito sobre el alcance del principio cuando lo uses, sobre todo con gente que empieza. YAGNI protege del cuarto extra; no da permiso de dejar los cables colgando del techo.
Ejercicios
Ejercicio 1 — Pasa cinco propuestas por la prueba. Para cada una, contesta las tres preguntas —costo hoy, costo después, costo de deshacer— más la de diagnóstico —¿mejora algo hoy?— y da un veredicto.
(a) En Boletia hay un solo idioma. Un compañero propone meter todos los textos visibles en un archivo de traducciones "para cuando internacionalicemos".
(b) El identificador de las órdenes es un entero autoincremental. Alguien propone cambiarlo a un identificador aleatorio ahora, antes de que la tabla crezca.
(c) La función checkout(order) recibe el objeto completo. Alguien propone cambiarla a checkout(order_id) "para que sea más desacoplada".
(d) Hoy se guarda una sola dirección por cliente, en tres columnas de la tabla. Alguien propone crear ya una tabla addresses con relación de uno a muchos, "porque tarde o temprano va a haber varias".
(e) El reporte de asistentes se genera en el momento de pedirlo y tarda cuatro segundos. Alguien propone montar ya una cola de trabajos en segundo plano "porque cuando haya eventos grandes va a tardar más".
Ver solución
(a) Archivo de traducciones. Hoy: unas horas, hay que tocar todos los textos. Después: las mismas horas, quizá algo más si el sistema creció. Deshacer: horas. ¿Mejora hoy? Marginalmente —los textos quedan juntos y es más fácil corregir una errata— pero también agrega un salto para leer cualquier mensaje. Veredicto: no. Hoy y después cuestan lo mismo, así que anticiparse no compra nada. Y hay un argumento extra: internacionalizar de verdad no es sacar los textos a un archivo; es plurales, formatos de fecha, monedas, dirección del texto. La preparación que harías hoy probablemente sería la versión equivocada de la capacidad —el segundo escenario de Fowler—.
(b) Identificador aleatorio. Hoy: una migración pequeña, la tabla todavía es chica. Después: una migración sobre millones de filas, con todas las claves foráneas y las URLs públicas que ya usan el número. Deshacer: caro en los dos momentos. ¿Mejora hoy? Sí: los identificadores secuenciales filtran información de negocio —cualquiera puede comprar dos boletos con una hora de diferencia y estimar cuántas órdenes tienes—. Veredicto: sí, y no es realmente YAGNI: la pregunta 2 tiene respuesta catastrófica y además hay un beneficio presente. Es la fila de UTC de la tabla.
(c) Cambiar a checkout(order_id). Hoy: minutos. Después: minutos. Deshacer: minutos. ¿Mejora hoy? No, lo empeora: obliga a la función a ir a buscar la orden a la base de datos, lo cual agrega una consulta y hace más difícil probarla. Veredicto: no, y con un matiz importante: aquí ni siquiera se trata de YAGNI. La propuesta usa la palabra "desacoplada" como si fuera un bien en sí mismo, y lo que produce es una dependencia nueva a la base de datos donde no había ninguna. La lección 7 se ocupa exactamente de esta confusión.
(d) Tabla addresses desde ya. Hoy: una tabla y una migración, más el código que la use. Después: una migración de datos, que es más cara pero perfectamente hacible con volúmenes normales. Deshacer: caro, hay una tabla con datos. ¿Mejora hoy? No: agrega un JOIN a cada consulta que necesite la dirección. Veredicto: no, todavía. Este es un caso intermedio honesto y por eso lo incluí: si hubiera un requisito con fecha para direcciones múltiples, la respuesta cambiaría, porque migrar datos siempre es más caro que empezar bien. Sin requisito, tres columnas funcionan y la migración futura es un trabajo conocido y acotado.
(e) Cola de trabajos en segundo plano. Hoy: días, más infraestructura nueva que hay que operar, monitorear y desplegar. Después: los mismos días. Deshacer: caro, porque la interfaz de usuario cambia —el reporte deja de ser inmediato y pasa a "te avisamos cuando esté"—. ¿Mejora hoy? No: cuatro segundos es aceptable. Veredicto: no. Y fíjate en algo: esta propuesta trae un costo que ninguna de las otras tiene, que es operativo. Una cola es un componente más que se cae, que hay que monitorear y que alguien tiene que atender a las tres de la mañana. La infraestructura especulativa es más cara que la abstracción especulativa, porque su costo de carga incluye a las personas de guardia.
Por qué funciona: dos de los cinco casos dan "sí" o "casi sí". Si la prueba diera siempre "no", no sería una prueba: sería un prejuicio con formato de tabla.
Ejercicio 2 — Los cuatro escenarios, aplicados. Toma el sistema de plugins de asientos de Boletia y determina, con la información que tienes de las lecciones anteriores: (a) en cuál de los cuatro escenarios de Fowler cayó; (b) cuánto costó cada uno de los cuatro costos, con los números que conoces; (c) cuál de los cuatro costos fue el mayor, y por qué es el que menos se discute.
Ver solución
(a) Escenario 1: nunca se necesitó. Cero plugins registrados en dos años, la columna seating_plugin siempre en "default" en ciento ochenta mil eventos, y un supports() que devuelve True para todo, lo cual es la confesión escrita de que nunca hubo intención de que hubiera un segundo.
(b) Los cuatro costos con los números que tenemos:
- Construir: tres días.
- Retraso: tres días que no se dedicaron a otra cosa. En ese momento, el
checkoutya estaba dando problemas y ya se hablaba de agregar un tercer proveedor de pago. Es imposible saber qué habría pasado con esos tres días, pero el costo existió. - Carga: medio día de la migración a Python 3.11, cuarenta minutos de caída en producción más el tiempo de diagnóstico —del cual veinticinco minutos se fueron solo en entender que la culpa era de un archivo que nadie usaba—, sesenta y siete líneas de tests que prueban el andamiaje, y los minutos de lectura repartidos entre seis personas durante dos años cada vez que alguien pasa por ahí.
- Reparación: todavía no se pagó. Es el proyecto de la lección 8, y hoy cuesta bastante más que las tres horas que habría costado el primer mes.
(c) El mayor fue el de carga, y es el que menos se discute por tres razones que conviene separar. Primera: se paga en cuotas pequeñas y nadie suma cuotas. Segunda: se reparte entre varias personas, así que ninguna siente el total. Tercera, y la más importante: se paga en el futuro y la decisión se tomó en el pasado, de modo que casi nunca se atribuye a su causa. Cuando alguien pierde veinte minutos entendiendo el registro de plugins, no lo anota en ningún lado ni lo conecta con una decisión de hace dos años; simplemente piensa que el código es complicado.
Por qué funciona: este ejercicio convierte una historia en una cuenta. Y la cuenta es lo que puedes llevar a una discusión con alguien que no comparte tu intuición, que es exactamente la situación en la que vas a estar el día que alguien proponga el próximo sistema de plugins.
Ejercicio 3 — Encuentra la excepción y defiéndela. Escribe un caso, distinto a los de la lección, en el que sí hay que construir para el futuro aunque nadie lo haya pedido. Justifícalo con las tres preguntas y di explícitamente qué propiedad lo saca del alcance de YAGNI.
Ver solución
Hay varias familias de respuesta correcta. Una buena, con su justificación completa:
Caso: registrar en la base de datos quién y cuándo modificó una orden, desde el primer día.
Nadie pidió una auditoría. Pero: hoy cuesta media hora —dos columnas y una función que las llena—. El día que se necesite cuesta lo mismo escribirlo, y además es imposible recuperar la historia que no se guardó. Deshacerlo es trivial: se borran dos columnas. Y mejora el presente, porque cuando algo sale mal en producción puedes ver qué pasó.
Lo que lo saca del alcance de YAGNI es que la información es irrecuperable. La pregunta 2 no tiene respuesta "un poco más caro": tiene respuesta "no se puede". YAGNI es una herramienta para decisiones reversibles, y una decisión que destruye información no lo es.
Otras respuestas igual de válidas, con la misma propiedad de fondo:
- Guardar el monto y la moneda en la orden en vez de calcularlos al vuelo desde el precio actual del boleto. Los precios cambian; lo que el cliente pagó no. Si no lo guardas hoy, mañana no puedes reconstruirlo.
- Poner un número de versión en el formato de un archivo o de un evento que otros sistemas consumen. Cuesta un campo hoy; sin él, el día que el formato cambie no tienes forma de distinguir lo viejo de lo nuevo, y los consumidores ya publicados no se pueden actualizar a la vez.
- Definir explícitamente qué pasa cuando dos personas compran el último boleto al mismo tiempo. No es "una capacidad futura": es una condición que ya puede ocurrir hoy. Descubrir que no lo definiste significa descubrirlo con dinero de por medio.
La propiedad común de todas: la pregunta 2 no tiene respuesta en dinero, tiene respuesta en imposibilidad. Cuando hacerlo después no es más caro sino inviable —porque los datos se perdieron, porque el cliente ya desplegó, porque el formato ya salió— estás fuera del alcance de YAGNI y dentro del de las decisiones irreversibles, donde la regla es la contraria: piensa de más.
Y una nota final para calibrar: fíjate en que ninguna de estas excepciones es una abstracción. Son datos que se guardan, campos que se agregan, comportamientos que se definen. Las excepciones legítimas a YAGNI casi nunca toman la forma de una interfaz o de un mecanismo de extensión. Eso no es casualidad: las interfaces son de las cosas más fáciles de agregar después, porque agregarlas no destruye información. Cuando alguien te diga que hay que poner una interfaz ahora "porque después va a ser imposible", pídele que te explique qué se vuelve imposible exactamente.
Resumen y siguiente paso
En esta lección desarmaste YAGNI. Viste que no dice "no pienses en el futuro" sino no construyas para el futuro que no está pedido, y que "pedido" tiene un significado verificable: alguien que lo pide y una fecha. Y viste que el principio no aplica a la calidad interna: los tests, los nombres y el manejo de errores del código de hoy no son capacidades del mañana.
Te llevas la imagen de la mudanza: la caja de cables —barata, reversible, sin mantenimiento— contra el cuarto extra —caro de construir, caro de mantener, imposible de tirar—. Misma intención, economía opuesta.
Viste las dos decisiones que la misma persona tomó la misma semana en Boletia. Envolver el correo en send_email(): quince minutos, mejora el presente, reversible en cinco minutos, y cobró su beneficio dos años después con un solo archivo tocado. El sistema de plugins: tres días, no mejora nada hoy, imposible de deshacer sin un proyecto, y beneficio cero. La diferencia no fue la intención ni la disciplina: fue que nadie hizo la cuenta.
Tienes la prueba de las tres preguntas —cuánto cuesta hoy, cuánto costaría después, cuánto cuesta deshacerlo— más la de diagnóstico —¿mejora algo hoy?—, y una regla práctica que se deriva de ella: si una preparación solo se justifica por el futuro y no mejora nada en el presente, desconfía.
Viste los cuatro costos de Fowler —construir, retraso, carga, reparación— y que el escenario en el que anticiparse gana es uno de cuatro. Inventariaste el costo de mantener lo que nadie usa, hasta el peor de todos: que bloquea decisiones. Y conociste los cuatro casos donde invocar YAGNI es un error, con el más importante de todos: YAGNI es una herramienta para decisiones reversibles.
Antes de avanzar deberías poder: enunciar YAGNI con su matiz sin caricaturizarlo; aplicar la prueba de las tres preguntas a una propuesta concreta; y reconocer cuándo una decisión es irreversible y por lo tanto queda fuera de su alcance.
Con esto tienes las cuatro piezas del criterio: el costo, el momento, el daño de equivocarse y la motivación que lleva al error. La lección 6 las junta todas sobre un solo caso, el más extremo de todos: una arquitectura completa de plugins —interfaz, registro, carga dinámica— para algo que tiene y tendrá una implementación. Vas a ver el código entero, cómo se llegó ahí paso por paso, y el procedimiento para desmontarlo sin romper nada. Es la lección que prepara directamente el proyecto.
Recursos
- YAGNI (Martin Fowler) — la referencia. Dos páginas, con el desglose de los cuatro costos y la aclaración explícita de que el principio aplica a capacidades presuntas y no a la calidad interna.
- You're NOT gonna need it (c2 wiki) — la discusión original de la comunidad de Extreme Programming, incluida la formulación de Ron Jeffries. Documento histórico y todavía la mejor fuente sobre los matices.
- Speculative Generality (catálogo de code smells) — el nombre formal del olor que produce el incumplimiento de YAGNI, con sus refactorizaciones asociadas. El vocabulario para nombrarlo en una revisión es del módulo 7.
- The Grug Brained Developer — su sección sobre "el demonio de la complejidad" es la versión emocionalmente honesta de esta lección: por qué el impulso de construir de más es tan fuerte y por qué resistirlo se siente mal.