Tabla de Contenidos
¡Esta es una revisión vieja del documento!
18. Spec-driven development
Spec-driven development (SDD) es escribir qué tiene que hacer el software, y en qué consiste estar hecho, antes de que se escriba el código, y dejarlo escrito en un documento que vive en el repositorio y del que se deriva todo lo demás.
El cambio respecto a lo de siempre no está en que haya un documento: está en quién lo usa. Una especificación clásica se escribía, se aprobaba y se olvidaba, y la verdad acababa estando en el código. En SDD la especificación es la entrada de trabajo del agente: si no está escrita, no se implementa; y cuando el código y la especificación no concuerdan, se corrige la especificación primero. Hasta dónde se lleva esto depende del tipo de SDD.
SDD, tal y como se suele contar, no es suficiente. Vamos a verlo pieza a pieza, y cada apartado termina con dónde se queda corta esa pieza. Todos esos fallos llevan al mismo sitio: SDD centrado en la arquitectura.
1. El problema que intenta resolver
Con agentes de código, escribir código ha dejado de ser lo caro. Lo caro es decir bien qué hay que hacer. El cuello de botella se ha movido, y las prácticas de trabajo todavía no.
Los síntomas son siempre los mismos:
- Compila, pasa los tests y no es lo que pedías. El malentendido estaba en la primera frase del encargo, pero se descubre cuatrocientas líneas después.
- No hay dónde discutir el enfoque. Un diff de cuarenta ficheros es el peor sitio y el peor momento para enterarse de que la arquitectura elegida no era la que querías. A esas alturas, corregir significa tirar.
- La intención no queda en ninguna parte. El porqué de cada decisión se quedó en una conversación que se cerró. La siguiente sesión no lo tiene, la siguiente persona tampoco, y el código solo cuenta el qué.
- El agente deriva. En una sesión larga reinterpreta el objetivo por el camino, y cada reinterpretación parece razonable vista de una en una.
- No hay criterio de terminado. Sin una definición comprobable de hecho, el agente para cuando le parece que ya está, que rara vez es cuando lo está.
- El mismo encargo da resultados distintos según quién lo escriba, porque el encargo iba en un prompt improvisado y no en un documento compartido.
Todo eso es la misma causa: la ambigüedad sobrevive hasta el código, y en el código cuesta mil veces más quitarla.
| Dónde se descubre el error | Lo que cuesta corregirlo |
|---|---|
| En los requisitos | Cambiar una frase |
| En el diseño | Cambiar un párrafo y un diagrama |
| En las tareas | Reordenar una lista |
| En el código | Rehacer el trabajo, y normalmente también los tests |
| En producción | Lo anterior, más el incidente |
SDD no inventa nada de esto: es la misma vieja lección de que el error es más barato cuanto antes se pilla. Lo que cambia es que antes no compensaba escribirlo todo, porque la especificación costaba una parte importante de lo que costaba programarlo, y ahora sí, porque implementar se ha vuelto barato.
Dónde se queda corto
El diagnóstico solo mira el qué. Una especificación perfecta sigue sin decir dónde va el trabajo dentro del sistema: qué módulo lo lleva, qué se reutiliza, qué frontera no se cruza. Quiros lo resume así: la especificación le dice al agente qué construir, pero no le dice de forma fiable dónde encaja. El resultado es código que cumple la especificación, pasa los tests y estropea la arquitectura.
2. En qué consiste
El trabajo se parte en fases, cada una produce un documento, y entre fase y fase hay una persona que aprueba.
| Documento | Qué contesta | Lo que no lleva |
|---|---|---|
requirements.md | Qué tiene que pasar, para quién y cómo se comprueba | Soluciones técnicas. Aquí no se elige base de datos |
design.md | Cómo se va a hacer: arquitectura, modelo de datos, contratos, decisiones y las alternativas descartadas | Requisitos nuevos colados por la puerta de atrás |
tasks.md | El plan: pasos pequeños, ordenados y verificables uno a uno | Nada que no salga de los dos documentos anteriores |
A esos tres se añade la memoria del proyecto —lo que vale para todas las funcionalidades y no para una: convenciones, arquitectura, reglas del negocio—, que es lo que evita repetir el mismo contexto en cada especificación.
La separación entre el QUÉ y el CÓMO es la que más se incumple y la que más rinde: mezclar la solución en los requisitos cierra el abanico antes de haber mirado, y es lo que convierte una revisión de requisitos en una discusión de implementación.
Dónde se queda corto
- Un solo proceso para todos los tamaños. Böckeler probó Kiro con un bug pequeño y le salieron 4 historias de usuario con 16 criterios de aceptación. Sus palabras: un mazo para cascar una nuez.
- El diseño se decide funcionalidad a funcionalidad. Cada
design.mdelige su solución, y la arquitectura del sistema acaba siendo la suma de lo que salió en cada uno. La memoria del proyecto debería evitarlo, pero aquí es un añadido: el peso sigue en los documentos de cada funcionalidad. - El QUÉ y el CÓMO no se separan tan limpiamente. La misma Böckeler se perdía a menudo sin saber cuándo seguir en lo funcional y cuándo pasar a los detalles técnicos.
- Demasiado markdown que revisar. Es el fallo que más se nota. Scott Logic quitó de una aplicación suya una funcionalidad de unas mil líneas y la volvió a crear de dos formas: con Spec Kit y con su forma habitual, incrementos pequeños que revisa en minutos.
| Agente | Revisión humana | Markdown | Código | |
|---|---|---|---|---|
| Con Spec Kit | 33 min | 3,5 h | 2.577 líneas | 689 líneas |
| Sin especificación | 8 min | 24 min | 0 | 1.000 líneas |
Buena parte de ese markdown repetía lo ya dicho o se lo inventaba, y el contrato de un módulo medía cuatro veces lo que el propio módulo. El código no salió mejor ni con menos errores. Es un solo caso y una aplicación pequeña, pero coincide con lo que dice Böckeler: prefiere revisar código antes que todos esos ficheros.
3. Tipos de SDD
Todo SDD empieza escribiendo la especificación. Lo que cambia es qué pasa con ella después, y eso decide cuál es la fuente de verdad al final. Böckeler distingue tres niveles, cada uno construido sobre el anterior:
| Tipo | La especificación al acabar la tarea | El código lo edita | Fuente de verdad al final |
|---|---|---|---|
| Spec-first | Se tira. Es el punto de partida de esa tarea | El agente y la persona | El código |
| Spec-anchored | Se conserva y se edita con cada cambio de la funcionalidad | El agente y la persona | La especificación, y hay que mantener el código de acuerdo con ella |
| Spec-as-source | Es el fichero fuente: la persona solo edita esto | Nadie: se genera | La especificación. El código es un derivado |
Con el mismo cambio se ve la diferencia. Seis meses después hay que exportar los pedidos también a Excel:
- Spec-first: se escribe una especificación nueva solo con el cambio.
- Spec-anchored: se edita la especificación de la exportación y después se cambia el código.
- Spec-as-source: se edita la especificación y se regenera el código.
Dónde colocó Böckeler cada herramienta al probarlas en 2025:
- Kiro: spec-first. Todos los ejemplos que encontró eran para una tarea o una historia de usuario.
- GitHub Spec Kit: spec-first, aunque GitHub aspira a spec-anchored. Crea una rama por especificación, así que esta dura lo que dura el cambio, no lo que dura la funcionalidad.
- Tessl: la única que aspira a spec-anchored y explora spec-as-source. Una especificación genera un fichero de código, marcado con
GENERATED FROM SPEC - DO NOT EDIT. ==== Dónde se queda corto ==== * Spec-first: al tirar la especificación se tira también la intención. Dentro de seis meses solo queda el código, que cuenta el qué pero no el porqué. * Spec-anchored: son dos cosas que mantener de acuerdo, y nada obliga a hacerlo. * Spec-as-source: generar no es determinista. Böckeler generó varias veces desde la misma especificación, con resultados distintos, y tuvo que hacerla cada vez más concreta para que se repitiera. Además, una especificación en lenguaje natural no es un lenguaje formal: del código se puede razonar con exactitud, de ella no (Scott Logic). <note warning>Esto ya se intentó. En el desarrollo dirigido por modelos (MDD) los modelos eran la especificación y un generador sacaba el código, y nunca cuajó en aplicaciones de negocio: demasiada sobrecarga y demasiadas restricciones. Böckeler avisa de que spec-as-source, e incluso spec-anchored, pueden acabar con lo peor de los dos mundos: la rigidez de MDD y el no determinismo de los LLM.</note> —- ===== 4. Por qué encaja tan bien con los agentes ===== * Es ingeniería de contexto escrita y versionada. La especificación es exactamente el contexto que quieres que el agente tenga, en un fichero que se revisa en el pull request en vez de en un prompt que se pierde (Ingeniería de contexto). * Da un criterio de terminado comprobable, que es el requisito sin el cual un bucle no puede funcionar: un objetivo demostrable y un verificador (Ingeniería de bucles). * Es el pipeline con human-in-the-loop, aplicado al desarrollo: pasos fijos, puerta entre paso y paso, y la persona en la puerta y no en cada línea. * Cambia lo que revisas. En teoría, una página de requisitos en vez de dos mil líneas de diff a las que todo el mundo acaba dando al botón verde. * Las tareas trocean el trabajo en piezas que caben. Cada tarea es un encargo pequeño y acotado, que es justamente donde un agente acierta; el encargo grande y vago es donde se pierde. * La especificación es reutilizable. La promesa es que el mismo documento sirve para volver a generar el código con otro modelo o para retomar dentro de seis meses. ==== Dónde se queda corto ==== * Falsa sensación de control. Tener la especificación no significa que el agente la cumpla. Böckeler vio a menudo que no seguía todas las instrucciones, y otras veces que se pasaba de celo con una de ellas. * Duplicados. En su prueba con Spec Kit, el análisis previo describía clases que ya existían. El agente tomó esas descripciones como especificación nueva y las generó otra vez. * Una instrucción no es un guardarraíl. La especificación es texto y el agente se la puede saltar, igual que cualquier otra instrucción (ver las capas del harnés). Que sea más larga no la hace más obligatoria. * La misma especificación no da el mismo código. Böckeler lo comprobó con Tessl generando varias veces desde la misma especificación. Sirve para no perder la intención, no para regenerar el sistema. —- ===== 5. Lo que SDD no es ===== * No es cascada. El ciclo es por funcionalidad pequeña, no por proyecto: se especifica lo que se va a hacer esta semana, no el sistema entero. Y se vuelve atrás: cuando la implementación demuestra que el diseño estaba mal, se corrige el diseño y se sigue, que es justo lo que la cascada no permitía. * No es documentación. Un documento que nadie lee ni ejecuta es papel. La especificación quiere mantenerse viva porque es la entrada del agente. * No es escribir más, es escribir antes. Lo que se quiere ahorrar es el trabajo que había que rehacer. * No sustituye al criterio. Las puertas de aprobación valen lo que valga la lectura: aprobar los requisitos sin leerlos es peor que no tener puerta, porque da sensación de control sin el control. ==== Dónde se queda corto ==== * La especificación también deriva. Terminado el cambio, el código sigue evolucionando y nadie obliga a actualizar el documento. Que pasen los tests no garantiza que especificación y código digan lo mismo (Grabowski). * No todo arreglo es un cambio de especificación. En la prueba de Scott Logic falló una variable sin rellenar. Siguiendo SDD había que aclarar la especificación y repetir, pero en la especificación no había nada que aclarar. * Se parece a la cascada más de lo que admite. Sobre el papel, todo son funcionalidades pequeñas; en la práctica, Böckeler observa que los paquetes de trabajo pequeños casi van contra la idea de SDD, y Scott Logic se encontró con horas de revisión antes de ver funcionar nada. —- ===== 6. Cuándo compensa ===== ^ Compensa ^ No compensa ^ | Funcionalidad que toca varios ficheros | Un arreglo de una línea | | Trabajo que dura más de una sesión | Un script de usar y tirar | | Más de una persona implicada | Un prototipo que se va a tirar | | Dominio con reglas de negocio que no se deducen del código | Cambios mecánicos y evidentes | | Código que va a vivir años | Explorar: cuando todavía no sabes qué quieres | La regla corta: si el encargo cabe en una frase sin ambigüedad, escribirlo dos veces es ceremonia. Y si no sabes lo que quieres, primero se explora —a mano, con prototipos que se tiran— y se especifica después, con lo aprendido; especificar no es un método para averiguar qué quieres. ==== Dónde se queda corto ==== * La tabla no aguanta el caso real. Lo de Scott Logic eran 14 ficheros, así que caía en la columna de «compensa», y no compensó. * El tamaño adecuado no está claro. A Böckeler una historia de 3 a 5 puntos también le pareció excesiva para el proceso, y duda de que sirva para funcionalidades grandes y poco definidas. Queda una franja estrecha. * Peor en código existente. Según Böckeler, dos de las tres herramientas que probó cuestan todavía más de introducir en un proyecto que ya existe, y ese es el caso normal. El motivo de fondo es que la unidad de SDD es la funcionalidad, y lo que se estropea es el sistema. —- ===== 7. Un ejemplo de por qué hace falta ===== La petición, tal y como llega: <sxh markdown> hay que poder exportar los pedidos </sxh> Ahí hay cinco decisiones escondidas, y el agente va a tomar las cinco por su cuenta sin avisar: * ¿En qué formato? * ¿Qué pedidos: todos, los del usuario, los que su rol puede ver? * ¿Cuántos? Diez y diez millones no se resuelven igual. * ¿En el momento, o se genera y se avisa al terminar? * ¿Qué pasa si no hay ninguno? Contestarlas cuesta cinco minutos por delante. Descubrirlas por detrás cuesta rehacer la funcionalidad, y encima con la sensación de que el agente «ha hecho algo raro» cuando lo que hizo fue rellenar los huecos que le dejamos. Escrito como requisito queda comprobable, que es lo único que le pedimos: <sxh markdown> Cuando un usuario solicita la exportación de pedidos, el sistema DEBERÁ generar un fichero CSV con los pedidos visibles para su rol. Si la consulta supera los 10.000 pedidos, el sistema DEBERÁ generarlo en segundo plano y avisar por correo al terminar. Si no hay ningún pedido, el sistema DEBERÁ informar de ello y no generar ningún fichero. </sxh> Esa forma de escribir —cuando pasa esto, el sistema deberá hacer esto otro— es el formato EARS, y no es un capricho de estilo: obliga a nombrar la condición que dispara cada comportamiento, que es exactamente donde se esconden los casos que nadie había pensado. Se ve en detalle en Kiro. ==== Dónde se queda corto ==== El requisito está bien escrito y aun así deja otros huecos, estos de arquitectura: * ¿En qué módulo va? Nada impide que el agente meta la exportación en el controlador de pedidos. * «Visibles para su rol»: ¿reutiliza la comprobación de permisos que ya existe o escribe otra? * «En segundo plano»: ¿usa la cola de trabajos del proyecto o monta un hilo por su cuenta? * «Avisar por correo»: ¿pasa por el módulo de notificaciones o llama directamente al servidor de correo? El agente puede cumplir los tres requisitos al pie de la letra con la peor respuesta a las cuatro preguntas, y todos los tests pasarán. Además, no son preguntas de esta funcionalidad: valen para todas, así que no tiene sentido contestarlas en cada especificación. —- ===== 8. SDD centrado en la arquitectura ===== Todos los fallos anteriores vienen de lo mismo: SDD pone el peso en el documento de cada funcionalidad. La solución es darle la vuelta y poner el peso en la arquitectura. SDD centrado en la arquitectura es una variante del desarrollo guiado por especificaciones en la que el documento principal no describe el comportamiento de cada funcionalidad, sino la estructura del sistema: fronteras, interfaces, responsabilidades y decisiones técnicas. La persona define esa arquitectura antes de generar código y la IA se limita a implementarla. No es un nombre establecido, sino una etiqueta descriptiva para un enfoque que cada autor llama de una forma: Layered Generation (Djukic), Spec-driven Development (Chambers), Spec Growth Engine (Grabowski) o Architecture Driven Development (Quiros). ==== El flujo ==== Los dos primeros documentos son persistentes: se guardan en el repositorio y sirven de contexto en cada tarea. -ARCHITECTURE.mdVISION.md: qué es el sistema y qué no es. Una página. -ARCHITECTURE.md: componentes, fronteras, responsabilidades y decisiones. Lo escribe la persona. - Tareas o issues pequeños: cada uno abarcable en una sola interacción con la IA. - Implementación: un issue por sesión. El agente lee los dos documentos y el issue. - Validación: cada resultado se comprueba con tests y contra la arquitectura. Si falla, primero hay que preguntarse de quién es el error: si el issue estaba mal, se corrige el issue; si no, se le pide al agente que arregle ese problema concreto. - Revisión de la deriva: periódicamente se comparan código y arquitectura. Si el código se ha desviado, se corrige; si la implementación ha descubierto algo nuevo, se actualiza la arquitectura. ==== El ejemplo, resuelto ==== Las cuatro preguntas de la exportación se contestan una sola vez y valen para todas las funcionalidades: <sxh markdown;title:ARCHITECTURE.md> ## Módulos - pedidos: dominio de pedidos. No conoce a los demás módulos. - informes: exportaciones. Lee los pedidos solo con PedidoQueryService. - notificaciones: el único módulo que envía correo. ## Reglas - Los permisos por rol se comprueban con PermisosService. - Lo que dure más de 30 segundos va a la cola de trabajos. - Los controladores no tienen lógica: llaman a un servicio y responden. </sxh> Y lo que queda por escribir de la funcionalidad es poco: <sxh markdown;title:Issue 142> Exportar pedidos a CSV en el módulo informes. - Solo los pedidos visibles para el rol del usuario. - Más de 10.000 pedidos: en segundo plano y aviso por correo al terminar. - Sin pedidos: se informa y no se genera fichero. Tests: uno por cada caso. </sxh> Lo bueno de SDD no se tira: las cinco decisiones siguen contestadas y por escrito antes de empezar. Lo que desaparecen son los tres documentos por funcionalidad. ==== Antes de implementar: el diseño por niveles ==== Sin un punto de control, el primer sitio donde ves las decisiones del agente es el código, que es el más caro. Por eso, en un cambio que no sea trivial, el diseño se acuerda de lo abstracto a lo concreto, un nivel cada vez (Garg): - Capacidades: qué tiene que hacer y qué queda fuera. - Componentes: qué módulos y servicios intervienen. - Interacciones: cómo se comunican. - Contratos: interfaces, tipos y esquemas. - Implementación: el código, solo cuando lo anterior está aprobado. <sxh markdown> Diseña esto por niveles: capacidades, componentes, interacciones y contratos. Presenta cada nivel por separado y espera mi aprobación antes de pasar al siguiente. No escribas código hasta que los contratos estén acordados. </sxh> No siempre hacen falta los cinco: una utilidad empieza en los contratos, un único componente en los componentes y una funcionalidad con varios componentes en las capacidades. <note>Esto es una conversación y no deja documento. Lo que valga para más de un cambio se pasa a; lo demás, al issue.</note> ==== Qué fallo arregla cada cosa ==== ^ Fallo de SDD ^ Cómo se resuelve ^ | La especificación no dice dónde va el trabajo |ARCHITECTURE.mdlo dice para todas las funcionalidades | | El mismo proceso para cualquier tamaño | La especificación de cada cambio es un issue, tan corto como el cambio | | El diseño se decide funcionalidad a funcionalidad | La arquitectura se decide antes, y la decide una persona | | Demasiado markdown que revisar | Dos documentos que cambian poco. Lo que se revisa cada vez es el código de un issue | | El agente se salta las instrucciones | Tarea pequeña y validación contra la arquitectura. Las fronteras se comprueban con una herramienta, como ArchUnit (tema 14), no confiando en que el agente las lea | | La especificación deriva | La deriva se revisa de forma explícita, y Grabowski propone automatizarlo para que bloquee el merge | ==== Cómo encaja en los niveles de Böckeler ==== Con los tipos de SDD de Böckeler, aquí se usan dos: * Documentos de arquitectura: spec-anchored, porque se conservan y se mantienen. * Issues: spec-first, porque se usan para una tarea concreta. Con su terminología, esos documentos se parecen más al memory bank que a una especificación por funcionalidad: el contexto del sistema pesa mucho y la especificación de cada cambio es ligera. ==== Lo que no resuelve ==== * Los criterios de aceptación no tienen documento propio. Si no los escribes en el issue, no los escribe nadie. Es lo que se paga por quitar la burocracia de Kiro en los cambios pequeños. * Código existente. Djukic solo lo muestra en un proyecto nuevo y pequeño, sin explicar cómo aplicarlo a un sistema ya existente. Quiros propone empezar modelando lo que ya hay. * Hay que saber de arquitectura. La IA implementa lo que le das: Djukic avisa de que funciona sobre todo a quien ya sabe construir sistemas en producción. * Está poco medido. Hay casos de un solo autor, como las 8.000 líneas de Go en unas 5 horas de Djukic, sin comparación con otra forma de trabajar. —- ===== 9. Resumen ===== * El cuello de botella ya no es escribir código: es decir bien qué hay que hacer. * SDD saca la ambigüedad del código y la pone en un documento: requisitos (el QUÉ) → diseño (el CÓMO) → tareas → implementación, con una persona aprobando en cada salto. * Según lo que pasa con la especificación después, SDD es spec-first, spec-anchored o spec-as-source: la fuente de verdad acaba siendo el código o la especificación. * Solo eso no basta: no dice dónde va el trabajo, genera más markdown del que se puede revisar, el agente puede ignorarlo y el documento deriva. * Sí a especificar antes, pero con el peso en la arquitectura:VISION.mdyARCHITECTURE.mdlos escribe la persona, cada cambio es un issue pequeño y lo que implementa la IA se valida con tests y contra la arquitectura. Cómo se hace SDD con herramientas concretas —OpenSpec, GitHub Spec Kit, BMAD y Kiro— es el tema 19. ===== Más información ===== * The Architecture-First Approach (Petar Djukic, 2026): el método paso a paso, conVISION.md,ARCHITECTURE.mde issues. * Understanding Spec-Driven-Development: Kiro, spec-kit, and Tessl (Birgitta Böckeler, 2025): los niveles de SDD y qué falla al probar las herramientas. * Putting Spec Kit through its paces (Scott Logic, 2025): la comparación con cifras de Spec Kit frente a incrementos pequeños. * Design-First Collaboration (Rahul Garg, 2026): los cinco niveles de diseño antes de escribir código. * Chamber of Tech Secrets #54: Spec-driven Development (Brian Chambers, 2025): un flujo real conarchitecture.mdytasks.md''. * The Spec Growth Engine (Hartwig Grabowski, 2026): cómo hacer que la deriva bloquee el merge. * Architecture Driven Development: Why SDD Needs More Context (Guillermo Quiros, 2026): por qué SDD es necesario pero no suficiente.
