DEV Community

Alberto Luiz Souza
Alberto Luiz Souza

Posted on

Código humano ou código de IA: quem tem mais defeito?

Disclaimer

Este texto foi inicialmente concebido pela IA Generativa em função da transcrição de um vídeo do canal Dev Eficiente, apresentado por Alberto Souza. Se preferir acompanhar por vídeo, é só dar o play.

Introdução

Uma pergunta que aparece com frequência quando falamos de agentes de código é qual o nível de desconfiança que devemos ter de um código gerado por um modelo. Não um modelo qualquer, mas os modelos de ponta que usamos no dia a dia. A resposta costuma vir carregada de intuição, e intuição raramente é um bom instrumento de decisão técnica.

Neste post eu reviso um artigo científico que tenta responder isso com dados: "Human written versus AI generated code: a large scale study of defects, vulnerabilities and complexities". O estudo compara código escrito inteiramente por pessoas com código escrito inteiramente por LLMs, em três dimensões de qualidade: defeitos, vulnerabilidades de segurança e complexidade estrutural.

Vale um recorte temporal honesto antes de qualquer conclusão. O artigo é de 2025, e este vídeo foi gravado em junho de 2026. Em um cenário de evolução acelerada dos modelos e dos agentes construídos sobre eles, um ano é bastante tempo. Então trate os números como uma fotografia de um momento que já passou, e preste atenção principalmente na direção que eles apontam.

Como o estudo foi feito

O ponto de partida foi um dataset com centenas de milhares de funções, algo em torno de 200 e poucas mil em Python e um número parecido em Java, mineradas de dezessete a dezoito mil repositórios do GitHub. Todas escritas por seres humanos.

O dataset pronto não trazia a documentação das funções. Então os autores executaram um processo para casar cada função de volta ao seu repositório original e recuperar a documentação. A partir dessa documentação, rodaram prompts contra três famílias de modelos para gerar implementações equivalentes: um modelo da OpenAI, o GPT-3.5, um modelo da família Qwen e um modelo da família DeepSeek. Foram quatro implementações de cada função, para poder comparar.

Um detalhe importante sobre a metodologia, porque ele muda a leitura de tudo o que vem depois: não havia agente, não havia contexto adicional, não havia harness. Era um prompt direto contra a documentação, pedindo a implementação naquela linguagem. Um cenário muito mais pobre do que qualquer fluxo sério de geração de código hoje.

O estudo se organiza em torno de três perguntas:

  • Os tipos e a frequência de defeitos diferem entre código humano e código gerado, e isso muda conforme a linguagem?
  • Existe diferença nas vulnerabilidades de segurança entre código humano e código gerado?
  • As métricas de complexidade estrutural variam entre um e outro?

O que conta como defeito aqui

Antes dos resultados, é preciso alinhar o vocabulário, porque a palavra defeito carrega mais peso do que o estudo lhe atribui. A classificação usou o framework Orthogonal Defect Classification, bem aceito na literatura, com regras aplicadas por ferramentas de análise estática tanto para Python quanto para Java.

Defeito, nesse contexto, não é sinônimo de código que não funciona. É uma categoria ampla que inclui desde erros que impedem a execução até práticas desencorajadas. Alguns tipos, para dar concretude:

  • Assignment: erros de inicialização ou de binding de variável, por exemplo usar uma variável que não foi inicializada. Esse tende a quebrar de fato.
  • Algoritmo: problemas de lógica. Aqui entra também algo como blocos aninhados demais, que não afeta a corretude, mas é considerado um defeito de estrutura.
  • Interface: problemas de comunicação entre módulos, como um parâmetro sem valor definido.
  • Checking: validação de falhas e tratamento de erro faltando, como a ausência de checagem de timeout ou um bloco de catch vazio.
  • Timing e serialização: questões de concorrência, ordenação e sincronização.
  • Function, class e object: problemas estruturais de design.

Guarde isso: quando o estudo diz que um código tem mais defeitos, boa parte disso é prática ruim capturada por regra estática, não é, necessariamente, código que não roda.

Resultado 1: defeitos

O resultado dos defeitos surpreende quem chega com a intuição pronta. O código que saiu com menos defeitos foi o gerado pelo GPT-3.5, um modelo antigo se comparado ao que temos hoje e, lembrando, sem agente e sem contexto. Ainda assim, com menos defeitos.

Em Python, o código humano foi menos ruim do que parte dos modelos, mas ainda perdeu. Em Java a disputa ficou mais equilibrada, com o código humano em uma posição intermediária. No total acumulado de defeitos, no entanto, o código humano saiu pior nas duas linguagens.

O que eu achei mais curioso não foi o número, foi a conclusão que os autores tiraram dele. Eles escrevem que os achados reforçam a necessidade de avaliar o código gerado por IA, não apenas quanto à corretude, mas também quanto ao design. Pela leitura dos dados, porém, o que precisou de mais revisão foi o código humano, não o da máquina. A necessidade de revisão é real e vale para todos, porque todos apresentaram defeitos. Mas o dado não aponta especificamente para o código gerado.

Resultado 2: vulnerabilidades

Aqui a história se inverte, e essa é a parte que merece mais atenção. Em ambas as linguagens, o código humano foi o que apresentou menos vulnerabilidades de segurança. Todos os modelos, de forma consistente, geraram código com mais problemas de segurança do que o escrito por pessoas.

E não é só uma questão de quantidade. Os autores registram que o código gerado por IA difere do humano também na natureza e na distribuição das vulnerabilidades, ficando mais suscetível a problemas de alta severidade.

