Desenvolvimento Dirigido por Especificação: Como Parar de Vibe Coding e Entregar Código Gerado por IA Pronto pra Produção
Você já viu as demos. Um engenheiro digita "cria um dashboard SaaS" num agente de IA, e em três minutos aparece um app React completo com auth, banco de dados e fluxo de pagamento. A galera aplaude. O tweet viraliza.
Aí você tenta a mesma coisa no seu projeto real, aquele com 200 arquivos, uma camada de auth custom, três integrações com APIs externas e uma estrutura monorepo, e o agente reescreve seu schema do banco de dados cheio de confiança, deleta um middleware crítico e introduz quatro vulnerabilidades de segurança antes de você conseguir apertar Ctrl+C.
Essa é a armadilha do vibe coding. A distância entre "funciona na demo" e "funciona em produção" não é um problema de ferramenta. É um problema de metodologia. E a metodologia que fecha essa lacuna tem nome: Desenvolvimento Dirigido por Especificação (SDD).
SDD não é escrever mais documentação. É dar pros agentes de IA exatamente as restrições que precisam pra operar de forma confiável: arquivos de spec, loops test-first e um fluxo de 4 fases que substitui "gerar e rezar" por "especificar, projetar, dividir, implementar." Times que adotam SDD reportam consistentemente 60-80% menos regressões geradas por IA e dramaticamente menos tempo debugando código que não escreveram.
Esse guia cobre a metodologia completa: por que o vibe coding falha em escala, o loop SDD de 4 fases, como estruturar arquivos de spec (CLAUDE.md, cursor rules, AGENTS.md), integração de TDD com agentes IA e padrões de produção pra orquestrar agentes em codebases reais.
Por Que o Vibe Coding Quebra
Bora ser preciso sobre o que falha e por quê. Vibe coding é a prática de dar um prompt em linguagem natural pro agente e fazer deploy da saída direto. Funciona surpreendentemente bem pra protótipos greenfield. Mas falha sistematicamente em codebases de produção por quatro razões específicas:
1. O Problema do Colapso de Contexto
Agentes de IA são stateless. Cada sessão começa do zero. Seu projeto de 200 arquivos tem conhecimento implícito embutido em tudo: convenções de naming, padrões de tratamento de erro, o fato de que userId na sua camada de auth é UUID mas user_id na sua API legada é um inteiro sequencial. Nada disso existe no contexto do agente a menos que você forneça explicitamente.
Vibe coding não tem mecanismo pra isso. Você digita um prompt, o agente gera código baseado nos dados de treino, e a saída segue os padrões default do agente, não os seus. O resultado é código que "funciona" isolado mas cria inconsistências sutis que acumulam em drift arquitetural.
Colapso de Contexto na Prática:
Seu projeto: O que o agente gera:
───────────── ──────────────────────
camelCase em tudo snake_case em arquivos novos
Zod pra validação if-checks manuais
Classes de erro custom throw new Error() genérico
Padrão Repository Chamadas diretas ao banco
Chaves primárias UUID Auto-increment inteiros
2. O Viés do Happy Path
LLMs são treinados predominantemente com código de tutorial, exemplos de documentação e respostas do Stack Overflow. Esses dados de treino demonstram esmagadoramente o "happy path": quando tudo dá certo. O resultado é código de IA que trata o fluxo principal lindamente mas desmorona nas bordas:
- Timeouts de rede? Sem tratamento.
- Requests concorrentes pro mesmo recurso? Race conditions.
- Esgotamento do pool de conexões do banco? Crash.
- Input malformado do usuário? Sem validação.
- Rate limits de APIs externas? Ignorados.
Um estudo de 2025 da Endor Labs descobriu que 62% do código gerado por IA continha fraquezas de segurança ou falhas de design, com 44-49% das dependências sugeridas por IA carregando vulnerabilidades conhecidas. O relatório Verizon DBIR 2025 descobriu que o envolvimento de terceiros em brechas dobrou pra 30%, ressaltando o risco crescente de código gerado por IA sem verificação entrando nas cadeias de suprimento de software.
3. O Vazio de Ownership
Vibe coding produz código que o próprio dev não entende. Fez o deploy, mas não sabe explicar o control flow, a estratégia de erro, nem por que aquela biblioteca foi escolhida. Quando um bug aparece em produção às 2 da manhã, o dev fica cara a cara com código que parece ter vindo de outro planeta, escrito com premissas completamente diferentes sobre como erros se propagam.
Isso não é preocupação teórica: é a reclamação mais comum de engineering managers sobre desenvolvimento assistido por IA em 2026. O código funciona até não funcionar, e quando não funciona, ninguém consegue resolver rápido porque ninguém entende profundamente.
4. A Dívida Técnica Composta
Cada sessão de vibe coding adiciona código que segue os padrões implícitos do agente em vez dos estabelecidos pelo projeto. Depois de dez sessões, você não tem uma codebase: tem uma acumulação de dez estilos de codificação ligeiramente diferentes, abordagens de tratamento de erro e suposições arquiteturais. Essa dívida técnica se acumula exponencialmente porque cada nova sessão de IA herda a confusão das anteriores.
O Loop SDD de 4 Fases
O Desenvolvimento Dirigido por Especificação substitui o passo único "prompt → código" por um loop de 4 fases que constrói contexto antes de gerar código. Cada fase produz um artefato documental que o agente pode referenciar nas fases seguintes.
O Loop SDD:
Fase 1: REQUISITOS ──→ requirements.md
↓ "O que vamos construir?"
Fase 2: DESIGN ──→ design.md
↓ "Como vamos construir?"
Fase 3: TAREFAS ──→ tasks.md
↓ "Que passos exatos em que ordem?"
Fase 4: IMPLEMENTAÇÃO ──→ código + testes
↓ "Construir, testar, verificar."
└──── FEEDBACK ─────→ Atualizar specs, repetir.
Fase 1: Requisitos
Comece cada feature fazendo a IA ajudar a clarificar o que você tá construindo. Não peça código: peça uma análise de requisitos.
Prompt pro seu agente IA: "Preciso adicionar um sistema de convites de time no nosso app SaaS. Antes de escrever código, cria um requirements.md cobrindo: - User stories pro fluxo de convite - Edge cases (convites expirados, emails duplicados, conflitos de role) - Requisitos de segurança (rate limiting, validação de token) - Pontos de integração com nosso sistema de auth existente - O que NÃO estamos construindo nessa fase"
A restrição "o que NÃO estamos construindo" é crítica. Sem limites de escopo explícitos, agentes de IA tendem a construir demais: adicionam features que ninguém pediu, introduzem abstrações prematuras e expandem o escopo até o change tocar metade da codebase.
Fase 2: Design
Com requisitos travados, traduza pra decisões técnicas. De novo, nada de código ainda: só arquitetura.
Prompt pro seu agente IA: "Leia requirements.md. Agora cria um design.md cobrindo: - Mudanças no schema do banco (tabelas/colunas, com estratégia de migração) - Endpoints de API (método, path, shapes de request/response) - Arquitetura do service layer (funções, dependências) - Estratégia de tratamento de erros (erros, códigos HTTP, mensagens) - Máquina de estados pro ciclo de vida do convite Referencie nossos padrões existentes em src/services/ e src/api/. NÃO escreva código de implementação."
Essa fase pega erros de arquitetura antes de qualquer código existir. Corrigir um documento de design é infinitamente mais barato que debugar uma feature meio implementada.
Fase 3: Tarefas
Decomponha o design em passos de implementação discretos, ordenados por dependência. Cada tarefa deve ser pequena o suficiente pro agente completar numa única sessão focada.
tasks.md exemplo: ## Sistema de Convites de Time — Tarefas de Implementação ### Camada de Banco - [x] Task 1 (P): Criar migração `team_invitations` - Colunas: id, team_id, email, role, token, status, expires_at - Testes: migração up/down, validação de constraints ### Camada de Serviço - [ ] Task 2 (M): Implementar `InvitationService.create()` - Depende de: Task 1 - Valida: formato de email, check de duplicata, limite de membros - Testes: happy path, rejeição de duplicata, enforcement de limite - [ ] Task 3 (M): Implementar `InvitationService.accept()` - Depende de: Task 2 - Valida: token existe, não expirado, não já aceito - Testes: aceitação válida, token expirado, token já usado ### Camada de API - [ ] Task 4 (M): POST /api/teams/:id/invitations - Depende de: Task 2 - Auth: requer role de team admin - Testes: 201 sucesso, 403 não-admin, 409 duplicata, 429 rate limit - [ ] Task 5 (M): POST /api/invitations/:token/accept - Depende de: Task 3 - Auth: precisa estar logado, email precisa bater com convite - Testes: 200 sucesso, 404 token inválido, 410 expirado
Fase 4: Implementação
Agora, e só agora, a IA escreve código. Mas em vez de um prompt gigante único, você alimenta uma tarefa por vez, com contexto completo:
Prompt pro seu agente IA: "Leia requirements.md, design.md e tasks.md. Implemente Task 2: InvitationService.create() Requisitos: - Siga nosso padrão de serviço existente em src/services/TeamService.ts - Use Zod pra validação de input - Use nossa classe custom AppError pra tratamento de erros - Escreva testes primeiro (arquivo de teste, depois implementação) - Rode testes depois da implementação pra verificar NÃO modifique nenhum arquivo existente exceto pra adicionar imports. NÃO implemente as tasks 3-5 ainda."
As restrições nesse prompt fazem o trabalho pesado. "Siga nosso padrão" previne colapso de contexto. "Escreva testes primeiro" força TDD. "NÃO modifique arquivos existentes" previne refactoring "amigável" do agente. "NÃO implemente tasks 3-5" previne scope creep.
Estruturando seus Arquivos de Spec
O loop SDD depende de contexto persistente: arquivos que sobrevivem entre sessões e dizem pra todo agente como se comportar no seu projeto.
CLAUDE.md / Cursor Rules / AGENTS.md
Esses arquivos servem o mesmo propósito em ferramentas diferentes: são o "documento de briefing" do projeto que a IA lê no início de cada sessão.
# CLAUDE.md (ou .cursor/rules, ou AGENTS.md) ## Visão Geral do Projeto Plataforma SaaS de e-commerce construída com Next.js 16, TypeScript, Drizzle ORM, PostgreSQL. Monorepo gerenciado com Turborepo. ## Stack Tecnológico - Framework: Next.js 16 (App Router, Server Components) - Linguagem: TypeScript 6.0 (strict mode) - Banco de dados: PostgreSQL 17 + Drizzle ORM - Validação: Zod v3 - Estilização: Tailwind CSS v4 - Testes: Vitest + Playwright - Auth: JWT custom + rotação de refresh token ## Regras de Arquitetura 1. Todo acesso ao banco vai por classes repository em src/repositories/ 2. Lógica de negócio vive em classes de serviço em src/services/ 3. Rotas de API são controladores finos que chamam serviços 4. Todos inputs são validados com schemas Zod em src/schemas/ 5. Erros usam classe custom AppError (veja src/lib/errors.ts) 6. Todos IDs são UUIDs gerados com crypto.randomUUID() ## Convenções de Código - Use named exports, não default exports - Tipos de retorno explícitos em todas funções públicas - Padrão de mensagens de erro: "[Entidade].[ação] failed: [razão]" - Nomes de arquivo: kebab-case. Classes: PascalCase - Imports: agrupar por externos → internos → tipos ## Warnings Críticos - NUNCA use tipo `any`. Use `unknown` com type narrowing. - NUNCA use default exports. Só named exports. - NUNCA modifique arquivos de migração. Crie novos pra mudanças. - NUNCA commite arquivos .env. Use .env.example pra documentação.
Princípio Chave: Roteie, Não Despeje
Mantenha seu arquivo root de spec abaixo de 200-300 linhas. Deve dizer pro agente o que fazer e onde encontrar mais info, não conter toda regra do projeto.
## Documentos de Referência - Decisões de arquitetura: /docs/architecture.md - Convenções de API: /docs/api-conventions.md - Schema do banco: /docs/schema.md - Specs de features: /docs/specs/[nome-feature].md
O agente lê o arquivo root, depois lê os documentos referenciados on-demand quando trabalha em áreas relevantes. É revelação progressiva: o mesmo princípio de UX que faz bom software, aplicado à gestão de contexto de IA.
Regras Por Diretório
Muitas ferramentas de IA suportam regras com escopo por diretório. Use pra restrições específicas do domínio:
# src/services/.rules (ou src/services/.cursorrules) ## Regras do Service Layer - Todos métodos de serviço devem ser async - Serviços recebem dependências por injeção no construtor - Serviços não devem importar de src/api/ (sem deps circulares) - Todo método público deve ter um teste correspondente - Use transações pra operações multi-tabela - Logue entrada e saída de operações críticas com logger.info()
TDD com Agentes IA: O Loop Red-Green-Refactor
TDD não é só compatível com agentes IA: é o workflow ideal pra eles. Testes fornecem a única coisa que agentes precisam desesperadamente: uma definição objetiva e verificável de "correto."
Por Que TDD Funciona Melhor Com IA Do Que Sem
Sem testes, você pede pra IA gerar código e depois revisa manualmente procurando erros. Isso é cognitivamente exaustivo e propenso a erros.
Com TDD, você define correção primeiro, depois deixa a IA gerar código até os testes passarem. Você não tá revisando detalhes de implementação: tá revisando resultados. A suite de testes é seu verificador automático.
Fluxo Tradicional (frágil):
Prompt → Código → Revisão Manual → "Parece certo?" → Deploy → Bug
Fluxo TDD (confiável):
Spec → Teste (falha) → Prompt IA → Código → Rodar Testes → Passa? → Deploy
↓
Falha → IA itera automaticamente
O Padrão Spec → Teste → Implementação
Passo 1: Escreva o spec do teste (humano guia)
// __tests__/services/invitation-service.test.ts import { describe, it, expect, beforeEach } from 'vitest'; import { InvitationService } from '@/services/invitation-service'; describe('InvitationService.create', () => { it('deve criar um convite com email e role 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('deve rejeitar convites duplicados pro mesmo 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('deve enforçar o limite de membros do time', 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'); }); });
Passo 2: Deixe a IA implementar (agente guia)
O agente gera código, roda os testes, vê falhas e itera automaticamente. É o loop Red-Green, mas a IA que tá ciclando. Você definiu o "o quê" (testes), e a IA resolve o "como" (implementação).
Passo 3: Revisão humana (focada em resultados)
Uma vez que os testes passam, revise a implementação: segue os padrões do projeto? Tem concerns de performance? Tem concerns de segurança? Você tá revisando com propósito, não escaneando linha por linha código desconhecido esperando achar um bug.
Padrões de Falha e Como SDD Previne
| Padrão de Falha | Causa Raiz | Prevenção SDD |
|---|---|---|
| Colapso de contexto | Agente não conhece convenções do projeto | CLAUDE.md com regras de arquitetura e convenções |
| Viés do happy path | Não gera tratamento de erros | Testes definem explicitamente cenários de erro |
| Scope creep | Constrói demais ou mexe em código não relacionado | Decomposição de tarefas com restrições "NÃO" explícitas |
| Drift arquitetural | Usa seus padrões, não os seus | Documento de design + regras por diretório |
| Regressão | Código novo quebra funcionalidade existente | Fluxo test-first pega regressões imediatamente |
| Brechas de segurança | Não considera modelo de ameaças | Requisitos de segurança + test cases de segurança |
| Vazio de ownership | Deploy de código sem entender | Revisão de design força compreensão antes de implementar |
| Dívida técnica | Padrões inconsistentes entre sessões | CLAUDE.md garante consistência em toda sessão |
Workflow de Produção: Juntando Tudo
O fluxo SDD completo do mundo real, do pedido de feature ao merge:
1. Brief da Feature
## Feature: Gestão de Roles do Time Usuários precisam poder mudar roles de membros do time (admin → membro, membro → admin) e remover membros. Só admins do time devem poder realizar essas ações.
2. Requisitos Assistidos por IA
Prompt: "Leia o brief da feature acima e nosso sistema de auth existente em src/services/auth-service.ts. Gere requirements.md cobrindo user stories, edge cases, requisitos de segurança e o que NÃO estamos construindo. Considere: o que acontece quando o último admin tenta mudar seu próprio role?"
3. Design Assistido por IA
Prompt: "Leia requirements.md. Crie design.md com mudanças de schema do banco, endpoints de API, métodos de serviço e um diagrama de estados pra transições de role. Siga os padrões da nossa codebase existente. Marque qualquer decisão de design que precise de revisão humana."
4. Checkpoint de Revisão Humana
Esse é o momento crítico de human-in-the-loop. Revise o documento de design:
- O schema do banco faz sentido?
- Os endpoints de API são RESTful e consistentes com nossa API?
- A IA pegou o edge case do "último admin"?
- Tem implicações de segurança que a IA não viu?
Correções são feitas no documento de design antes de escrever uma linha de código.
5. Decomposição de Tarefas Assistida por IA
Prompt: "Leia requirements.md e design.md. Crie tasks.md com passos de implementação ordenados e com dependências. Cada tarefa deve incluir seus requisitos de cobertura de testes."
6. Implementação Iterativa
Prompt: "Implemente Task 1 de tasks.md. Escreva testes primeiro, depois a implementação. Rode testes pra verificar. Marque a tarefa como completa em tasks.md quando terminar. NÃO avance pra Task 2."
Repetir pra cada tarefa. Cada tarefa pode ser revisada independentemente, tornando o code review gerenciável.
7. Verificação de Integração
Prompt: "Todas tarefas em tasks.md estão completas. Rode a suite de testes completa com `pnpm test`. Se tiver falhas, corrija. Depois rode `pnpm lint` e corrija qualquer issue."
Escalando SDD: Padrões de Time
Repositório Compartilhado de Specs
Pra times, mantenha arquivos de spec em controle de versão junto com o 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 pra Trabalho AI-Assistido
Exija que PRs com código gerado por IA referenciem sua spec:
## Checklist de PR (AI-Assistido) - [ ] Spec de feature existe em /docs/specs/[nome-feature]/ - [ ] requirements.md revisado e aprovado pelo tech lead - [ ] design.md revisado e aprovado pelo tech lead - [ ] Todas tarefas em tasks.md completadas e marcadas - [ ] Cobertura de testes: todos paths dos requisitos testados - [ ] Sem modificações em arquivos fora do escopo da feature - [ ] `pnpm test` passa - [ ] `pnpm lint` passa
Métricas que Importam
| Métrica | Antes do SDD | Depois do SDD | Por Que Importa |
|---|---|---|---|
| Regressões IA por sprint | 8-15 | 1-3 | Medida direta de qualidade |
| Tempo de debug código IA | 2-4 horas/bug | 15-30 min/bug | Redução do vazio de ownership |
| Tempo de review de PR | 45-60 min | 15-20 min | Eficiência de revisão |
| Tempo total de delivery | Igual (coding rápido, debug lento) | 30-40% mais rápido | Ganho real de produtividade |
| Issues de segurança detectados | 20-30% taxa | 80-90% (testes + spec) | Melhoria de segurança |
Objeções Comuns (e Respostas)
"SDD é só mais overhead de documentação"
Não. Documentos SDD são gerados pela IA, revisados por você, e consumidos pela IA. O esforço humano total de documentação é 10-15 minutos por feature (tempo de revisão). A alternativa é 2-4 horas por bug debugando código que você não entende.
"Meu projeto é pequeno demais pra isso"
Se seu projeto é pequeno o suficiente pra caber inteiro na sua cabeça, vibe coding pode funcionar. SDD se torna essencial quando a codebase ultrapassa sua memória de trabalho: aproximadamente 10-20 arquivos com lógica interconectada.
"Testes atrasam o desenvolvimento"
Testes atrasam a primeira hora. Aceleram todas as próximas. Com agentes IA, esse trade-off é ainda mais favorável: o agente escreve a implementação pra bater com seus testes, geralmente acertando na primeira ou segunda tentativa. Escrever testes leva 5-10 minutos pro humano; a implementação leva pro IA 30-60 segundos.
"Só preciso escrever prompts melhores"
Qualidade do prompt importa, mas prompts são efêmeros. Desaparecem quando a sessão termina. Arquivos de spec do SDD são persistentes, melhoram com o tempo e funcionam entre diferentes ferramentas de IA. Seu CLAUDE.md não ajuda só a sessão de hoje: ajuda toda sessão, todo membro do time e toda ferramenta de IA.
O Modelo de Maturidade
Times que adotam SDD tipicamente progridem por três estágios:
Estágio 1: Reativo (A maioria dos times hoje)
- Usam IA pra geração de código com prompts ad-hoc
- Debug frequente, reviews dolorosos
- Sem arquivos de contexto persistente
- Cada sessão começa do zero
Estágio 2: Estruturado (Adoção de SDD)
- CLAUDE.md / AGENTS.md estabelecidos
- Loop de 4 fases pra features complexas
- TDD integrado com workflows de IA
- Regras por diretório pra restrições de domínio
- Revisão de design antes da implementação
Estágio 3: Sistemático (Maturidade SDD completa)
- Repositório de specs mantido junto com o código
- Agentes IA atualizam documentos de spec enquanto trabalham
- Métricas rastreadas e otimizadas
- Onboarding de novos membros via docs de spec
- Consistência entre ferramentas (Cursor, Claude Code, Copilot seguem as mesmas specs)
A maioria dos times consegue chegar ao Estágio 2 num único sprint. O Estágio 3 se desenvolve naturalmente em 2-3 meses conforme os arquivos de spec acumulam e os padrões se estabilizam.
A Realidade de Engenharia
Agentes de IA são as ferramentas mais poderosas que já tivemos pra produzir código rápido. Também são as mais poderosas pra produzir bugs rápido. A diferença entre os dois resultados não é o modelo, o prompt nem a ferramenta: é a metodologia.
Vibe coding trata a IA como substituição da disciplina de engenharia. SDD trata a IA como amplificador da disciplina de engenharia. O loop de 4 fases não é burocracia. É o mesmo processo que senior devs sempre seguiram, agora tornado explícito pra que agentes de IA também sigam.
Seu agente IA é o junior mais produtivo que você já contratou. SDD é como você faz o onboarding dele direito: com requisitos claros, padrões documentados, tarefas definidas e critérios de aceitação verificáveis. Pula o onboarding e pega o caos que todo mundo reclama. Investe no onboarding e pega o multiplicador de produtividade que todo mundo sonha.
A escolha não é se vai usar agentes de IA. A escolha é se vai usar com disciplina de engenharia ou sem. SDD torna essa escolha óbvia.
Explore ferramentas relacionadas
Experimente estas ferramentas gratuitas do Pockit