Artigo 10 de 12
Kiro & AWS

Spec-driven development vs vibe coding: quando usar cada um (com exemplos lado a lado)

Os dois modos têm lugar. O erro não é escolher vibe coding — é usá-lo onde o custo do erro é alto. Aqui está o contraste, com a mesma feature escrita das duas formas.

17 de julho de 2026 · Prompt & Deploy

TL;DR

  • Vibe coding é conversar com o agente e deixar o código emergir do diálogo. Brilha em exploração, protótipo e scripts descartáveis. Fracassa quando vira produção sem deixar rastro do porquê.
  • Spec-driven development estrutura a intenção dentro do repositório em três fases: requirements.md (EARS) → design.mdtasks.md. Você aprova cada porta antes de gerar código.
  • Lado a lado: a mesma feature (avaliações de produto) sai como um prompt único no vibe e como três artefatos versionados no spec. O contraste é o rastro de decisão.
  • Bugfix specs geram um bugfix.md com current / expected / unchanged — o contrato que impede o fix de causar regressão.
  • A regra: escolha pelo custo do erro, não por hábito. O Kiro faz os dois modos; a decisão é sua.

Quando o vibe coding “deu certo demais”

Você abriu o chat numa sexta à tarde para testar uma ideia. “Faz um endpoint que aceita avaliações de produto.” Trinta segundos depois havia código rodando. Funcionou. Você ajustou uma coisa ou outra no diálogo, tudo por conversa, e no fim do dia tinha um protótipo que fazia exatamente o que você imaginou.

O problema começou na segunda-feira, quando alguém disse “isso é bom, bota em produção”. Aquele protótipo nascido de uma conversa efêmera não tinha requisito escrito, não tinha decisão de arquitetura registrada, não tinha teste de borda. A regra de “só quem comprou pode avaliar” estava na sua cabeça, não no código. O limite de tamanho do texto? Ninguém definiu. Três semanas depois, o dev que herdou aquilo abriu um PR que quebrou a moderação sem perceber — porque o contexto nunca existiu fora do chat que já tinha evaporado.

Isso é o vibe coding que deu certo demais: rápido o suficiente para parecer pronto, informal o suficiente para virar dívida técnica. O erro não foi usar vibe coding. Foi promover a produção algo que nasceu sem contrato. Este artigo é sobre saber a diferença — e mostrar, com a mesma feature, como cada modo se parece.

Vibe coding não é o vilão. O vilão é confundir “funciona na minha máquina” com “está especificado”.

O que é vibe coding (e onde ele brilha)

Vibe coding é o modo conversacional: você descreve o que quer em linguagem natural, o agente gera, você reage ao resultado e itera. Não há artefato intermediário — a intenção vive no diálogo. O Kiro foi construído explicitamente para ir além disso, mas ainda oferece o vibe mode porque ele é a ferramenta certa em vários cenários.

Onde o vibe coding brilha:

  • Exploração rápida: você quer entender se uma lib serve, como uma API se comporta, se uma abordagem é viável. Escrever spec antes de saber o que você quer é burocracia.
  • Protótipos sem meta clara: um spike de 40 linhas para validar uma hipótese. Se der certo, você reescreve com calma; se não, você joga fora.
  • Scripts descartáveis e tarefas pontuais: um one-off para migrar um CSV, um comando que você roda uma vez.
  • Aprendizado: quando o objetivo é entender um domínio novo, o diálogo é mais rápido que a estrutura.

O limite aparece quando o código deixa de ser descartável. Em produção, o vibe coding tem três custos ocultos:

  1. A intenção evapora. O “porquê” ficou no chat, que ninguém versiona. O próximo dev herda o “o quê” sem o “porquê”.
  2. As bordas ficam implícitas. Regras de validação, permissões e casos de erro que você “sabia” nunca viraram requisito explícito — e por isso não viraram teste.
  3. A regressão fica barata de causar e cara de detectar. Sem um contrato do que não pode mudar, qualquer alteração futura é uma aposta.

