Pare de atirar no escuro. O processo de 4 fases que transforma debugging de adivinhação em investigação.
Debugging sistemático não é mais rápido que debugging aleatório em cada bug individual — mas é dramaticamente mais rápido em média, porque elimina as tentativas que não funcionam antes de tentar. O processo de 4 fases aplica o método científico ao diagnóstico de bugs.
Documentar exatamente o que está acontecendo: mensagem de erro completa, stack trace, condições de reprodução, frequência.
Listar 3-5 possíveis causas, em ordem de probabilidade. Não começar a testar ainda — primeiro pensar.
Para cada hipótese, criar um teste mínimo que a confirme ou descarte. Testar uma hipótese por vez, registrando o resultado.
A hipótese confirmada é a causa raiz. Corrigir especificamente essa causa, não o sintoma. Verificar com evidência.
Um dos bugs mais insidiosos em sistemas assíncronos é o race condition causado por sleep fixo. O agente usa sleep porque parece simples, mas sleep não garante que a condição que você está esperando realmente se cumpriu — apenas que passou tempo suficiente para que provavelmente tenha se cumprido.
await startServer();
await sleep(2000); // esperamos 2s
const res = await fetch('/health');
// falha se servidor demorou 2.1s
await startServer();
await waitUntil(
() => fetch('/health').then(r => r.ok),
{ timeout: 10000, interval: 100 }
);
// só continua quando o servidor responder
Instrua o agente explicitamente
Agentes usam sleep por padrão porque está no treinamento deles. Instrua: "Nunca use sleep fixo para sincronização. Use polling de condição com timeout e intervalo configurável."
Um dos problemas mais frustrantes com agentes é que eles frequentemente declaram "bug corrigido" antes de verificar se a correção realmente funciona. A skill debugging instrui o agente a exigir evidência verificável antes de qualquer declaração de sucesso.
npm test mostrando que os testes passamO que NÃO é evidência
Para bugs em sistemas complexos, as 4 fases básicas não são suficientes. Técnicas avançadas de rastreamento permitem encontrar origens não intuitivas, como bugs que surgem da interação de dois sistemas corretos individualmente.
Quando o bug existe na versão atual mas não em um commit anterior, git bisect faz busca binária automática no histórico de commits para encontrar exatamente quando o bug foi introduzido.
Criar a versão mais simples possível do sistema que ainda reproduz o bug. Cada componente removido que mantém o bug é uma hipótese eliminada.
Adicionar logs com contexto (timestamp, request ID, user ID, estado relevante) em pontos estratégicos para criar uma trilha rastreável do fluxo de execução.
Mudar uma variável de cada vez (input, ambiente, configuração, dados) para identificar qual combinação específica causa o bug.
Corrigir um bug sem adicionar proteção contra regressão é incompleto. A regressão ocorre quando uma correção é desfeita por uma mudança futura — seja por outro agente, por refatoração ou por nova feature. Defense-in-depth cria múltiplas camadas que protegem a correção.
Bugs que voltam são os mais frustrantes de debugar porque parecem resolvidos. Defense-in-depth garante que se o bug tentar voltar, ele seja detectado antes de chegar à produção.
Se o código do módulo anterior tem bugs, use-os como exercício. Se não tem, introduza um bug propositalmente para praticar. O objetivo não é a velocidade — é executar o processo de 4 fases sem pular etapas.
Critério de conclusão
Bug corrigido com evidência real, teste de regressão adicionado, e um comentário explicando por que a correção existe. O processo foi seguido sem pular etapas.