De Prompt Vago a Especificação Executável: BDD e TDD na Era do AI-Driven Development
← Voltar para Artigos

De Prompt Vago a Especificação Executável: BDD e TDD na Era do AI-Driven Development

TL;DR — IA generativa gera código que faz exatamente o que você pede. O problema é que o que você pede raramente é o que você precisa. Instruções vagas funcionam para a maioria dos casos — módulos simples, escopos isolados, comportamento óbvio. Mas quando a complexidade envolve interação entre estados, condições de contorno e comportamentos temporais, a ambiguidade da linguagem natural cobra seu preço. BDD (Given/When/Then) e TDD não são overhead quando se trabalha com IA. São a diferença entre gerar código rápido e gerar código certo rápido.


A Promessa e a Armadilha

Ferramentas de IA generativa tornaram possível gerar centenas — às vezes milhares — de linhas de código funcional em minutos. E na maior parte das vezes, funciona. Módulos isolados, lógica simples, CRUD: a IA entrega rápido e bem.

O problema aparece quando a complexidade é sutil. Quando o comportamento depende de estado, de timing, de condições de contorno que não cabem em uma instrução de duas linhas. Nesses casos, a IA não erra — ela implementa exatamente o que você pediu. E o que você pediu estava incompleto.

Este post é sobre como BDD e TDD transformam o resultado da geração de código por IA — não como práticas teóricas, mas como ferramentas práticas que mudam a qualidade do output.


Os 80% Fáceis

Quando a instrução é clara e o escopo é limitado, a IA funciona surpreendentemente bem. Módulos com responsabilidade única, interfaces bem definidas e comportamento previsível saem quase prontos na primeira tentativa.

Exemplos do que funcionou com instruções simples:

  • “Crie um módulo de cache com TTL e eviction” — implementação limpa, funcionou de primeira
  • “Adicione retry com exponential backoff” — lógica correta, sem bugs
  • “Implemente persistência de configurações do usuário” — código correto e idiomático

Nesses casos, a descrição em linguagem natural era suficiente porque o escopo era pequeno, o comportamento era óbvio e não havia interação complexa entre componentes.

A IA gera código que faz exatamente o que você pede. O problema é que o que você pede raramente é o que você precisa.


Os 20% Que Custam 80% do Tempo

Os problemas começaram quando a complexidade envolvia interação entre estados, condições de contorno e comportamentos temporais. São exatamente os cenários onde linguagem natural é ambígua — e onde a IA interpreta a ambiguidade da forma mais literal possível.

Caso 1: Processamento com janela temporal

Pedi “processamento com janela temporal” e o código fazia exatamente isso — mas recalculava a janela a cada ciclo de execução, em vez de respeitar a fase corrente. Resultado: comportamento instável. O comportamento que eu queria era:

DADO que o processo está em execução há X segundos na fase atual
QUANDO o sistema recalcula o ciclo de trabalho
ENTÃO o processo só é interrompido SE o tempo de execução excedeu o novo valor calculado
E uma vez interrompido nesta fase, NÃO reinicia até a próxima fase

Essa especificação teria eliminado a ambiguidade. Sem ela, a IA implementou a interpretação mais literal — e tecnicamente correta — do que eu pedi.

Caso 2: Estado inválido antes da inicialização

Uma função de verificação retornava true quando configuredTime > 0 && remainingTime == 0 && !running. Isso era verdade antes do sistema ser iniciado — o usuário tinha configurado um valor, mas não tinha dado Start. Resultado: loop infinito de desativação.

Um teste escrito antes da implementação teria capturado:

DADO que o processo foi configurado para 01:30
MAS o usuário não iniciou a execução
QUANDO verifico se o ciclo expirou
ENTÃO deve retornar false

Caso 3: Recuperação de estado após reinício

O estado era salvo periodicamente, mas ao reiniciar em menos tempo que o intervalo de salvamento, nada tinha sido persistido. Teste:

DADO que o sistema acabou de ser ativado
QUANDO houver interrupção imediata (crash, reinício)
ENTÃO o estado anterior deve ser recuperável no restart

Em todos esses casos, o bug não era da IA. O bug era da especificação — ou melhor, da falta dela.


BDD Como Linguagem de Especificação Para IA

O padrão que emergiu foi claro: os trechos do projeto onde usei Given/When/Then para descrever comportamento foram os que menos deram problema. E isso não é coincidência.

BDD fecha esse gap com “intenção estruturada” — e a sintaxe que viabiliza isso é Gherkin. “Processamento com janela temporal” pode significar três coisas diferentes para três engenheiros diferentes. Mas:

DADO [estado inicial]
QUANDO [evento ou condição]
ENTÃO [comportamento esperado]

…tem uma única interpretação. E a IA respeita essa unicidade.

Gherkin funciona aqui pelo mesmo motivo que funciona entre times: é uma linguagem ubíqua. Desenvolvedores, produto, QA — e agora a IA — leem a mesma especificação e entendem a mesma coisa. Não é código, não é linguagem natural livre. É um meio-termo estruturado o suficiente para ser preciso, mas legível o suficiente para ser validado por qualquer pessoa envolvida no problema. Quando a especificação é compartilhada sem ambiguidade entre todas as pontas, o alinhamento não depende de reunião — depende do artefato.