Esse é o ponto onde o balanço fica interessante. Se cada dimensão do estudo tivesse o mesmo peso, o código humano perderia no geral. Mas as dimensões não têm o mesmo peso. Uma falha de segurança de alta severidade tende a ser mais crítica do que um bloco aninhado a mais, que é um defeito de prática e não de corretude. Peso não é algo que o estudo decide por você. É julgamento de engenharia, e depende do que está em jogo no seu sistema.

Resultado 3: complexidade estrutural

A terceira dimensão avaliou complexidade a partir de um conjunto de métricas: número de linhas, complexidade ciclomática, número de tokens, tamanho dos nomes de funções como proxy para semântica e tokens únicos como proxy para o vocabulário da linguagem utilizado.

O resultado foi consistente nas duas linguagens: o código humano é estruturalmente mais complexo, tanto em tamanho quanto em estrutura lógica. O código gerado, sobretudo pelos modelos DeepSeek e Qwen, favorece brevidade e complexidade reduzida, com menos linhas, menor complexidade ciclomática e menos tokens.

Vale uma ressalva sobre a metodologia, porque ela ensina algo mais valioso do que o resultado em si. Escolher tamanho de nome como proxy para semântica é uma decisão defensável, mas o mesmo número maior também poderia indicar prolixidade, alguém que escreve nomes gigantes sem ganho real de clareza. Ou seja, a métrica não é neutra.

O que eu tiro disso não é qual métrica é a certa. É que medir complexidade importa mais do que acertar de primeira o conjunto de métricas. Quando você tem um conjunto de métricas que, combinadas, produzem uma avaliação, você ganha a capacidade de iterar sobre esse processo avaliativo e descobrir se aquelas métricas de fato trazem a perspectiva que você quer. Sem medir, você fica preso na intuição.

Quem é o assistente de quem

Feita a revisão, a pergunta que fica é o que fazer com isso na prática. O artigo, como boa parte da literatura, termina em revisão, revisão, revisão. Eu não discordo que revisão importa. Mas, pela minha experiência, ela tende a ser cada vez menos necessária quando o input é bem feito, o contexto é adequado e existe um mecanismo mínimo de revisão no fluxo. Com isso, a saída costuma vir correta. Isso depende do seu contexto, da sua stack e do seu domínio, então defina por conta própria o que correto e o que suficiente significam no seu caso.

Antes de qualquer discussão sobre revisão, existe uma questão de responsabilidade que não muda. Eu sou o responsável por tudo o que gero através dos agentes. Se um bug entra na plataforma, a pessoa cobrada sou eu. Se um conteúdo sai com informação incorreta, quem responde sou eu. Não dá para responsabilizar a máquina. O responsável continua sendo a pessoa, sem qualquer dúvida.

Existe uma ideia comum entre quem lidera que ajuda a enquadrar isso: uma habilidade importante é contratar pessoas melhores do que você para determinados tipos de trabalho. É assim que eu enxergo os agentes hoje. Eu sou o chefe, e o agente é alguém que eu contratei, com capacidade de execução geralmente melhor do que a minha para a maioria das tarefas.

A questão então é onde eu entro. Eu entro no pedaço de conhecimento em que o modelo por baixo do agente não foi tão bem treinado, ou foi treinado em uma linha que não é a que eu quero seguir. Quando o assunto é design de código, as práticas mais estabelecidas nos modelos tendem para múltiplas camadas e para tratar acoplamento com frameworks como algo sempre ruim. Não é a linha que eu defendo há alguns anos, então ali eu preciso fazer o ajuste fino.

Em contrapartida, quando eu preciso escrever queries eu não faço ajuste nenhum, porque o modelo tem mais repertório do que eu nisso. Em testes, os modelos são capazes, mas tendem a produzir testes superficiais quando não são direcionados, então ali eu direciono. Em segurança por design, eu diria que o modelo já é mais bem treinado do que eu.

Levando a ideia ao limite, eu me vejo menos como quem tem um assistente e mais como o assistente do assistente. Meu papel, nesse momento, é atrapalhar o mínimo possível o agente. Isso passa por engenharia de contexto: entender o que de fato é necessário, dar a autonomia adequada e ser sucinto. Passa também pelo harness, e aqui ferramentas como Claude Code e Codex ajudam bastante, porque já trazem guardrails sobre até onde o agente pode ir, como avaliar se a geração atendeu ao requisito e até onde vai o loop de autonomia.

Conclusão

Se o estudo já apontava, mesmo com modelos antigos e sem agente, que o código gerado tende a ter menos defeitos e menor complexidade estrutural, é razoável imaginar que a distância aumente com os modelos e agentes atuais. Na dimensão de segurança, onde o código humano ainda levava vantagem, é plausível que o cenário se aproxime ou até se inverta conforme os modelos amadurecem nesse eixo. Isso é leitura de tendência, não afirmação fechada.

O que não muda é a divisão de trabalho. A capacidade de execução migra cada vez mais para o agente. O que fica em primeiro plano do lado humano é o julgamento: definir peso entre dimensões que competem, cravar a linha de design que você acredita, direcionar onde o modelo tende ao superficial e responder pelo resultado. Não é sobre digitar código. É sobre decidir e responder por estar certo.

Dev + Eficiente

Desenvolva software de alta qualidade e domine Engenharia de IA com o Dev + Eficiente. Cursos práticos, acesso vitalício, comunidade ativa e acesso a vagas remotas exclusivas em diversas empresas de tecnologia. Sua jornada para se tornar um dev mais eficiente pode começar agora.

Top comments (0)