O que é spec-driven development (as três fases)

Spec-driven development inverte a ordem: em vez de o código emergir da conversa, a intenção é estruturada dentro do repositório, versionada junto com o código e revisável em diff. No Kiro, toda spec vive em .kiro/specs/<nome-da-spec>/ e gera três arquivos, produzidos num fluxo de três fases onde você aprova cada porta antes de avançar:

  • Fase 1 — requirements.md: user stories com critérios de aceitação em notação EARS (Easy Approach to Requirements Syntax).
  • Fase 2 — design.md: arquitetura, diagramas de sequência, fluxo de dados, tratamento de erros e estratégia de testes.
  • Fase 3 — tasks.md: tarefas discretas e rastreáveis, que você roda individualmente ou todas de uma vez.

O fluxo tem variantes: Requirements-First e Design-First para Feature Specs, e um Quick Plan que gera os três artefatos sem os approval gates quando você já sabe o que quer. As specs ficam sincronizadas com o código conforme ele evolui — não é documentação que apodrece.

A chave é o que muda no seu papel: você deixa de aprovar um blob de código que não escreveu e passa a aprovar decisões que você tomou. Cada fase é um gate.

Você não revisa uma caixa-preta. Você aprova requisitos, depois um design, depois um plano — cada um em texto, cada um em diff.

Lado a lado: a mesma feature nos dois modos

Vamos pegar uma única feature — um sistema de avaliações de produto — e escrevê-la das duas formas. O contraste fala por si.

(a) No vibe coding: um prompt, um transcript

No vibe mode, a feature inteira nasce de uma conversa. O transcript é mais ou menos assim:

você> Faz um endpoint pra criar avaliação de produto. Nota de 1 a 5 e um texto.

kiro> Criei POST /products/:id/reviews em src/routes/reviews.ts.
      Aceita { rating, body } e persiste no banco. Quer que eu adicione validação?

você> adiciona sim. e só quem comprou pode avaliar

kiro> Feito. Adicionei checagem na tabela orders antes de inserir. Retorno 403
      se não houver compra. O texto tem limite? Coloquei 2000 chars por padrão.

você> pode ser. beleza, tá bom assim

Funciona. Mas note o que não existe no repositório depois dessa conversa: nenhum registro de que o limite é 2000 caracteres (foi um “default” que o agente sugeriu e você aceitou de passagem), nenhuma menção a moderação de conteúdo, nenhuma decisão sobre o modelo de dados e nenhum teste garantindo o 403. O rating “1 a 5” foi dito, mas não há garantia de que valores fora da faixa sejam rejeitados. Tudo isso mora no chat — que some.

(b) No spec-driven: três artefatos versionados

A mesma feature, como spec. Primeiro o requirements.md, onde cada regra vira um critério EARS com gatilho explícito:

# Requisitos — Sistema de Avaliações de Produtos

## User Story 1: Criar avaliação
Como cliente autenticado, quero avaliar um produto que comprei,
para ajudar outros compradores.

### Critérios de aceitação (EARS)
- WHEN um cliente autenticado envia uma avaliação com nota de 1 a 5,
  THE SYSTEM SHALL persistir a avaliação e associá-la ao produto e ao usuário.
- IF o usuário não comprou o produto,
  THEN THE SYSTEM SHALL rejeitar a avaliação com HTTP 403.
- WHILE o texto da avaliação exceder 2.000 caracteres,
  THE SYSTEM SHALL bloquear o envio e exibir mensagem de validação.
- WHERE a avaliação contém linguagem sinalizada pelo filtro,
  THE SYSTEM SHALL marcá-la como "pendente de moderação".

Repare que o EARS não deixa a regra implícita: o 403, o limite de 2.000 e a moderação — que no vibe eram sussurros no chat — agora são requisitos com gatilho (WHEN, IF, WHILE, WHERE) que você aprovou.

