Saltar para o conteúdo
Telmo da Silva/hub
Verificar código de IA

O Estagiário Que Nunca Diz Que Não Sabe

A certeza com que a IA responde não é prova de nada. É só certeza.

Por Telmo da Silva

Ir para o registo de verificação ↓

Porque escrevi este guia

Nos últimos anos passei de escrever scripts para automatizar tarefas repetitivas a construir software em produção, com IA a fazer boa parte do trabalho de escrita. O que mudou não foi a minha capacidade de escrever código, foi a minha capacidade de confiar nele sem verificar. A IA nunca hesita. Entrega uma função, uma explicação de porque funciona, e segue para a próxima, com o mesmo tom seguro quer esteja certa quer esteja completamente errada.

Não é queixa da ferramenta, é um facto sobre ela que muda o que se exige de quem a usa. Antes, escrever código lento era o que travava um projeto. Agora, para quem usa IA a sério, escrever deixou de ser o gargalo. Verificar é.

Uma honestidade sobre o que aqui está

Não sou engenheiro de software de formação, sou autodidata na parte técnica. O que trago é a mesma disciplina de qualidade que apliquei durante quase uma década a avaliar pessoas: critérios escritos, mais do que um avaliador, e a desconfiança de qualquer resposta convincente que ainda não tenha prova a apoiá-la. Hoje aplico-a a submeter tudo o que construo a vários agentes de IA em papel de auditor, antes de qualquer coisa chegar a produção. Os dois casos reais que uso neste guia, uma ponte entre duas blockchains e uma plataforma de NFTs, são meus, embora o código seja de repositório privado: o que mostro é o processo e o resultado, não a implementação.

Serve para quem usa IA para construir a sério e sente que está a confiar demasiado depressa, e para quem já foi surpreendido por um bug que a IA jurava que não existia.

A certeza com que a IA responde não é prova de nada. É só certeza.

8 capítulos, cerca de 12 minutos. Os capítulos 5 e 6 são os dois casos reais, o resto é o método por trás deles.

01O Estagiário Que Nunca Diz Que Não Sabe

Um estagiário decente, mais cedo ou mais tarde, diz "não tenho a certeza, deixa-me confirmar". É um dos sinais mais fiáveis de que se pode confiar nele: sabe onde está o limite do que sabe. A IA raramente faz isso sem lhe ser pedido explicitamente: justifica a escolha com seis alíneas convincentes, no mesmo tom seguro quer o código esteja certo quer esteja completamente errado.

Isto não é uma falha pontual que a próxima versão do modelo resolve. É uma característica de como estas ferramentas respondem: o texto mais provável, dado o que já foi escrito, não é o mesmo que o texto correto. Às vezes coincidem. Confundir as duas coisas é o erro que este guia tenta evitar.

O que isto não é

Não é um guia contra usar IA para construir. Uso-a todos os dias e escrevi outro guia inteiro sobre isso ("O Colega Que Leu Tudo", também nesta biblioteca). É sobre o hábito que falta a quase todos os que a usam: verificar antes de confiar, não confiar e verificar só quando algo já correu mal.

O resto deste guia é sobre como construir esse hábito sem ele consumir mais tempo do que aquele que a IA te poupou.

02Construir Ficou Fácil. Verificar Não.

Escrever código deixou de ser lento. Nos projetos que construo hoje, protocolos de blockchain, infraestrutura de pagamentos, sistemas com IA, uma boa parte da primeira versão sai em segundos. O que mudou não foi só a minha capacidade de escrever código. Foi a rapidez com que consigo produzi-lo, e é aí que está a armadilha.

Quando escrever era lento, o próprio ritmo obrigava a pensar em cada linha. Quando escrever fica rápido, o gargalo desloca-se: já não é produzir código, é decidir se o código que acabaste de receber está certo. Se a forma de decidir isso não mudar ao mesmo ritmo que a forma de o produzir, o resultado é mais código a chegar a produção sem ter sido pensado por ninguém, humano ou não.

Um teste simples

Pega no último ficheiro que a IA te escreveu e que aceitaste sem alterar uma linha. Consegues explicar, sem reabrir o código, o que acontece se a função for chamada duas vezes seguidas com o mesmo argumento? Se não conseguires, ainda não verificaste, só leste.

Os capítulos seguintes são sobre como fechar essa distância: primeiro o princípio (nunca confiar num avaliador só), depois o método (um teste que prova, não uma explicação que convence), depois dois casos reais onde isso apanhou algo que ia passar.

03Um Avaliador Sozinho Não Chega (Nem Quando É Só Um Agente)

A ideia de que código não devia ser confiado só porque a pessoa que o escreveu acredita nele não é nova. Já em 1971, Gerald Weinberg descrevia, no livro que viria a popularizar a ideia de "programação sem ego", como um programador convencido da própria correção é sistematicamente pior a encontrar os próprios erros do que uma segunda pessoa a rever o mesmo código de fora. Não é falta de competência, é estrutural: quem escreveu o código já decidiu, ao escrevê-lo, que aquele era o caminho certo.

