Desarrollo Dirigido por Especificaciones: Cómo Dejar el Vibe Coding y Enviar Código Generado por IA Listo para Producción
Ya viste las demos. Un ingeniero escribe "construime un dashboard SaaS" en un agente de IA, y en tres minutos aparece una app React completa con auth, base de datos y flujo de pagos. Aplausos. El tweet se vuelve viral.
Después lo intentás en tu proyecto real, el que tiene 200 archivos, una capa de auth custom, tres integraciones con APIs externas y una estructura monorepo, y el agente reescribe tu esquema de base de datos con total confianza, borra un middleware crítico e introduce cuatro vulnerabilidades de seguridad antes de que puedas tocar Ctrl+C.
Esta es la brecha del vibe coding. La distancia entre "funciona en una demo" y "funciona en producción" no es un problema de herramientas. Es un problema de metodología. Y la metodología que cierra esta brecha tiene nombre: Desarrollo Dirigido por Especificaciones (SDD).
SDD no es escribir más documentación. Se trata de darle a los agentes IA exactamente las restricciones que necesitan para operar de manera confiable: archivos de spec, loops test-first y un flujo de 4 fases que reemplaza "generar y rezar" con "especificar, diseñar, dividir, implementar." Los equipos que adoptan SDD reportan consistentemente 60-80% menos regresiones generadas por IA y dramáticamente menos tiempo debugueando código que no escribieron.
Esta guía cubre la metodología completa: por qué el vibe coding falla a escala, el loop SDD de 4 fases, cómo estructurar archivos de spec (CLAUDE.md, cursor rules, AGENTS.md), integración de TDD con agentes IA y patrones de producción para orquestar agentes en codebases reales.
Por Qué el Vibe Coding Se Rompe
Seamos precisos sobre qué falla y por qué. El vibe coding, la práctica de prompt en lenguaje natural al agente y desplegar la salida inmediatamente, funciona sorprendentemente bien para prototipos greenfield. Pero falla sistemáticamente en codebases de producción por cuatro razones específicas:
1. El Problema del Colapso de Contexto
Los agentes IA son stateless. Cada nueva sesión empieza de cero. Tu proyecto de 200 archivos tiene conocimiento implícito embebido por todos lados: convenciones de naming, patrones de manejo de errores, el hecho de que userId en tu capa de auth es un UUID pero user_id en tu API legacy es un entero secuencial. Nada de esto existe en el contexto del agente a menos que se lo des explícitamente.
El vibe coding no provee mecanismo para esto. Escribís un prompt, el agente genera código basado en sus datos de entrenamiento, y el output sigue los patrones por defecto del agente, no los tuyos. El resultado es código que "funciona" aislado pero crea inconsistencias sutiles que se acumulan en drift arquitectural.
Colapso de Contexto en la Práctica:
Tu proyecto: Lo que genera el agente:
───────────── ──────────────────────────
camelCase en todo snake_case en archivos nuevos
Zod para validación if-checks manuales
Clases de error custom Generic throw new Error()
Patrón Repository Llamadas directas a la DB
Claves primarias UUID Auto-increment integers
2. El Sesgo del Happy Path
Los LLMs están entrenados predominantemente con código de tutoriales, ejemplos de documentación y respuestas de Stack Overflow. Estos datos de entrenamiento demuestran abrumadoramente el "happy path": cuando todo sale bien. El resultado es código AI que maneja el flujo principal elegantemente pero se desmorona en los bordes:
- ¿Timeouts de red? No manejados.
- ¿Requests concurrentes al mismo recurso? Race conditions.
- ¿Agotamiento del pool de conexiones a la DB? Crash.
- ¿Input malformado del usuario? Sin validar.
- ¿Rate limits de APIs externas? Ignorados.
Un estudio de Endor Labs de 2025 encontró que el 62% del código generado por IA contenía debilidades de seguridad o defectos de diseño, con 44-49% de las dependencias sugeridas por IA portando vulnerabilidades conocidas. El reporte Verizon DBIR 2025 encontró que la participación de terceros en brechas se duplicó al 30%, subrayando el riesgo creciente de código generado por IA sin verificar entrando en las cadenas de suministro de software.
3. El Vacío de Ownership
El vibe coding produce código que su supuesto dueño no entiende. El developer lo desplegó, pero no puede explicar el control flow, la estrategia de manejo de errores, o por qué se eligió una librería particular. Cuando aparecen bugs en producción a las 2 AM, se enfrentan a código escrito por una inteligencia alien con suposiciones diferentes sobre cómo se propagan los estados de error.
Esto no es una preocupación teórica: es la queja más común de los engineering managers sobre el desarrollo asistido por IA en 2026. El código funciona hasta que no funciona, y cuando no funciona, nadie puede arreglarlo rápido porque nadie lo entiende profundamente.
4. La Deuda Técnica Compuesta
Cada sesión de vibe coding agrega código que sigue los patrones implícitos del agente en lugar de los establecidos por el proyecto. Después de diez sesiones, no tenés un codebase: tenés una acumulación de diez estilos de codificación ligeramente diferentes, enfoques de manejo de errores y suposiciones arquitecturales. Esta deuda técnica se acumula exponencialmente porque cada nueva sesión de IA hereda la confusión de las anteriores.
El Loop SDD de 4 Fases
El Desarrollo Dirigido por Especificaciones reemplaza el paso único "prompt → código" con un loop de 4 fases que construye contexto antes de generar código. Cada fase produce un artefacto documental que el agente puede referenciar en fases posteriores.
El Loop SDD:
Fase 1: REQUERIMIENTOS ──→ requirements.md
↓ "¿Qué estamos construyendo?"
Fase 2: DISEÑO ──→ design.md
↓ "¿Cómo lo vamos a construir?"
Fase 3: TAREAS ──→ tasks.md
↓ "¿Qué pasos exactos en qué orden?"
Fase 4: IMPLEMENTACIÓN ──→ código + tests
↓ "Construir, testear, verificar."
└──── FEEDBACK ──────→ Actualizar specs, repetir.
Fase 1: Requerimientos
Empezá cada feature haciendo que la IA te ayude a clarificar qué estás construyendo. No pidas código: pedí un análisis de requerimientos.
Prompt a tu agente IA: "Necesito agregar un sistema de invitación de equipos a nuestra app SaaS. Antes de escribir código, creá un requirements.md que cubra: - User stories para el flujo de invitación - Edge cases (invitaciones expiradas, emails duplicados, conflictos de roles) - Requerimientos de seguridad (rate limiting, validación de tokens) - Puntos de integración con nuestro sistema de auth existente - Lo que NO estamos construyendo en esta fase"
La restricción "lo que NO estamos construyendo" es crítica. Sin límites de scope explícitos, los agentes IA tienden a sobre-construir: agregan features que nadie pidió, introducen abstracciones prematuras y expanden el scope hasta que el cambio toca la mitad del codebase.
Fase 2: Diseño
Con los requerimientos fijados, traducilos en decisiones técnicas. De nuevo, todavía nada de código: solo arquitectura.
Prompt a tu agente IA: "Leé requirements.md. Ahora creá un design.md que cubra: - Cambios de esquema de DB (tablas/columnas, con estrategia de migración) - Endpoints de API (método, path, shapes de request/response) - Arquitectura de service layer (funciones, dependencias) - Estrategia de manejo de errores (errores, códigos HTTP, mensajes) - Máquina de estados del ciclo de vida de invitación Referenciá nuestros patrones existentes en src/services/ y src/api/. NO escribas código de implementación."
Esta fase atrapa errores arquitecturales antes de que exista código. Arreglar un documento de diseño es infinitamente más barato que debuguear una feature medio implementada.
Fase 3: Tareas
Descomponé el diseño en pasos de implementación discretos, ordenados por dependencia. Cada tarea debe ser lo suficientemente chica para que el agente la complete en una sola sesión enfocada.
tasks.md ejemplo: ## Sistema de Invitación de Equipos — Tareas de Implementación ### Capa de Base de Datos - [x] Task 1 (S): Crear migración `team_invitations` - Columnas: id, team_id, email, role, token, status, expires_at - Tests: migración up/down, validación de constraints ### Capa de Servicios - [ ] Task 2 (M): Implementar `InvitationService.create()` - Depende de: Task 1 - Valida: formato de email, chequeo de duplicados, límite de miembros - Tests: happy path, rechazo de duplicados, enforcement de límite - [ ] Task 3 (M): Implementar `InvitationService.accept()` - Depende de: Task 2 - Valida: token existe, no expirado, no ya aceptado - Tests: aceptación válida, token expirado, token ya usado ### Capa de API - [ ] Task 4 (M): POST /api/teams/:id/invitations - Depende de: Task 2 - Auth: requiere rol de team admin - Tests: 201 success, 403 no-admin, 409 duplicado, 429 rate limit - [ ] Task 5 (M): POST /api/invitations/:token/accept - Depende de: Task 3 - Auth: debe estar logueado, email debe coincidir con invitación - Tests: 200 success, 404 token inválido, 410 expirado
Fase 4: Implementación
Ahora, y recién ahora, la IA escribe código. Pero en vez de un prompt masivo único, le das una tarea a la vez, con contexto completo:
Prompt a tu agente IA: "Leé requirements.md, design.md y tasks.md. Implementá Task 2: InvitationService.create() Requerimientos: - Seguí nuestro patrón de servicio existente en src/services/TeamService.ts - Usá Zod para validación de input - Usá nuestra clase custom AppError para manejo de errores - Escribí tests primero (archivo de test, después implementación) - Ejecutá tests después de implementar para verificar NO modifiques ningún archivo existente excepto para agregar imports. NO implementes las tasks 3-5 todavía."
Las restricciones en este prompt hacen el trabajo pesado. "Seguí nuestro patrón existente" previene el colapso de contexto. "Escribí tests primero" fuerza TDD. "NO modifiques archivos existentes" previene el refactoring "amable" del agente. "NO implementes tasks 3-5" previene el scope creep.
Estructurando tus Archivos de Spec
El loop SDD depende de contexto persistente: archivos que sobreviven entre sesiones y le dicen a cada agente cómo comportarse en tu proyecto.
CLAUDE.md / Cursor Rules / AGENTS.md
Estos archivos sirven el mismo propósito en diferentes herramientas: son el "documento de briefing" del proyecto que la IA lee al inicio de cada sesión.
# CLAUDE.md (o .cursor/rules, o AGENTS.md) ## Visión General del Proyecto Plataforma SaaS de e-commerce construida con Next.js 16, TypeScript, Drizzle ORM, PostgreSQL. Monorepo gestionado con Turborepo. ## Stack Tecnológico - Framework: Next.js 16 (App Router, Server Components) - Lenguaje: TypeScript 6.0 (strict mode) - Base de datos: PostgreSQL 17 + Drizzle ORM - Validación: Zod v3 - Estilos: Tailwind CSS v4 - Testing: Vitest + Playwright - Auth: JWT custom + rotación de refresh tokens ## Reglas de Arquitectura 1. Todo acceso a DB va a través de clases repository en src/repositories/ 2. La lógica de negocio vive en clases de servicio en src/services/ 3. Las rutas de API son controladores delgados que llaman a servicios 4. Todos los inputs se validan con esquemas Zod en src/schemas/ 5. Los errores usan la clase custom AppError (ver src/lib/errors.ts) 6. Todos los IDs son UUIDs generados con crypto.randomUUID() ## Convenciones de Código - Usá named exports, no default exports - Tipos de retorno explícitos en todas las funciones públicas - Patrón de mensajes de error: "[Entidad].[acción] failed: [razón]" - Nombres de archivos: kebab-case. Clases: PascalCase - Imports: agrupar por externos → internos → tipos ## Warnings Críticos - NUNCA usés tipo `any`. Usá `unknown` con type narrowing. - NUNCA usés default exports. Solo named exports. - NUNCA modifiques archivos de migración. Creá nuevos para cambios. - NUNCA comitees archivos .env. Usá .env.example para documentación.
Principio Clave: Ruteá, No Volcás
Mantené tu archivo root de spec debajo de 200-300 líneas. Debe decirle al agente qué hacer y dónde encontrar más info, no contener cada regla del proyecto.
## Documentos de Referencia - Decisiones de arquitectura: /docs/architecture.md - Convenciones de API: /docs/api-conventions.md - Esquema de base de datos: /docs/schema.md - Specs de features: /docs/specs/[nombre-feature].md
El agente lee el archivo root, después lee los documentos referenciados on-demand cuando trabaja en áreas relevantes. Es revelación progresiva: el mismo principio de UX que hace buen software, aplicado a la gestión de contexto de IA.
Reglas Por Directorio
Muchas herramientas de IA soportan reglas con scope por directorio. Usalas para restricciones específicas del dominio:
# src/services/.rules (o src/services/.cursorrules) ## Reglas del Service Layer - Todos los métodos de servicio deben ser async - Los servicios reciben dependencias por inyección en el constructor - Los servicios no deben importar desde src/api/ (sin deps circulares) - Cada método público debe tener un test correspondiente - Usá transacciones para operaciones multi-tabla - Logueá entrada y salida de operaciones críticas con logger.info()
TDD con Agentes IA: El Loop Red-Green-Refactor
El TDD no solo es compatible con agentes IA: es el flujo de trabajo ideal para ellos. Los tests proveen lo único que los agentes necesitan desesperadamente: una definición objetiva y verificable de "correcto."
Por Qué TDD Funciona Mejor Con IA Que Sin Ella
Sin tests, le pedís a la IA que genere código y después lo revisás manualmente buscando errores. Esto es cognitivamente agotador y propenso a errores.
Con TDD, definís la corrección primero, después dejás que la IA genere código hasta que los tests pasen. No estás revisando detalles de implementación: estás revisando resultados. La suite de tests es tu verificador automático.
Flujo Tradicional (frágil):
Prompt → Código → Revisión Manual → "¿Se ve bien?" → Deploy → Bug
Flujo TDD (confiable):
Spec → Test (falla) → Prompt IA → Código → Correr Tests → ¿Pasa? → Deploy
↓
Falla → IA itera automáticamente
El Patrón Spec → Test → Implementación
Paso 1: Escribí el spec del test (humano guía)
// __tests__/services/invitation-service.test.ts import { describe, it, expect, beforeEach } from 'vitest'; import { InvitationService } from '@/services/invitation-service'; describe('InvitationService.create', () => { it('debería crear una invitación con email y rol válidos', async () => { const result = await service.create({ teamId: 'team-uuid-1', email: '[email protected]', role: 'member', invitedBy: 'admin-uuid-1', }); expect(result.id).toBeDefined(); expect(result.status).toBe('pending'); expect(result.token).toHaveLength(64); expect(result.expiresAt).toBeInstanceOf(Date); }); it('debería rechazar invitaciones duplicadas para el mismo email', async () => { await service.create({ teamId: 'team-uuid-1', email: '[email protected]', role: 'member', invitedBy: 'admin-uuid-1' }); await expect( service.create({ teamId: 'team-uuid-1', email: '[email protected]', role: 'member', invitedBy: 'admin-uuid-1' }) ).rejects.toThrow('Invitation.create failed: duplicate invitation'); }); it('debería imponer el límite de miembros del equipo', async () => { await expect( service.create({ teamId: 'full-team', email: '[email protected]', role: 'member', invitedBy: 'admin-uuid-1' }) ).rejects.toThrow('Invitation.create failed: team member limit reached'); }); });
Paso 2: Dejá que la IA implemente (agente guía)
El agente genera código, corre los tests, ve fallos e itera automáticamente. Es el loop Red-Green, pero la IA es la que cicla. Vos definiste el "qué" (tests), y la IA resuelve el "cómo" (implementación).
Paso 3: Revisión humana (enfocada en resultados)
Una vez que pasan los tests, revisá la implementación para: ¿sigue los patrones del proyecto? ¿Hay concerns de performance? ¿Hay concerns de seguridad? Estás revisando con propósito, no escaneando línea por línea código desconocido esperando encontrar un bug.
Patrones de Fallo y Cómo SDD los Previene
| Patrón de Fallo | Causa Raíz | Prevención SDD |
|---|---|---|
| Colapso de contexto | El agente no conoce las convenciones | CLAUDE.md con reglas de arquitectura y convenciones |
| Sesgo del happy path | No genera manejo de errores | Tests definen explícitamente escenarios de error |
| Scope creep | Sobre-construye o toca código no relacionado | Desglose de tareas con restricciones "NO" explícitas |
| Drift arquitectural | Usa sus patrones, no los tuyos | Documento de diseño + reglas por directorio |
| Regresión | Código nuevo rompe funcionalidad existente | Flujo test-first atrapa regresiones inmediatamente |
| Agujeros de seguridad | No considera el modelo de amenazas | Requerimientos de seguridad + test cases de seguridad |
| Vacío de ownership | Se despliega código sin entenderlo | Revisión de diseño fuerza comprensión antes de implementar |
| Deuda técnica | Patrones inconsistentes entre sesiones | CLAUDE.md asegura consistencia en cada sesión |
Flujo de Producción: Poniéndolo Todo Junto
Acá va el flujo SDD completo del mundo real, desde el pedido de feature hasta el merge:
1. Brief del Feature
## Feature: Gestión de Roles de Equipo Los usuarios necesitan poder cambiar roles de miembros del equipo (admin → miembro, miembro → admin) y eliminar miembros. Solo los admins del equipo deberían poder realizar estas acciones.
2. Requerimientos Asistidos por IA
Prompt: "Leé el brief del feature arriba y nuestro sistema de auth existente en src/services/auth-service.ts. Generá requirements.md cubriendo user stories, edge cases, requerimientos de seguridad y lo que NO estamos construyendo. Considerá: ¿qué pasa cuando el último admin intenta cambiar su propio rol?"
3. Diseño Asistido por IA
Prompt: "Leé requirements.md. Creá design.md con cambios de schema de DB, endpoints de API, métodos de servicio y un diagrama de estados para transiciones de roles. Seguí los patrones de nuestro codebase existente. Marcá cualquier decisión de diseño que necesite revisión humana."
4. Checkpoint de Revisión Humana
Este es el momento crítico de human-in-the-loop. Revisá el documento de diseño:
- ¿Tiene sentido el schema de la base de datos?
- ¿Los endpoints de API son RESTful y consistentes con nuestra API existente?
- ¿La IA capturó el edge case del "último admin"?
- ¿Hay implicaciones de seguridad que la IA no vio?
Se hacen correcciones al documento de diseño antes de escribir una sola línea de código.
5. Desglose de Tareas Asistido por IA
Prompt: "Leé requirements.md y design.md. Creá tasks.md con pasos de implementación ordenados y con dependencias. Cada tarea debe incluir sus requerimientos de cobertura de tests."
6. Implementación Iterativa
Prompt: "Implementá Task 1 de tasks.md. Escribí tests primero, después la implementación. Corré tests para verificar. Marcá la tarea como completa en tasks.md cuando termines. NO avances a Task 2."
Repetir para cada tarea. Cada tarea se puede revisar independientemente, haciendo el code review manejable en vez de enfrentar un solo PR masivo.
7. Verificación de Integración
Prompt: "Todas las tareas en tasks.md están completas. Corré la suite de tests completa con `pnpm test`. Si hay fallos, arreglalos. Después corré `pnpm lint` y arreglá cualquier issue."
Escalando SDD: Patrones de Equipo
Repositorio Compartido de Specs
Para equipos, mantené los archivos de spec en control de versiones junto al código:
project/
├── .claude/
│ └── rules/
│ ├── general.md
│ ├── api-conventions.md
│ └── testing.md
├── docs/
│ └── specs/
│ ├── team-invitations/
│ │ ├── requirements.md
│ │ ├── design.md
│ │ └── tasks.md
│ └── role-management/
├── CLAUDE.md
├── AGENTS.md
└── src/
Template de PR para Trabajo AI-Asistido
Exigí que los PRs con código generado por IA referencien su spec:
## Checklist de PR (AI-Asistido) - [ ] Spec de feature existe en /docs/specs/[nombre-feature]/ - [ ] requirements.md revisado y aprobado por tech lead - [ ] design.md revisado y aprobado por tech lead - [ ] Todas las tareas en tasks.md completadas y chequeadas - [ ] Cobertura de tests: todos los paths de requirements testeados - [ ] Sin modificaciones a archivos fuera del scope del feature - [ ] `pnpm test` pasa - [ ] `pnpm lint` pasa
Métricas que Importan
| Métrica | Antes de SDD | Después de SDD | Por Qué Importa |
|---|---|---|---|
| Regresiones IA por sprint | 8-15 | 1-3 | Medida directa de calidad de código |
| Tiempo de debug de código IA | 2-4 horas/bug | 15-30 min/bug | Reducción del vacío de ownership |
| Tiempo de review de PR | 45-60 min | 15-20 min | Eficiencia de revisión |
| Tiempo total de delivery | Igual (coding rápido, debug lento) | 30-40% más rápido neto | Ganancia real de productividad |
| Issues de seguridad detectados | 20-30% tasa de captura | 80-90% (tests + spec) | Mejora de seguridad |
Objeciones Comunes (y Respuestas)
"SDD es solo más overhead de documentación"
No. Los documentos SDD son generados por la IA, revisados por vos, y consumidos por la IA. El esfuerzo total de documentación humana es 10-15 minutos por feature (tiempo de revisión). La alternativa es 2-4 horas por bug debugueando código que no entendés.
"Mi proyecto es muy chico para esto"
Si tu proyecto es lo suficientemente chico como para tener todo el codebase en tu cabeza, el vibe coding puede funcionar. SDD se vuelve esencial cuando el codebase excede tu memoria de trabajo: aproximadamente 10-20 archivos con lógica interconectada.
"Los tests enlentecen el desarrollo"
Los tests enlentecen la primera hora. Aceleran todas las horas siguientes. Con agentes IA, este trade-off es aún más favorable: el agente escribe la implementación para matchear tus tests, generalmente acertando en el primer o segundo intento. Escribir tests lleva 5-10 minutos para humanos; la implementación le lleva a la IA 30-60 segundos.
"Solo necesito escribir mejores prompts"
La calidad del prompt importa, pero los prompts son efímeros. Desaparecen cuando la sesión termina. Los archivos de spec de SDD persisten, mejoran con el tiempo y funcionan entre diferentes herramientas de IA. Tu CLAUDE.md no solo ayuda a la sesión de hoy: ayuda a cada sesión, cada miembro del equipo y cada herramienta de IA.
El Modelo de Madurez
Los equipos que adoptan SDD típicamente progresan por tres etapas:
Etapa 1: Reactiva (La mayoría de los equipos hoy)
- Usan IA para generación de código con prompts ad-hoc
- Debuguean frecuentemente, reviews dolorosos
- Sin archivos de contexto persistente
- Cada sesión empieza de cero
Etapa 2: Estructurada (Adopción de SDD)
- CLAUDE.md / AGENTS.md establecidos
- Loop de 4 fases para features complejos
- TDD integrado con workflows de IA
- Reglas por directorio para restricciones de dominio
- Revisión de diseño antes de implementación
Etapa 3: Sistemática (Madurez SDD completa)
- Repositorio de specs mantenido junto al código
- Agentes IA actualizan documentos de spec mientras trabajan
- Métricas trackeadas y optimizadas
- Onboarding de nuevos miembros via docs de spec
- Consistencia entre herramientas (Cursor, Claude Code, Copilot siguen las mismas specs)
La mayoría de los equipos puede llegar a la Etapa 2 en un solo sprint. La Etapa 3 se desarrolla naturalmente en 2-3 meses a medida que los archivos de spec se acumulan y los patrones se estabilizan.
La Realidad de Ingeniería
Los agentes de IA son las herramientas más poderosas que hemos tenido para producir código rápido. También son las más poderosas para producir bugs rápido. La diferencia entre ambos resultados no es el modelo, el prompt ni la herramienta: es la metodología.
El vibe coding trata a la IA como reemplazo de la disciplina de ingeniería. SDD trata a la IA como amplificador de la disciplina de ingeniería. El loop de 4 fases no es burocracia. Es el mismo proceso que los senior devs siempre siguieron, ahora hecho explícito para que los agentes también lo sigan.
Tu agente IA es el junior más productivo que jamás contrataste. SDD es cómo lo onboardeás correctamente: con requerimientos claros, patrones documentados, tareas definidas y criterios de aceptación verificables. Salteate el onboarding y obtenés el caos del que todos se quejan. Invertí en el onboarding y obtenés el multiplicador de productividad con el que todos sueñan.
La elección no es si usar agentes de IA. La elección es si usarlos con disciplina de ingeniería o sin ella. SDD hace esa elección obvia.
Explora herramientas relacionadas
Prueba estas herramientas gratuitas de Pockit