Depois o design.md, onde a arquitetura e o modelo de dados ficam explícitos:

## Arquitetura

​```mermaid
sequenceDiagram
    participant U as Cliente
    participant API as Review API
    participant DB as PostgreSQL
    U->>API: POST /products/{id}/reviews
    API->>DB: verifica compra (orders)
    DB-->>API: compra confirmada
    API->>DB: INSERT review (status=published)
    API-->>U: 201 Created
​```

## Modelo de dados
| Campo | Tipo | Nota |
|-------|------|------|
| id | uuid | PK |
| product_id | uuid | FK products |
| user_id | uuid | FK users |
| rating | int | 1..5 |
| body | text | <= 2000 chars |
| status | enum | published \| pending \| rejected |

E por fim o tasks.md, onde cada tarefa aponta de volta para o requisito que a justifica (o (Req 1)), tornando cada diff futuro auditável contra uma decisão:

# Plano de implementação

- [ ] 1. Criar migration da tabela reviews (Req 1)
- [ ] 2. Implementar ReviewRepository com verificação de compra (Req 1)
  - [ ] 2.1 Testes unitários do repositório
- [ ] 3. Endpoint POST /products/{id}/reviews (Req 1)
  - [ ] 3.1 Teste de integração (403 sem compra)
- [ ] 4. Filtro de moderação (Req 1 - WHERE)

O contraste: no vibe, o resultado foi código sem contrato. No spec, o mesmo código veio acompanhado de um requisito revisável, um design explícito e um plano rastreável. Quando você roda “Run all Tasks”, o Kiro monta um grafo de dependências e agrupa as tarefas independentes em waves — a Wave 1 tem tudo que não depende de nada (a migration e o scaffolding, por exemplo), rodando em paralelo com a ordem garantida.

O vibe entrega o “o quê”. O spec entrega o “o quê”, o “porquê” e o “não pode”.

Bugfix specs: corrigir sem regredir

Feature nova é só metade da vida real. A outra metade é o bug em produção — e é aqui que o custo do erro dispara, porque um fix mal contido causa regressão. Para isso o Kiro tem as Bugfix Specs, que geram um bugfix.md descrevendo o comportamento em três eixos: current (o que acontece hoje, o bug), expected (o que deveria acontecer) e unchanged (o que não pode mudar).

O unchanged é o coração do contrato anti-regressão. Ele diz explicitamente ao agente o que está fora do escopo do fix. Imagine que apareceu um bug de avaliação duplicada — o mesmo usuário consegue avaliar duas vezes o mesmo produto. Um bugfix spec para isso:

# Bugfix — Avaliação duplicada

## current
Um cliente autenticado consegue enviar múltiplas avaliações para o mesmo
produto. Cada POST /products/{id}/reviews cria uma nova linha, sem checar
se já existe avaliação daquele usuário para aquele produto.

## expected
O sistema deve permitir no máximo uma avaliação por (user_id, product_id).
Um segundo envio deve retornar HTTP 409 Conflict, sem criar nova linha.
A operação deve ser idempotente sob concorrência.

## unchanged
- A regra de 403 para quem não comprou o produto NÃO muda.
- O limite de 2.000 caracteres do corpo NÃO muda.
- O fluxo de moderação (status=pending) NÃO muda.
- O contrato de resposta do caso de sucesso (201) NÃO muda.

Com esse contrato, o agente sabe exatamente onde pode mexer (adicionar uma constraint de unicidade e o tratamento de 409) e o que não pode encostar. A seção unchanged é a linha que ele não cruza — e é o que te deixa mergear o fix com confiança, porque os testes de regressão validam justamente aquilo que deveria continuar igual. O fluxo, aliás, começa por uma fase de Bug Analysis (equivalente à fase de Requirements das feature specs) antes de ir para o design e as tasks.

Tabela de decisão: qual modo para qual situação

