Spec-Driven Development: deja de pedirle 'un botón azul' a la IA
"Créame un botón azul que envíe el formulario." Le das esa instrucción a un agente de IA y casi siempre te devuelve algo. Un botón. Azul. Que probablemente envía el formulario. El problema no es lo que pediste, es todo lo que no pediste: dónde vive el botón, qué pasa mientras la petición está en curso, qué muestra si falla, si funciona con teclado. La IA no deja esos huecos vacíos, los rellena con suposiciones.
Y ahí empieza el baile: "no, así no", "ahora cámbiame el color", "falta el estado de carga", "¿por qué se borró lo que escribí?". Corriges, regeneras, corriges otra vez. Terminas dirigiendo a la IA decisión por decisión, después de que ya escribió el código, que es el momento más caro para corregir.
Spec-Driven Development es la idea opuesta: defines bien qué quieres antes de pedir el código, no después. Suena obvio, pero cambia por completo el resultado cuando programas con IA. Vamos a verlo.
El problema: un prompt vago delega tus decisiones
Cada prompt es, en el fondo, una especificación. La diferencia es cuánto dejas sin decir. Cuando pides "un botón azul", estás delegando en la IA un montón de decisiones que en realidad son tuyas:
- ¿En qué pantalla y en qué parte del layout va?
- ¿Qué hace exactamente al hacer click? ¿A qué endpoint llama?
- ¿Se deshabilita si el formulario está incompleto?
- ¿Qué pasa mientras la petición está en curso? ¿Y si falla?
- ¿Conserva lo que el usuario escribió o lo borra?
- ¿Es accesible por teclado y para lectores de pantalla?
La IA va a responder todas esas preguntas igual, las hayas hecho o no. Solo que las responde con defaults genéricos, no con lo que tu proyecto necesita. Un prompt vago no produce menos decisiones, produce decisiones que no tomaste tú.
¿Qué es Spec-Driven Development?
Spec-Driven Development (desarrollo guiado por especificaciones) es escribir el qué y el porqué antes de pedir el cómo. La especificación es la fuente de verdad; el código es un derivado de ella. En vez de tratar el prompt como una orden suelta, lo tratas como una especificación: contexto, comportamiento esperado, restricciones y criterios para saber que está listo.
No es una idea nueva. Las especificaciones existen desde mucho antes que la IA. Lo nuevo es que ahora el spec es el input principal del agente: lo que escribas ahí es, literalmente, lo que va a construir. Mientras más claro el spec, menos espacio para que la IA improvise.
La analogía más simple es contratar a alguien para construir algo. Decir "hazme una casa" y decir "aquí está el plano" pueden terminar en una casa, pero solo uno de los dos termina en tu casa. El spec es el plano.
Antes vs después: el mismo botón, dos resultados
Veámoslo concreto. Este es el prompt vago de siempre:
text
Create a blue button that submits the form.Y este es el mismo pedido, pero como spec. Fíjate que no es más largo por gusto: cada línea cierra una de las decisiones que antes quedaban al azar.
markdown
# Spec: submit button for the contact form
## Goal
Let the user send the contact form on /contact and get clear feedback.
## Behavior
- Disabled while any required field is empty.
- On click: switch to "loading" state and call POST /api/contact.
- On success: show a confirmation message and clear the form.
- On error: show the error message and keep the typed data.
## Constraints
- Reuse the existing <Button> component. Do not add new libraries.
- Match the current form's design tokens (no hardcoded colors).
## Acceptance criteria
- Keyboard accessible (focusable, activates with Enter/Space).
- aria-busy="true" while loading.
- The form data survives a failed request.El segundo prompt no le pide a la IA que adivine nada importante. Le da el contexto, le marca los límites ("reusa el componente que ya existe, no agregues librerías") y, sobre todo, le dice cómo se ve "terminado". El resultado llega bien a la primera mucho más seguido, y cuando no, ya tienes una lista contra la cual revisar.
Anatomía de un buen spec
No necesitas un documento formal de diez páginas. Un buen spec, incluso corto, cubre cuatro cosas:
- Objetivo y contexto: qué problema resuelve y por qué, dónde encaja.
- Comportamiento esperado: entradas, salidas y los casos que importan (éxito, error, vacío).
- Restricciones: el stack, los patrones a seguir y, muy importante, lo que NO se debe hacer.
- Criterios de aceptación: cómo sabes, de forma verificable, que está listo.
Una plantilla mínima que puedes copiar y llenar antes de pedir cualquier feature:
markdown
# Spec: <nombre de la feature>
## Goal
<qué problema resuelve y para quién>
## Behavior
- <caso normal>
- <caso de error>
- <caso límite / vacío>
## Constraints
- <stack, patrones a seguir, qué NO hacer>
## Acceptance criteria
- <condición verificable 1>
- <condición verificable 2>Los criterios de aceptación son la parte que más se olvida y la que más rinde: son lo que después te (y le) permite responder "¿ya está?" sin discutir.
Del spec al plan de ejecución
El spec dice qué quieres. El siguiente paso es convertirlo en un plan de ejecución: descomponer ese qué en tareas concretas, ordenadas y pequeñas que el agente va a ejecutar una por una. La regla de oro es que cada tarea sea chica (de dos a cinco minutos de trabajo) y verificable por sí sola.
¿Por qué este paso intermedio? Porque revisar un plan de texto es barato y revisar ocho archivos ya escritos es caro. Si algo está mal pensado, lo ves en el plan y lo corriges ahí, antes de que se escriba una sola línea de código.
markdown
# Plan: submit button for the contact form
## Tasks
1. Create the SubmitButton component (disabled/loading states).
2. Wire the submit handler to POST /api/contact.
3. Handle the success response (confirmation message + clear form).
4. Handle the error response (show error, keep typed data).
5. Accessibility pass (keyboard focus, aria-busy on loading).
## Verification
- Run the form manually: empty, success, and failure paths.
- Check focus order and aria-busy with the dev tools.Cómo el agente sabe qué falta
Acá está la pieza que el plan vuelve realmente útil: el plan no es estático, lleva el estado de cada tarea. La forma más simple es una lista de checkboxes que el agente marca a medida que termina. Con eso, en cualquier momento se ve de un vistazo qué está hecho (
[x]) y qué falta ([ ]).Así se ve el mismo plan a medio ejecutar:
markdown
# Plan: submit button for the contact form
## Tasks
- [x] 1. Create the SubmitButton component (disabled/loading states)
- [x] 2. Wire the submit handler to POST /api/contact
- [ ] 3. Handle the success response (message + clear form) <- next
- [ ] 4. Handle the error response (show error, keep typed data)
- [ ] 5. Accessibility pass (keyboard focus, aria-busy on loading)
## Status
Done 2/5. Resume at task 3.Esto resuelve dos problemas a la vez. El primero es de continuidad: si se corta la sesión, se llena la ventana de contexto o vuelves al día siguiente, el agente (o tú) lee el plan, ve que va en la tarea 3 y retoma exactamente desde ahí, sin rehacer ni saltarse nada. El segundo es de visibilidad: no tienes que adivinar en qué punto está el trabajo, está escrito.
El plan es tu seguro contra la pérdida de contexto
Mantener el plan con su estado en un archivo (no solo en la conversación) hace que el trabajo sea durable. Una nueva sesión empieza leyendo el plan: qué se hizo, qué falta y dónde retomar. Es la diferencia entre "perdí el hilo" y "sigo en la tarea 3".
Por qué funciona mejor con IA
- Menos ciclos de corrección: defines bien una vez en vez de corregir diez veces después.
- Revisión barata: es más fácil arreglar un párrafo del spec que ocho archivos ya generados.
- Intención documentada: el spec deja registro de por qué se hizo algo, no solo de qué se hizo.
- Autoverificación: con criterios de aceptación claros, la IA puede revisar su propio trabajo contra ellos.
- Trabajo durable: spec y plan sobreviven a la sesión; cualquiera retoma sin contexto previo.
Spec-driven no es escribir una novela
Importante para no caer en el otro extremo: no todo cambio necesita un spec formal. Corregir un typo, ajustar un margen o renombrar una variable no amerita un plano. Escribir un spec de tres párrafos para un cambio de una línea es burocracia, no disciplina.
La regla práctica es escalar el rigor al tamaño y al riesgo del cambio. Cuanto más grande es la feature, cuantos más archivos toca y más decisiones de diseño implica, más vale la pena escribir el spec y el plan antes. Para lo trivial, un buen prompt directo alcanza.
Escala el proceso al cambio
Para una feature que toca varios archivos: spec, plan con checkboxes, ejecución. Para un cambio cosmético de un archivo: un prompt claro y listo. La estructura está para cuando la necesitas, no para frenar lo simple.
Cómo empezar hoy
No hace falta ninguna herramienta especial para empezar. Antes de pedirle código a la IA, escribe un párrafo: objetivo, comportamiento, restricciones, cómo sabrás que está listo. Solo eso ya cambia la calidad de lo que recibes. Después puedes pedirle que convierta ese spec en un plan de tareas con checkboxes y que lo vaya marcando mientras avanza.
Si quieres que el proceso sea más sistemático, hay frameworks que lo estructuran de punta a punta (lluvia de ideas, spec, plan, ejecución con seguimiento de tareas). Escribí sobre uno de ellos acá: Superpowers: el framework que cambió cómo programo con IA. Y si quieres el panorama más amplio de cómo sacarle provecho a la IA al programar (agentes, tools y buenas prácticas), está Codeando con IA: agentes, skills y buenas prácticas.
Para terminar
El spec es donde piensas; el código es donde la IA ejecuta. Cuando inviertes los cinco minutos de escribir bien qué quieres, no estás siendo lento: estás moviendo las decisiones al punto más barato para corregirlas. El botón azul vago y el spec del botón pueden tardar lo mismo en generarse, pero solo uno de los dos llega a lo que de verdad necesitabas.
La IA amplifica tu claridad o tu ambigüedad
Un spec claro produce código que se acerca a lo que querías. Un prompt vago produce código que se acerca a lo que la IA supuso. La herramienta es la misma; lo que cambia es cuánto pensaste antes de pedir. Tu criterio sigue siendo lo que decide el resultado.