Pedir a um agente de IA para rever o código que outro agente escreveu tem exatamente o mesmo ponto cego, só que mais difícil de notar. Parece revisão independente porque é outra conversa, outro pedido, por vezes outro modelo. Mas se os dois herdam a mesma lacuna, seja no treino, seja no contexto que lhes deste, os dois vão validar o mesmo erro com a mesma confiança.

Na prática, aplico três coisas: peço a mais do que um agente para atacar o mesmo código, com instruções deliberadamente diferentes ("tenta partir isto" em vez de "isto está correto?"), reviso eu próprio o que os agentes concordam entre si com mais desconfiança do que aquilo em que discordam, e trato qualquer aprovação unânime e imediata como um sinal para olhar com mais cuidado, não menos.

O mesmo ponto cego, noutro contexto

É a mesma ideia que descrevo, aplicada a avaliar pessoas em vez de código, no guia sobre o outro lado da entrevista deste site: quem decide sozinho tem um ponto cego que só uma segunda avaliação independente revela.

04O Teste Que Prova, Não a Explicação Que Convence

Uma boa explicação de porque um código funciona é fácil de produzir e fácil de aceitar, e não prova nada. Michael Feathers, no livro sobre trabalhar com código legado que ficou como referência da área, populariza a ideia do "teste de caracterização": em vez de perguntar se o comportamento está certo, escreve-se primeiro um teste que capta o comportamento real, tal como é, e só depois se decide se esse comportamento devia mudar.

Aplicado a código de IA, o princípio fica assim: antes de aceitares uma correção, escreve um teste que reproduza o problema original, falha com o código antigo, e só o marca como resolvido quando esse mesmo teste passa. Não perguntes à IA se corrigiu. Faz o teste perguntar.

Resposta fraca, e porquê

Corrigi o problema: agora a função valida o valor antes de o processar, por isso já não deve falhar.

"Deve" é a palavra a assinalar. É uma previsão sobre o comportamento, não uma demonstração dele. Sem um teste que reproduza o cenário exato que falhava antes e passe agora, isto é uma opinião com vocabulário de certeza.

É a mesma regra que uso em produção: uma falha só é considerada corrigida quando existe um teste que a reproduz. Não é burocracia extra, é a diferença entre saber e confiar que se sabe.

05Falhas Reais Numa Ponte Entre Duas Blockchains

Um dos sistemas que construí move valor entre duas blockchains diferentes, com uma prova criptográfica a garantir que nada é criado do nada. Antes de qualquer avanço sério, submeti-o a uma auditoria adversarial com vários agentes de IA independentes, cada um instruído para tentar ativamente encontrar uma forma de quebrar o sistema, não para confirmar que estava bem feito.

A camada principal de segurança foi confirmada sólida. Mas a auditoria encontrou falhas reais, coisas que eu, sozinho, tinha deixado passar por estarem fora do caminho óbvio que eu próprio tinha desenhado:

  • Uma forma de forjar um certificado singleton que devia ser único, sem passar pela verificação normal. Em linguagem simples: conseguir criar uma segunda cópia de um documento que o sistema inteiro assume só existir uma vez.
  • Uma janela demasiado curta contra reorganizações da cadeia, que podia deixar valor a ser movido sobre um bloco que ainda podia desaparecer. Em linguagem simples: levantar dinheiro com base num cheque que ainda pode ser cancelado.
  • Falta de uma etiqueta de domínio por perna da operação, que em teoria permitia reutilizar uma prova destinada a um sentido no sentido contrário. Em linguagem simples: o mesmo bilhete a servir para a ida e para a volta, quando só devia servir para uma.
  • Uma chave de verificação de reserva (placeholder) que, se esquecida em produção, aceitava provas que não deviam ser aceites. Em linguagem simples: a fechadura provisória de obra, que abre com qualquer chave, deixada na porta final.

As quatro foram corrigidas, cada correção com um teste próprio a reproduzir o ataque original e a confirmar que deixa de funcionar. Nenhuma delas era visível a olhar para o caminho feliz, o caso em que tudo corre como esperado. Todas viviam no caminho que só aparece quando alguém pergunta ativamente "como é que eu quebrava isto de propósito?", que é exatamente a pergunta que sozinho raramente fazes ao teu próprio trabalho.

06Quando o Bug Impede o Próprio Criador de Vender

Noutro projeto meu, uma plataforma onde artistas criam e vendem coleções digitais, apareceu um bug com uma assinatura muito específica: o próprio criador de uma coleção não conseguia comprar a sua própria peça. A transação era rejeitada com um erro genérico de saldo insuficiente, mesmo com fundos de sobra. Uma carteira de terceiros comprava sem problema nenhum. Só o dono ficava bloqueado.

A causa era simples de encontrar depois de encontrada: a lógica de pagamento assumia sempre que comprador e vendedor eram entidades diferentes, e nunca tinha sido testada para o caso, óbvio em retrospetiva, de um criador a comprar de si próprio. É o tipo de caso que ninguém pensa em testar porque parece marginal, mas que na prática é quase sempre o primeiro caminho que alguém percorre a sério: o próprio criador, a confirmar que o que construiu funciona.