A escolha não é ideológica. É sobre o custo do erro e a vida útil do código. Aqui está o mapa, alinhado com o “Use Specs when / Use Vibe when” da documentação:

SituaçãoModoPor quê
Feature complexa, com regras de negócio e bordasSpecO EARS torna cada regra explícita e testável antes do código existir
Bug onde a regressão é caraSpec (Bugfix)O unchanged é o contrato que impede o fix de quebrar o resto
Código que vira documentação para o timeSpecA intenção fica versionada e sincronizada, não evapora no chat
Requisitos ou design que precisam iterarSpecCada fase é um gate revisável em diff antes de gastar esforço em código
Exploração rápida de uma lib ou abordagemVibeEscrever spec antes de saber o que você quer é burocracia
Protótipo sem meta clara / spikeVibeO código é descartável; o contrato seria overhead
Script one-off / tarefa pontualVibeVida útil curta, custo do erro baixo
Aprender um domínio novo pela conversaVibeO diálogo é mais rápido que a estrutura

A leitura prática da tabela: quanto mais longa a vida útil do código e mais caro o erro, mais o pêndulo aponta para spec. Quanto mais descartável e barato, mais aponta para vibe. Você pode até começar no vibe e, quando o protótipo prova valor, promovê-lo a uma spec — o vibe vira o rascunho, a spec vira o compromisso.

A verdade: cada modo tem um custo e um contexto

Nenhum dos dois modos é grátis, e é honesto admitir isso.

O spec-driven tem um custo de setup: você gasta tempo escrevendo requisitos e aprovando design antes de ver a primeira linha de código rodar. Para um spike de 40 linhas, esse overhead é ridículo — você estaria burocratizando a exploração. Spec num protótipo descartável é cerimônia sem propósito.

O vibe coding tem um custo diferido: ele é barato agora e caro depois, quando a intenção precisa ser recuperada, quando a borda não testada estoura, quando a regressão passa despercebida. Vibe em produção sem contrato é uma dívida com juros compostos.

A maturidade não é escolher um lado. É reconhecer que são ferramentas diferentes para custos de erro diferentes — e que o mesmo dev usa os dois no mesmo dia. Você entra no vibe de manhã para validar uma hipótese, e abre uma spec de tarde para a feature que vai pra produção. O Kiro foi desenhado para os dois: ele nasceu do spec-driven development (“vai além do vibe coding”), mas mantém o modo conversacional para quando ele é a escolha certa. A ferramenta não te obriga a nada; ela te dá o instrumento certo e devolve a decisão para onde ela deve estar — com você.

A pergunta certa nunca foi “spec ou vibe?”. É “quanto custa se isto der errado?”.

Principais aprendizados

  • Vibe coding não é dívida técnica por natureza — vira dívida quando promovido a produção sem contrato. Em exploração e protótipo, ele é a ferramenta certa.
  • Spec-driven mantém a intenção no repositório: requirements.md (EARS) → design.mdtasks.md, cada fase um gate que você aprova.
  • O contraste lado a lado é o rastro de decisão: o vibe entrega código; o spec entrega código + o porquê (EARS) + o design + o plano rastreável (Req N).
  • unchanged é o contrato anti-regressão das bugfix specs — a linha que o agente não cruza ao corrigir.
  • Escolha pelo custo do erro, não por hábito: vida útil longa e erro caro → spec; descartável e barato → vibe.
  • O Kiro faz os dois — a decisão de qual usar continua sendo sua.

Referências


Este artigo foi publicado originalmente no Medium. Preços, nomes de modelos e detalhes de produto refletem o estado do Kiro em meados de 2026 e podem mudar — confirme em kiro.dev antes de tomar decisões. Este é um conteúdo educacional independente, sem vínculo oficial com a AWS.

Tags: kiro, spec-driven-development, vibe-coding, aws, produtividade

Publicado originalmente em prompt.victorbatistax.com. Se você chegou por outra plataforma, esta é a versão canônica.