Spec-Driven Development vs. vibe coding: uma comparação honesta de quem usa os dois
Vibe coding é real e útil. Também é a escolha errada para tudo que precisa estar correto. Um RCT do METR, um duelo de idempotência em pagamentos e o veredito honesto.
Vibe coding é real, funciona e eu uso. Mas ele tem um modo de falha que fica mais caro quanto mais capaz o modelo fica. Este artigo é a comparação honesta: o que é cada abordagem, onde cada uma quebra e a regra para decidir quando usar qual.
Se você está chegando agora em SDD, a metodologia completa está em O que é Spec-Driven Development?. Depois volte aqui para o confronto direto.
O que vibe coding é, de fato
Andrej Karpathy cunhou o termo num post no X em 2 de fevereiro de 2025. A descrição dele era precisa: você se entrega totalmente às vibes, abraça os exponenciais e esquece que o código sequer existe. Você não está escrevendo código. Está descrevendo uma intenção e aceitando o que o modelo produz. O nome é certeiro. Você programa no feeling.
Quando apresentou a ideia, Karpathy limitou explicitamente o vibe coding a projetos descartáveis de fim de semana. Esse limite importa. O próprio criador nunca propôs o vibe coding como metodologia de produção. Em menos de um ano, ele virou outra coisa: o jeito padrão como a maioria dos devs usa ferramentas de AI coding. O nome pegou, e a restrição original caiu pelo caminho sem ninguém notar.
O workflow tem três passos. Você descreve o que quer em linguagem natural. O modelo gera o código. Você dá um empurrão quando algo parece errado e gera de novo. Você não lê cada linha. Você conduz uma conversa. Quem dirige é o modelo.
É um trabalho genuinamente útil. Num protótipo descartável, você põe algo de pé em vinte minutos. Num script quebrado, três prompts costumam resolver. Para entender a cara real de um problema antes de se comprometer com uma arquitetura, vibe coding dá um ciclo de feedback rápido que nada mais oferece.
A pergunta não é se vibe coding funciona. É onde ele deixa de ser seguro.
O problema estrutural que vibe coding não resolve
Vibe coding otimiza para o momento em que algo roda pela primeira vez. Terminal verde. Uma página que renderiza. Uma função que retorna um valor. Esse momento parece progresso. A confiança do modelo é contagiosa.
A sensação começa a mentir no instante em que o trabalho precisa sobreviver à sessão. A IA vive num eterno presente. Cada conversa começa do zero: nenhuma lembrança da restrição que você adicionou às 22h, do edge case que você pensou no banho, da regra de negócio que você deixou num comentário e depois apagou. Tudo o que você não escreveu é reinventado. E não do mesmo jeito.
Não é um problema que espera um contexto maior para ser resolvido. Uma context window de um milhão de tokens diz ao agente o que o sistema é hoje. Não diz nada sobre o que ele deveria se tornar: sua intenção, suas restrições, os edge cases que importam para você, o que está fora de escopo de propósito. Uma janela maior deixa o agente mais bem informado sobre o presente e nem um pouco mais sábio sobre o alvo.
A formulação de Addy Osmani mostra onde fica o teto: a IA te leva a uns 70% do caminho, rápido. Os últimos 30% são onde mora o código de produção: edge cases, regras de negócio, invariantes, restrições de segurança, tudo o que não é óbvio no caminho feliz. Vibe coding não tem nenhum mecanismo de precisão nessa profundidade. Ele manda outro prompt e torce para o modelo preencher a lacuna direito.
Às vezes preenche. Muitas vezes, não. Você só descobre qual dos dois quando o código encontra algo real.
A spec é o que fornece a direção que o modelo não consegue inventar.
Os dados são piores do que você imagina
O que a pesquisa encontrou de fato
- 19%
- mais lentos com IA (resultado real)RCT do METR, 2025, devs experientes nos próprios codebases
- ~20%
- mais rápidos (o que acharam depois)Mesmos devs, mesmo estudo, conclusão errada
- 246
- issues reais testadas16 devs experientes, projetos open source grandes e maduros
- ~40%
- do código de IA sensível à segurança tinha uma vulnerabilidade conhecidaPearce et al., IEEE S&P 2023
Em 2025, o METR rodou um ensaio clínico randomizado com 16 devs open source experientes, trabalhando em 246 issues reais em codebases grandes e maduros, com modelos de fronteira: Cursor Pro com Claude 3.5 e 3.7 Sonnet. Os devs esperavam que a IA os deixasse 24% mais rápidos. Na prática, ficaram 19% mais lentos. E, depois, ainda acreditavam que ela tinha acelerado o trabalho em uns 20%.
Esse último número é o incômodo. A combinação de output confiante com erros invisíveis torna a perda de produtividade invisível de dentro da sessão. Você se sente rápido. Está mais lento. A distância entre as duas coisas é exatamente o que produz código errado-mas-confiante que vai para produção. (O METR publicou um follow-up no início de 2026 dizendo que modelos mais novos mostram resultados diferentes no estudo em andamento; os dados de 2025 continuam sendo a base de RCT mais rigorosa para aquela geração de ferramentas, e o mecanismo por trás não mudou.)
O quadro de segurança é um capítulo à parte. A pesquisa de Pearce et al., publicada no IEEE Security and Privacy, mostrou que cerca de 40% do código gerado em contextos sensíveis à segurança continha uma vulnerabilidade conhecida. O mecanismo importa mais que o número: em código gerado por IA, um defeito é uma lacuna na especificação. Essa lacuna volta toda vez que o código é regenerado, com outra cara, até uma spec codificar a restrição explicitamente.
A crítica fica mais desconfortável por um motivo específico: o problema piora à medida que os modelos melhoram. Um modelo mais fraco faz uma coisa pequena e obviamente errada. Um modelo capaz faz uma coisa grande, coerente, bem arquitetada e sutilmente errada. Capacidade amplifica a direção. Não a fornece.
Por que o mesmo bug sempre volta
Esse é o mecanismo que a maioria das comparações deixa passar, e é o argumento central a favor de trabalhar com spec.
Em código gerado por IA, um defeito não é um erro no código. É uma lacuna na especificação. Como a geração é não determinística, essa lacuna reaparece com outra cara toda vez que o código é regenerado, até uma spec codificar a restrição explicitamente. Você corrige o output. Não corrige o processo. A próxima regeneração traz a mesma classe de problema de volta, em outro formato.
Vibe coding não tem como fechar essa lacuna na origem. Cada correção é um ajuste local num output avulso. O agente começa cada sessão nova do zero, deduz a mesma premissa que faltava e produz a mesma classe de erro.
A solução não é um prompt melhor. É escrever a restrição num artefato durável a partir do qual o agente consiga executar. Escrever a spec é corrigir o processo em vez do output. Quando você corrige o processo, toda regeneração futura produz uma implementação segura automaticamente. Toda sessão começa da mesma base.
É por isso que o modo de falha é invisível de dentro da sessão. Você manda outro prompt, o problema some, o terminal fica verde. Parece resolvido. A lacuna continua aberta. Ela volta na próxima regeneração, na próxima mudança de contexto ou na próxima vez que outro agente mexer no mesmo código.
Um confronto concreto: a cobrança que cobra duas vezes
Pegue uma tarefa realista de porte médio: um endpoint de cobrança em que um retry do cliente nunca pode cobrar o cliente final duas vezes. Esse padrão aparece nos fluxos de pagamento que construí ao entregar, sozinho, uma fintech cripto de 13 apps em 70 dias. O estudo de caso tem os números completos.
O caminho do vibe: você escreve “crie um endpoint POST /v1/charges com idempotência”. O modelo gera sessenta linhas de handler em oito segundos. Parece completo. Não está. Idempotência exige estado: um registro de quais chaves já foram processadas. Sem uma constraint explícita no banco, dois retries concorrentes podem entrar em race condition, os dois leem “não encontrado” e os dois inserem uma cobrança nova. Cliente cobrado em dobro.
O caminho da spec escreve isto antes de existir qualquer código:
FR-1 WHEN a merchant POSTs a charge with a valid Idempotency-Key,
THE SYSTEM SHALL create at most one charge for that (merchant_id, key) pair.
FR-2 WHEN the same Idempotency-Key is replayed within 24h,
THE SYSTEM SHALL return the original charge and create no new one.
Data model:
charges(id, merchant_id, amount_cents, idempotency_key, status, created_at)
UNIQUE(merchant_id, idempotency_key) -- this enforces FR-1 at the database level
A constraint UNIQUE é toda a diferença. Não é uma checagem no código que uma race condition consegue driblar. É uma invariante no nível do banco que o agente precisa implementar, e ela sobrevive a toda regeneração. A frase EARS (WHEN/SHALL) deixa o comportamento explícito o bastante para o modelo não inventar um atalho. Usei exatamente esse padrão em todos os endpoints de pagamento daquela fintech. Nenhum cobrou em dobro em produção.
Vibe coding
- 01Prompt: crie um endpoint de cobrança com idempotência. 60 linhas em 8 segundos.
- 02Chave de idempotência guardada numa coluna, mas sem constraint: retries concorrentes disputam e os dois inserem.
- 03A cobrança dupla aparece no teste de carga (na melhor hipótese) ou em produção (no caso comum).
- 04Um novo prompt corrige o sintoma, não a lacuna. Na próxima regeneração: a mesma classe de bug.
- 05Próxima sessão: o modelo começa do zero. Nenhuma memória da discussão sobre a restrição.
Spec-Driven
- 01Regra EARS escrita primeiro: WHEN a mesma chave é reenviada, THE SYSTEM SHALL devolver a cobrança original.
- 02UNIQUE(merchant_id, idempotency_key) declarada no modelo de dados antes de existir código.
- 03O agente gera o handler com o caso de concorrência coberto na primeira passada.
- 04A restrição vive na spec. Toda regeneração produz uma implementação segura.
- 05Próxima sessão: o agente lê a spec. A invariante já está lá.
O caminho do vibe não é só mais lento no total. É mais lento de um jeito que você não enxerga até o código falhar. E falha de um jeito que volta toda vez que você regenera sem corrigir a spec.
Frente a frente no que importa
Vibe coding vs. Spec-Driven Development
| Critério (peso) | Vibe coding | Spec-Driven |
|---|---|---|
| Velocidade até o primeiro output (2) | 5 | 3 |
| Correção em features reais (3) | 2 | 5 |
| Custo de retrabalho (invertido: maior = menos retrabalho) (3) | 2 | 5 |
| Escala além de uma sessão (3) | 1 | 5 |
| Pontuação ponderada | 25 | 51 |
Scale 1-5 (5 = best). Highlighted column: winner by weighted score.
Vibe coding lidera em uma única dimensão de produção: velocidade até o primeiro output. Essa vantagem encolhe quando você conta os ciclos de retrabalho. A velocidade até o output correto conta outra história.
Onde os métodos diferem no que conta
Vibe coding versus Spec-Driven Development, lado a lado
| Dimensão | Vibe coding | Spec-Driven |
|---|---|---|
| Artefato principal | O último prompt | A spec aprovada |
| Memória entre sessões | Nenhuma. Começa do zero toda vez. | O arquivo da spec. O agente continua de onde você parou. |
| Garantia de correção | O que o modelo deduziu do prompt | O que a spec diz explicitamente |
| Quando um defeito volta | Outro prompt e torcer. A lacuna na spec continua aberta. | Atualizar a spec. A restrição fica selada para todas as execuções futuras. |
| Serve para | Protótipos, scripts, exploração numa sessão só | Features de produção, movimentação de dinheiro, compliance |
A habilidade que falta aos devs seniores
A maioria dos devs chegou às ferramentas de IA com a intuição de que o gargalo era a velocidade de implementação. Se o modelo escreve código mais rápido, eu fico mais rápido. O resultado do METR derruba essa premissa sem rodeios. Devs experientes nos próprios codebases ficaram mais lentos. O gargalo nunca foi a implementação. Foi a precisão da intenção.
Isso pesa mais nos devs seniores do que qualquer um espera, e o motivo é contraintuitivo. Experiência significa mais contexto implícito: mais conhecimento da história do sistema, mais premissas sobre o que é “correto”, mais decisões que parecem óbvias e nunca são escritas. Todo esse conhecimento tácito é invisível para o modelo. Quanto mais você sabe, maior a distância entre o que você disse e o que você quis dizer.
Um dev júnior descreve o que quer em termos mais explícitos, porque tem menos certeza do que é óbvio. Um dev sênior passa um rascunho para o modelo e espera que ele complete o resto como outro engenheiro experiente completaria. O modelo não completa assim. Ele faz pattern matching contra tudo o que já viu, e o padrão mais comum não é o seu sistema específico.
É por isso que o resultado do METR atinge com mais força justamente quem mais esperava ganhar com a IA. Os devs do estudo eram experientes, trabalhavam nos próprios codebases e usavam modelos de fronteira. Mesmo assim, perderam terreno. A causa não é capacidade. É a distância entre o que foi dito e o que precisava ser verdade.
A própria orientação da Anthropic deixa isso explícito: “deixar o Claude pular direto para o código pode produzir código que resolve o problema errado”. Anos de experiência não te ajudam a escrever prompts mais rápido. Ajudam a pensar com precisão no que precisa ser verdade antes de o código rodar: as restrições, os edge cases, as invariantes, o que está fora de escopo de propósito. Essa precisão, trancada na sua cabeça, é invisível para o modelo. Escrever uma spec a externaliza num artefato durável a partir do qual o agente consegue executar de verdade.
Aprofundei isso em Don’t Code, Specify: por que devs experientes estavam tendo resultados piores com ferramentas de IA, e o que mudou quando troquei o workflow padrão.
O veredito honesto: vibe quando errar é barato, spec quando não é
Não estou argumentando contra vibe coding. Eu uso o tempo todo, e você deveria usar também. O erro é aplicá-lo à classe errada de problema.
A Anthropic traça uma linha prática na própria orientação: “se você consegue descrever o diff em uma frase, pule o plano”. Uso esse teste o tempo todo. Uma frase significa baixa complexidade, baixo risco, provavelmente pouco em jogo. Quando a descrição pede três frases e uma lista de edge cases, isso é a spec.
A maioria dos projetos reais precisa dos dois modos. Faça no vibe o trabalho exploratório, para entender qual é o problema de verdade. Especifique tudo o que vai para produção. O erro é tratar todo trabalho como de uma categoria só. É assim que surgem vibe coders com incidentes em produção e escritores de spec sem nada entregue.
A ideia dos 70% aponta onde fica a emenda. Use vibe coding para chegar aos 70% rápido e depois mude para SDD para fechar a lacuna direito. Em sequência, sem competição.
FAQ
Vibe coding é ruim?
Não. Vibe coding é genuinamente útil para trabalho de baixo risco e feedback rápido: protótipos, scripts, spikes exploratórios. O problema não é a abordagem. É aplicá-la a trabalho em que correção, edge cases e continuidade entre sessões realmente importam.
O modo de falha é tratar vibe coding como padrão para todo desenvolvimento assistido por IA, inclusive features de produção em que os últimos 30% de correção sustentam tudo.
Foi o Karpathy que inventou o vibe coding?
Andrej Karpathy cunhou o termo em 2 de fevereiro de 2025, num post no X. Ele descreveu a prática como se entregar totalmente às vibes e esquecer que o código sequer existe. O conceito em si (aceitar o output da IA sem ler cada linha, conduzindo no feeling) já vinha surgindo na prática; ele deu nome e forma.
Ele também limitou explicitamente a ideia a projetos descartáveis de fim de semana. Essa restrição original se perdeu conforme o termo se espalhou. A maior parte dos problemas de vibe coding em produção vem direto de ignorar o escopo que Karpathy definiu.
Dá para combinar vibe coding e SDD?
Dá, e na maioria dos projetos reais você deveria. Vibe coding é excelente para explorar: você aprende qual é o problema construindo uma versão tosca rápido. A spec captura o que você descobriu e vira a base do build de produção.
Vibe para descobrir. Spec para entregar. Em sequência, sem competição.
Por que o mesmo bug de IA sempre volta?
Porque você corrigiu o output, não a spec. Em código gerado por IA, um defeito é uma lacuna na especificação. A geração é não determinística, então essa lacuna reaparece com outra cara toda vez que você regenera, até uma spec codificar a restrição explicitamente.
A correção é ajustar a spec, não só o código. O código é o output. A spec é a fonte. Esse é o mecanismo central por trás da recorrência de vulnerabilidades em código de IA sensível à segurança (Pearce et al., IEEE S&P 2023).
Por que devs seniores ficam mais lentos com IA?
Dois motivos. Primeiro, devs experientes carregam mais contexto implícito, ou seja, mais premissas que o modelo pode violar em silêncio. A distância entre o que você quis dizer e o que você disse é maior quando seu modelo mental do sistema é complexo.
Segundo, devs experientes costumam trabalhar em sistemas de produção em que os últimos 30% de correção sustentam tudo. É exatamente aí que o vibe coding empaca. O resultado do METR (19% mais lentos nos próprios codebases, com modelos de fronteira) chama atenção porque esses devs conheciam bem seus codebases. O gargalo era a precisão da intenção, não a familiaridade com o código.
Para onde ir agora
Vibe coding e SDD respondem a perguntas diferentes. O vibe pergunta: quão rápido consigo pôr algo para rodar? O SDD pergunta: como garanto que o que está rodando é o que eu realmente quis construir?
As duas perguntas importam. A habilidade é saber qual delas se aplica.
A newsletter
Don’t Code, Specify. Toda semana, agentes de IA em produção de verdade. Sem hype: o que funcionou e o que quebrou.
Assinar no Substack (abre em nova aba)