Um segundo bug, na mesma plataforma, era mais silencioso. O sistema reservava um número de série assim que um pagamento começava, antes de confirmado. Se o pagamento falhasse a meio, por qualquer razão, esse número ficava queimado na mesma: nunca voltava a ficar disponível. Depois de falhas suficientes, uma coleção com peças por vender aparecia como esgotada. Não havia erro visível, nem alerta. Havia só uma contagem que descia e nunca voltava a subir.

A correção foi um mecanismo de libertação: percorrer os números reservados do mais recente para o mais antigo e devolver à coleção os que nunca tiveram pagamento confirmado. Nenhum dos dois bugs foi apanhado por eu ler o código com atenção. Foram apanhados por alguém a tentar de facto usar o sistema como um utilizador real usaria, e não como o caminho feliz que eu tinha em mente quando o escrevi.

07As Perguntas Que Furam Código Bonito

Código gerado por IA tende a estar bem formatado, bem comentado e a seguir convenções, o que o faz parecer mais confiável do que é. Formatação não é correção. As perguntas que valem a pena fazer, ao código ou ao próprio agente, não são sobre estilo:

  • "O que acontece se isto for chamado duas vezes seguidas com o mesmo pedido?" (a mesma pergunta do capítulo 2, agora como hábito, não como teste isolado)
  • "O que acontece se a operação falhar a meio, depois do primeiro passo mas antes do último?"
  • "Quem mais, além de quem eu tinha em mente, pode chegar a este código, e o que acontece se for essa pessoa?"
  • "Se eu tentasse ativamente partir isto, por onde é que começava?"

Pede a pergunta, não só a resposta

Em vez de perguntares se o código está correto, pede ao próprio agente para gerar três formas de o quebrar. Costuma ser mais honesto a atacar do que a validar, porque a instrução muda o que está a otimizar: já não é parecer útil, é encontrar o buraco.

Nenhuma destas perguntas exige saber mais do que quem as faz já sabe. Exige só perguntá-las antes de aceitar a resposta seguinte.

08O Que Fazer Quando Não Tens Tempo Para Isto Tudo

Nem tudo o que se constrói merece uma auditoria com vários agentes e um teste de caracterização para cada correção. Um protótipo de fim de semana não é uma ponte que move valor entre duas blockchains, e tratá-los da mesma forma é desperdiçar disciplina onde ela não compensa.

A versão mínima, para quando o tempo é curto, é uma pergunta só, feita a sério antes de aceitares qualquer código que decida algo em nome de outra pessoa (dinheiro, acesso, dados): "se isto correr mal, quem é que sofre, e eu saberia?" Se a resposta for alguém que não és tu, e não saberias, isso é o sinal de que compensa parar mais dois minutos e fazer as perguntas do capítulo anterior.

O registo no fim deste guia é para isso: não uma checklist de vinte pontos, uma entrada por coisa que decidiste confiar, com o risco que identificaste e como o testaste. Se o campo do teste ficar em branco outra vez e outra vez para o mesmo tipo de risco, é aí que sabes onde a tua disciplina ainda não chegou.

Registo de verificação

A versão do capítulo 8, sem precisar de nada à parte. Uma entrada por coisa que construíste: o risco que identificaste, como o testaste, e o que encontraste. Se o campo do teste ficar vazio, é o próprio registo a dizer-te que ainda não verificaste nada.

Fica guardado só neste browser.

Conclusão

A ideia central deste guia cabe numa frase: a confiança de uma resposta e a correção dela são coisas diferentes, e a IA só te dá a primeira de graça. A segunda continua a exigir o mesmo que sempre exigiu: mais do que um avaliador, e um teste que prove em vez de uma explicação que convença.

Nada disto garante que nunca vais enviar um bug para produção. Garante que, quando enviares, vai ser porque a verificação não chegou lá, não porque nunca a fizeste.

Se ficares só com uma decisão deste guia, fica com esta: da próxima vez que aceitares código sem hesitar porque a explicação soava bem, para e pergunta-te o que aconteceria se estivesses errado sobre isso. Depois vai escrever o teste que responde.

Se isto te ajudou a apanhar alguma coisa antes de chegar a produção, conta-me o que foi. E se discordas de alguma coisa aqui, ainda melhor, porque é assim que a próxima versão fica melhor.

Isto ajudou-te?

Se isto te foi útil, o mais provável é ser útil a alguém que conheces. Partilha.

LinkedInWhatsApp

Fontes, e o que é só observação minha

Revisão independente de código

  • Gerald M. Weinberg, "The Psychology of Computer Programming", 1971: a origem da ideia de "programação sem ego", a defender que código revisto por outra pessoa encontra erros que o próprio autor, convencido da sua correção, não encontra.

Testes que provam comportamento

  • Michael Feathers, "Working Effectively with Legacy Code", 2004: a origem do "teste de caracterização", um teste que capta o comportamento real de um sistema antes de decidir se esse comportamento devia mudar.

O resto

  • Fui Quality Coach numa operação de customer experience: avaliação de contactos por grelha, calibrações com o cliente, análise de causa-raiz. É de lá que vem a regra de nunca confiar num avaliador só, aplicada aqui a código em vez de pessoas.