Saltar para o conteúdo
Telmo 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 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. Entrega uma função, uma explicação de porque funciona, e seis alíneas a justificar a escolha, com o 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. É 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.

Nos últimos anos passei de escrever scripts para automatizar tarefas repetitivas a construir software em produção: protocolos de blockchain, infraestrutura de pagamentos, sistemas com IA. 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.

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.
  • Uma janela demasiado curta contra reorganizações da cadeia, que podia deixar valor a ser movido sobre um bloco que ainda podia desaparecer.
  • 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.
  • Uma chave de verificação de reserva (placeholder) que, se esquecida em produção, aceitava provas que não deviam ser aceites.

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 é exactamente 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?"
  • "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 4, 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. Hoje aplico a mesma disciplina a submeter o que construo a auditoria adversarial com vários agentes de IA antes de produção. Os dois casos de estudo (a ponte entre blockchains, a plataforma de coleções digitais) são projetos meus reais; o código é de repositório privado, por isso descrevo o processo e o resultado, não a implementação.