El costo del que YAGNI nunca habló
(newsletter.kentbeck.com)- YAGNI no es una simple regla de ahorro de “no escribas código que todavía no necesitas”, sino un principio que trata el costo de adelantarse a la estructura por suposición antes de que la necesidad esté confirmada
- El centro del problema no es el diseño en sí, sino cuándo diseñar, y estructurar demasiado pronto puede ser tan riesgoso como estructurar demasiado tarde
- La estructura anticipada genera tanto un costo de opcionalidad que cierra alternativas antes de que llegue la información, como un costo de NPV al adelantar costos y retrasar beneficios
- Aunque el costo de generar código se acerque a 0, YAGNI no desaparece; al contrario, la generación barata puede facilitar aún más la creación de frameworks basados en suposiciones
- La conclusión de construirlo cuando haga falta no se debe al costo de escribir código, sino a que el valor de la opcionalidad no ejercida y del dinero no gastado sigue existiendo
YAGNI no prohíbe diseñar
- YAGNI, sigla de “You Aren’t Gonna Need It”, no es una excusa para no diseñar nunca nada que no sea estrictamente necesario
- Si hace falta algo, se construye, pero el punto clave es el momento
- El punto de partida es una anécdota repetida en proyectos: ante situaciones como “en 3 semanas una implementación simple ya no alcanzará, así que quiero hacer algo más complejo desde ahora”, la respuesta que se repetía era “You aren’t going to need it”
- Este principio considera riesgoso tanto crear estructura demasiado pronto como hacerlo demasiado tarde
El problema no es el costo de escribir código, sino la estructura basada en suposiciones
- Una interpretación común ve YAGNI como una regla de ahorro: “no escribas código que todavía no necesitas porque es caro”
- Pero el verdadero objetivo de YAGNI no es el costo de producir código, sino la estructura especulativa (speculative structure) creada por adelantado antes de que una funcionalidad real la necesite
- Ese tipo de estructura genera dos clases de costo, en momentos y por razones distintas
Primer costo: la opcionalidad
- Si construyes estructura antes de que llegue la funcionalidad, terminas comprometiéndote por suposición frente a requisitos que todavía no conoces
- La funcionalidad para la que te preparaste de antemano suele ser distinta de la que finalmente llega, y como resultado pagas dos veces
- el costo de rodear una estructura con la forma equivocada
- el costo de desarmar esa estructura y rehacerla
- El problema no se limita a decir simplemente “predecir es difícil”
- Incluso si la suposición resulta correcta, sigues perdiendo por haber renunciado a la opción de no comprometerte antes y construir luego la estructura correcta
- Esperar no es pereza, sino conservar un activo llamado opcionalidad
Segundo costo: NPV
- Así como el dinero tiene valor en el tiempo, las funcionalidades también tienen valor temporal
- Si hoy construyes estructura para una funcionalidad que recién hará falta en 3 meses, adelantas el costo y retrasas la salida de las funcionalidades que sí generan dinero
- Este costo existe incluso si la suposición fue correcta
- Ni una predicción perfecta cambia el orden entre costos y beneficios; la pérdida aparece en el intervalo donde los costos se ubican antes que los beneficios
- El costo de opcionalidad trata de “no te comprometas antes de que llegue la información”, y el costo de NPV trata de “no pagues antes de que sea necesario”
- Incluso frente al argumento de que “más tarde será demasiado caro corregirlo”, esa remodelación costosa también puede ser otra predicción
YAGNI sigue vigente aunque generar código sea barato
- Ninguno de estos dos costos incluye el costo de tipear código
- Si el costo de escribir código se acerca a 0, entonces se derrumba la interpretación ahorrativa de YAGNI de “como el código era caro, no lo hagas antes de tiempo”
- Pero como YAGNI no es una regla de ahorro, la generación barata de código no lo invalida
- El costo de opcionalidad no nace de la cantidad de esfuerzo, sino del compromiso que cierra opciones futuras
- El costo de NPV no surge del precio de producción, sino del momento del flujo de caja
- La generación gratuita no debilita a YAGNI; de hecho, puede hacer todavía más fácil crear frameworks basados en suposiciones
- La estructura generada sigue produciendo los dos costos y, como no fue escrita directamente, la comprensión de ella puede ser menor
- La conclusión no es “espera porque el código es caro”, sino que la opcionalidad y el dinero valen más cuando aún no se han usado, así que constrúyelo cuando haga falta
1 comentarios
Opiniones en Hacker News
Creo que el costo de cambiar la estructura también bajó
Gracias a la IA, se redujo el costo de reforzar el comportamiento con pruebas antes de cambiar la estructura, y también bajó el costo de implementar migraciones sin interrupciones
Una de las grandes razones por las que Rust llamó la atención, incluso antes de la IA, era que el costo de cambiar la estructura interna de una aplicación era bajo, y ahora lo es aún más
El costo de oportunidad de no poder cambiar la estructura de forma segura aumentó mucho, y hoy se optimiza ante todo por la capacidad de cambiar grandes partes del código y del producto de manera rápida y segura
Pero antes de la IA los cambios estructurales tomaban mucho más tiempo, así que también podría verse como que el valor de aquello por lo que ahora se busca optimizar en realidad bajó
Sigue siendo valioso, pero quizá un poco menos que antes
Con el aumento de pruebas generadas por IA que son frágiles, el costo de cambiar la estructura es mayor que antes
Ordenar un conjunto de pruebas para que verifique la esencia del problema y no decisiones de diseño accidentales es algo que la IA todavía no hace bien
Pero también es demasiado fácil, sin hacer eso, terminar con un conjunto de pruebas frágil que está más o menos al 75%
Mucha gente se conforma considerando una mejora objetiva pasar de “unas pocas pruebas mediocres y frágiles escritas por humanos” a “muchas pruebas mediocres y frágiles escritas por IA”
Estoy completamente de acuerdo con usar las herramientas de esta manera, pero de ahí a decir que ya no hay que preocuparse por construir castillos en el aire equivocados demasiado pronto hay un trecho
Un contrato de pruebas perfecto que resista la refactorización sigue siendo bastante difícil de diseñar
Lo viejo volvió a sentirse nuevo
Desde la eficiencia contextual de enfoques como DDD o arquitectura limpia hasta puntos como estos, la IA no crea nuevas compensaciones, sino que actúa como un amplificador
Aumenta la productividad de los equipos que hacen las cosas bien, y también aumenta la deuda de los equipos con estándares bajos de diseño y arquitectura
Lo único que se obtiene es no tener que pensar en profundidad
Pensar en profundidad no requiere tanto tiempo ni esfuerzo, así que quienes usen la IA igual pero piensen lo suficiente para no hacer trabajo inútil les van a sacar ventaja
Kent Beck compara el código que aún no se escribió con una opción financiera que se puede comprar a un precio determinado
Pero eso no deja de ser una analogía, y si se la lleva demasiado lejos se vuelve rara
Si no escribiste nada de código, ¿tus opciones son infinitas? Aunque todavía no hayas invertido tiempo, eso no parece correcto
También podría servir como argumento para quedarse en la etapa de planificación y posponer indefinidamente la escritura de código con tal de no fijar nada
Aun así, si la analogía funciona, el costo podría estar en leer el código
El código no escrito no necesita leerse, y si usas agentes de programación, tampoco ensucia el contexto con detalles irrelevantes
El código que aún no se escribió tampoco necesita probarse, y las pruebas que aún no se escribieron no consumen tiempo de ejecución
Por eso conviene mantener el proyecto lo más pequeño posible, y al postergar funcionalidades se puede retrasar al máximo el crecimiento de la base de código
También implica que ejecutar código de terceros puede evitar muchos costos
Si puedes usar una API estándar, no necesitas entender la implementación en detalle ni ejecutar sus pruebas, aunque agregar dependencias tiene riesgos
El código no escrito no tiene valor
Para que el código escrito hoy cree valor, tiene que resolver la solicitud o el issue de hoy, o estar orientado a facilitar algo mañana
Si contraes deuda técnica con una solución hacky o pierdes tiempo en algo que contradice YAGNI, no estás creando valor
Lo importante no es el código no escrito, sino el código que se escribirá en adelante y su propósito
Hay que hacer la compensación correcta entre resolver el ticket o la tarea de hoy y no pegarse un tiro en el pie en el futuro
Escribir código es un compromiso: el valor de hoy se ve, pero el de mañana es más una estimación
Aun así, como siempre habrá costos que pagar más adelante, terminas estimando para anticipar qué hará falta y minimizar esos costos
Creo que no se enfatizan lo suficiente las mejores prácticas de la era de la IA, pero hay una parte que Kent pasa completamente por alto
Hay un valor considerable en descubrir más rápido qué funcionalidades se necesitan
Crear una estructura especulativa puede funcionar como un mecanismo que obliga a concretar los requisitos, o al menos empieza a revelar cómo fallan las cosas
Como puede ser más caro que esperar, no debería hacerse para la mayoría de los requisitos, pero a veces puede ser la mejor opción
El costo de construir lo incorrecto ahora es mucho menor, así que el cálculo alrededor de YAGNI también cambia
Aun así, sigue siendo necesario hacer el cálculo, y ahora cada equipo debe averiguar por sí mismo cómo cambió en su caso
Si no la descartas, se convierte en un mecanismo que obliga a producir un resultado desordenado
YAGNI es el problema de construir algo que no está en los requisitos actuales porque se espera que los requisitos cambien después
No es lo mismo que concretar los requisitos y restricciones actuales
Esas cosas suelen surgir de conversaciones con stakeholders, usuarios y clientes, de recursos, y de restricciones y capacidades de ingeniería
Un prototipo tiene valor cuando se conversa con stakeholders, se crea un modelo de gestión de proyecto o se hace investigación de ingeniería
Fuera de eso, es poner el carro delante de los caballos
El enfoque de ver el software en ejecución como un activo es correcto
Sin embargo, el costo de ejecutarlo y volverlo a crear bajó mucho
El costo que no bajó es el de romper la cadena de confianza en resultados predecibles
Una versión específica de software en ejecución ha ido acumulando confianza, y si se reescribe desde cero, ese capital se reinicia al momento del lanzamiento
En algún momento me cambió la forma de pensar
Empecé a posponer lo concreto con YAGNI y a escribir, en la medida de lo posible, una versión abstracta
¿Hacer un UserStore? Parece lo más simple, pero quizá no haga falta una forma específica llamada User
Entonces hago un Store que pueda contener cualquier cosa almacenable
Si no estás acostumbrado, puede parecer sobreingeniería y un revoltijo de genéricos, pero paradójicamente es la forma que menos compromisos asume con cualquier implementación concreta
No solo hiciste una interfaz UserStore que probablemente no hacía falta, sino también una abstracción Store generalizada que definitivamente no hacía falta
Para no comprometerte con una implementación concreta, implementaste capas pegajosas que no necesitas y que probablemente tampoco necesitarás en el futuro
Si es una abstracción que no se basa en una necesidad real, aunque más adelante haga falta, es muy probable que la hayas hecho casi mal
Al final seguramente vas a necesitar UserStore, así que eso era lo primero que debías hacer
No estoy de acuerdo con “no es un argumento de que la predicción sea difícil, como si un arquitecto más agudo pudiera evitarlo”
Ese argumento solo se sostiene si parte de la premisa de que predecir es difícil
Si preparas de antemano la base para una funcionalidad muy probable y todo encaja, lanzas más rápido
No hay garantía de que el equipo necesariamente crezca ni de que se mantenga la cantidad de gente, así que me parece peor felicitarse por la moderación que andar corriendo a último momento para cumplir con YAGNI
Hace poco tuve que salir funcionalmente de una base de código con muchísimo YAGNI acumulado, y aun con agentes fue un trabajo enorme
En un sistema distribuido, ¿cómo sabes qué está realmente en uso? Hubo cosas que se me escaparon a mí y cosas que se le escaparon al agente, y todo tardó más de lo necesario
No fue simplemente una migración 1:1; lo tomamos como una oportunidad para simplificar, así que había que entender por completo cómo funcionaba el sistema viejo
Incluso cosas que en realidad no se usaban para nada entraban en lo que había que entender si no las identificábamos como tales
Creo que al final todo se reduce a explorar el problema e implementar una solución
Siempre hay un costo por resolver el problema equivocado, y también hay un costo por implementar una mala solución para algo que ni siquiera se necesita
A veces el desarrollo de software puede terminar siendo simple prueba y error en lugar de pensar en la estrategia y el conjunto de problemas que conviene explorar
Hay casos en los que explorar un problema más a fondo en cierta dirección de lo necesario ayuda a largo plazo, pero implementar soluciones sin propósito nunca es bueno
Creo que lo que Kent Beck realmente critica es la actitud de implementar algo “por si acaso” porque tal vez haga falta en el futuro
Dijo que “si construyes la estructura antes de que llegue la funcionalidad, te comprometes con una conjetura”, pero creo que en cualquier caso se hace una conjetura
Puede ser muy probable que llegue la funcionalidad, pero no es seguro
Si no construyes la estructura ahora, hay un costo de refactorización; si la construyes demasiado pronto y la funcionalidad no llega, desperdicias esfuerzo
¿Cuáles son los costos, probabilidades y compromisos entre esas posibilidades? Obviamente depende del contexto
Todo YAGNI es, intencionalmente, una gran generalización
Al final depende de las circunstancias
En cualquiera de los dos lados suele haber muchas conjeturas y explicaciones a mano alzada, y es el mismo problema que con estimaciones de trabajo confiables
Algunos desarrolladores que no toleran bien un mundo incierto intentan encontrar reglas en blanco y negro para todo
https://www.sebastiansylvan.com/post/the-perils-of-future-co...
En resumen, se pone del lado de YAGNI
No he visto en los textos de Kent Beck nada que pudiera ser útil para una empresa de chips
En una empresa de chips, mucha gente tiene que trabajar durante mucho tiempo, los clientes no pueden ver nada hasta que esté terminado, y para ganar dinero hay que vender en unidades de millones
El hardware tiene restricciones fuertes
De hecho, el software se inventó precisamente para escapar de esas restricciones
Es verdad que muchas empresas de chips no comparten el trabajo en curso, pero se pueden compartir simulaciones, prototipos y muestras de ingeniería, y de hecho ocurre
Claro que normalmente tiene que tratarse de un cliente grande
Las ideas de una industria donde el costo del cambio es relativamente bajo no se aplican fácilmente a una industria donde el costo del cambio es alto, y lo contrario también suele ser cierto
¿Cómo planifican esos proyectos las empresas de chips? ¿Agile, cascada, o usan un framework distinto al de la industria del software?