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.
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.