Mais importante: especificações BDD em Gherkin permitem testar lógica de negócio antes da IA gerar código. Você escreve o cenário, valida mentalmente se ele cobre o comportamento correto, e só então pede a implementação. Isso inverte o ciclo de feedback — em vez de gerar código, testar, encontrar bug, pedir correção, você especifica, valida, e gera código certo na primeira tentativa.

É um “superpoder oculto”: a capacidade de definir o QUÊ e o POR QUÊ antes da IA resolver o COMO. Especificações servem como documentação viva — e como contrato entre o humano e a máquina.


TDD Como Validação do Entendimento da IA

Se BDD é a linguagem de especificação, TDD é o feedback loop que garante corretude.

A saída de uma IA é não-determinística. O mesmo prompt pode gerar implementações diferentes. Testes são a âncora que garante que, independente de como a IA resolveu o problema, o comportamento está correto.

O workflow que funciona melhor na prática é:

  1. Escreva o teste primeiro — ele é a especificação executável do comportamento desejado
  2. Valide o teste — se o teste parece certo, a especificação está certa
  3. Peça a implementação — a IA gera código para passar no teste
  4. Rode o teste — se passou, o comportamento está correto
  5. Refatore — peça melhorias mantendo os testes verdes

O ponto chave: escrever o teste primeiro permite usar o teste para entender o que a IA entendeu do seu pedido, antes dela gerar a implementação. Se o teste não faz sentido, o problema está na especificação — e você corrige antes de gerar código errado.

Na prática, o workflow test-first produz significativamente menos bugs que o test-after. Testes são especificações executáveis — mais precisas que prompts em linguagem natural.


”Explique Antes de Implementar”

Além de BDD e TDD, o hábito mais valioso que descobri foi pedir para a IA explicar o que vai fazer antes de fazer.

Em um caso, eu precisava de um algoritmo de otimização. Em vez de pedir a implementação direto, pedi para a IA explicar a abordagem que usaria. Na explicação, identifiquei que os parâmetros gerados seriam agressivos demais para o contexto. Mudamos a estratégia sem gerar uma única linha de código errado.

Em outro caso, pedi uma auditoria de quais variáveis não estavam sincronizando entre o sistema local e o serviço remoto. A IA encontrou que nenhuma mudança local estava sendo propagada. Corrigimos antes de virar bug em produção.

Esse padrão — explique, questione, implemente — não é intuitivo. A tendência natural é pedir código direto. Mas a IA é melhor analista do que implementadora quando você dá o direcionamento certo.


O Padrão Que Emergiu

Olhando para a prática como um todo, o workflow que produz os melhores resultados é:

EtapaDescrição
ExplainPeça para a IA explicar a abordagem antes de implementar
SpecifyDescreva o comportamento com Given/When/Then
TestEscreva (ou peça) o teste antes da implementação
ImplementPeça a implementação com o teste como referência
FeelTeste na prática, sinta a fricção, observe os edge cases
IterateAjuste a especificação e repita

Na prática, a parcela de código que recebe especificação estruturada (BDD/TDD) consome mais tempo de preparação — mas previne a grande maioria dos bugs. O restante — gerado com instruções vagas — funciona, mas produz a maioria dos problemas que precisam de correção.

A desproporção é reveladora: investir tempo em especificação é a forma mais eficiente de usar IA para gerar código.


Entregar Rápido vs. Sustentar no Longo Prazo

A IA não substitui engenharia de software — amplifica ela. As mesmas práticas que tornam um engenheiro eficaz sem IA — decomposição de problemas, especificação clara, testes antes de implementação, questionamento de premissas — são exatamente as que tornam o uso de IA drasticamente mais eficiente. BDD e TDD não são overhead. São a diferença entre “gerar código rápido” e “gerar código certo rápido”.

Mas a questão vai além de qualidade de código. Qualquer combinação de engenheiro e IA consegue entregar software funcionando. A diferença real aparece depois — quando o código precisa ser mantido, evoluído, operado. É essa a distinção que importa: entregar software vs. entregar software pensando em como ele vai ser operado no longo prazo. Quem especifica antes de implementar não está sendo mais lento — está evitando a dívida técnica que transforma velocidade inicial em atrito permanente.

O repertório do engenheiro — saber o que pedir, perceber quando algo está indo na direção errada, sentir que uma decisão de arquitetura vai cobrar caro depois — não vem da ferramenta. Vem de experiência. A IA é um multiplicador claro. Mas sem repertório para questionar o que ela entrega, vira uma forma mais rápida de errar.

Na CERC, é assim que temos escalado o uso de IA na engenharia. BDD, TDD e o hábito de especificar antes de gerar código não são práticas que adotamos apesar da IA — são práticas que adotamos por causa dela. O resultado tem sido consistente: mais eficiência, mais qualidade, e um time que confia no que entrega.


Na CERC, IA não é ferramenta lateral — é parte de como construímos software. Se você quer trabalhar em um ambiente onde práticas de engenharia importam e tecnologia de ponta resolve problemas reais — estamos contratando.


Este post foi escrito por: Vitor Melon | Head de Engenharia — Plataforma de Arranjos de Pagamentos.