en
· 3 min de leitura

Como eu reviso código que um modelo escreveu

O mesmo padrão de qualquer pull request, mas os bugs moram em lugares diferentes. Aqui é onde eu olho.

aiaudit

Um pull request escrito por modelo parece melhor que a maioria dos humanos. Nomes consistentes, estrutura arrumada, comentários no lugar certo, um arquivo de teste que existe. Esse polimento é o primeiro problema, porque o revisor relaxa quando o código parece competente. Não reviso código gerado com mais leniência nem com mais rigor. Reviso com um mapa diferente de onde os bugs provavelmente estão, porque a distribuição mudou.

Mesmo padrão, distribuição diferente de bugs

Bugs humanos se concentram em cansaço e pressa: o off-by-one no fim de um dia longo, o copia-e-cola que não foi atualizado. Bugs de modelo se concentram em premissas: o código é uma implementação confiante da tarefa como o modelo a entendeu, e o mal-entendido costuma estar na fronteira entre a tarefa e o resto do sistema. A função está certa. O ponto de chamada, o caminho de erro, a história de concorrência e o contrato de dados são onde ele chutou. Então é ali que gasto a revisão.

O que leio primeiro

Leio o tratamento de erro antes do caminho feliz. Código gerado adora capturar uma exceção, logar e seguir em frente, o que transforma uma falha barulhenta numa silenciosa. Leio todo lugar em que um valor cruza uma fronteira: resposta de API parseada sem validação, linha do banco que assume um campo, data parseada sem timezone. Leio duas vezes qualquer coisa que toca dinheiro, identidade ou exclusão. E leio os imports, porque o modelo vai pegar uma biblioteca plausível, deprecada, ou que não é a que o projeto já usa para o mesmo trabalho.

Os padrões que se repetem

  • Erros engolidos: um try-catch que esconde uma falha que quem chamou precisava saber.
  • Interfaces inventadas: chamada a um método que não existe naquele objeto, ou existe com outra assinatura.
  • Falta de idempotência: um handler que funciona uma vez e erra no retry.
  • Parsing otimista: confiar em input externo porque o exemplo no prompt estava bem formado.
  • Lógica duplicada: um helper novo que reimplementa algo que a base já tinha, um pouco diferente.

Testes escritos pelo mesmo modelo

Testes gerados merecem desconfiança especial porque saíram do mesmo processo que produziu o código, do mesmo entendimento, com os mesmos pontos cegos. Um teste que afirma que o código faz o que o código faz é tautológico. Procuro se os testes incluem o caso que o autor da tarefa se importaria: input vazio, duplicata, timeout, chamador não autorizado. Se estão ausentes, os testes são documentação, não verificação, e escrevo os que faltam antes de aprovar, ou peço ao modelo, nomeando o caso específico.

O revisor é o dono

Quem aprova o merge é dono do comportamento. Isso sempre foi verdade e é mais verdade agora, porque não dá para perguntar ao autor do código por que ele fez uma escolha, e se der, ele vai inventar uma razão. Então a revisão é o momento em que o código ganha um dono. Não aprovo nada que eu não conseguiria explicar numa reunião de incidente. Se uma mudança gerada é grande demais para caber na minha cabeça, peço em partes, exatamente como pediria a uma pessoa. A velocidade do modelo é real. A revisão precisa ser tão lenta quanto sempre foi, porque a coisa sendo revisada não é o código. É o entendimento da pessoa que está prestes a assinar.