A IA não está refatorando seu código — está clonando

Foto: Markus Spiske via Pexels
211 milhões de linhas alteradas, analisadas pela GitClear — uma empresa que mede diff de repositório profissionalmente. Cinco anos, de janeiro de 2020 a dezembro de 2024. Repositórios de Google, Microsoft, Meta e empresas de capital fechado.
O placar que sai daí:
- Linhas classificadas como copy/paste subiram de 8,3% para 12,3% das linhas alteradas.
- Linhas associadas a refatoração despencaram de 25% em 2021 para menos de 10% em 2024.
- E o achado que vale o artigo inteiro: em 2024, copy/paste superou "moved" — código que só mudou de lugar, a assinatura de quem refatora — pela primeira vez na história do dado.
Os números são do relatório de 2025 da GitClear, publicado aberto no site deles. Vá lá e confira — parte deste artigo é sobre gente que não conferiu.
A leitura fácil é: "a IA escreve código ruim". Não é essa a minha tese, e o dado não sustenta essa frase.
A minha tese é outra: o agente não duplica por preguiça nem por burrice. Ele duplica porque não sabe o que já existe no seu projeto. Escrever de novo é o comportamento racional de quem não tem como saber que aquilo já está escrito. Duplicação não é defeito do modelo — é consequência de contexto sem escopo, medida em linhas de código.
"Moved" contra "copy/paste": a métrica que ninguém explica
Essa inversão só significa alguma coisa se você entender as duas operações, e é justamente a parte que os resumos pulam.
A GitClear classifica cada linha alterada por tipo de operação — entre elas added, deleted, updated, moved e copy/pasted. Duas interessam aqui:
Moved é código que mudou de lugar. Você pegou um bloco que estava num arquivo e levou para outro; extraiu uma função; puxou lógica repetida para um ponto único. O total de código no sistema não cresce — ele se reorganiza. Por isso a própria GitClear trata moved como o proxy de refatoração: mover é o resíduo mecânico de melhorar a estrutura sem mudar o comportamento.
Copy/paste é código que apareceu de novo. O bloco que já existia agora existe em dois lugares. O sistema não ficou mais organizado; ficou maior.
Agora junte. Durante toda a série histórica, um codebase saudável movia mais do que clonava: o volume de reorganização superava o de repetição. Em 2024 isso inverteu. Na formulação da própria GitClear, no relatório seguinte, "The Maintainability Gap", 2024 foi "the first year on record where within-commit copy/paste exceeded 'moved' (refactored) code".
Não é uma piora gradual de qualidade. É uma troca de regime.
O código parou de ser reorganizado e passou a ser reproduzido.
O que esse dado NÃO diz — e eu preciso falar isso antes de continuar
Aqui é onde quase todo mundo que citou esse estudo escorregou, então vou ser explícito.
A GitClear mede código. Ela não mede quem escreveu o código. O estudo não tem grupo de controle, não separa commit assistido de commit não assistido, não pergunta a ninguém se usou Copilot. Ele observa uma mudança na forma do código ao longo de cinco anos — e esses cinco anos coincidem com a adoção em massa de assistentes.
Coincidência temporal não é causalidade. A inferência é razoável: o período bate, o efeito bate com o que a ferramenta faz, e não há candidato melhor à mesa. Mas continua sendo inferência, não achado. Um artigo que escreve "a IA causou 12,3% de clonagem" está inventando um resultado que o estudo não produziu.
Outras explicações não foram descartadas: composição da amostra mudando ao longo do tempo, mais empresas grandes entrando na base, mudança no perfil de projeto, pressão de prazo pós-2022. A própria GitClear não publica seção de limitações nem a definição operacional rigorosa da taxonomia — o que, honestamente, é um problema do relatório, não uma implicância minha.
Eu acho a inferência boa. Só não vou vendê-la como prova.
Os números que você viu por aí (e por que quase todos estão errados de lugar)
Se você já leu sobre esse estudo, provavelmente encontrou "+81%", "8x" ou "dez vezes". Eu fui atrás de cada um, esperando encontrar invenção de blog. Encontrei algo mais interessante — e pior.
Eles são reais. Só não são do estudo a que costumam ser atribuídos, nem medem a mesma coisa.
- "+81%" não é do relatório de 2025. É do relatório seguinte, "The Maintainability Gap", com outro recorte (623 milhões de mudanças, 2023–2026): subiu de 40,3 pra 73,0 no índice de duplicação de blocos deles — a unidade exata a GitClear não define na página, o que já diz alguma coisa num relatório que ensina régua — "an 81% increase over 2023". Outro estudo, outro período, outra unidade.
- "8x" e "10x" medem blocos duplicados — regiões de cinco ou mais linhas consecutivas repetidas — e não porcentagem de linhas. São métricas diferentes, com denominadores diferentes. Citar "8x de aumento em clonagem" ao lado de "8,3% → 12,3%" mistura duas réguas.
E tem um detalhe que eu não esperava: a própria GitClear titula a página de 2025 como "4x Growth in Code Clones", enquanto o corpo do texto reporta 8,3% → 12,3% — um aumento relativo de cerca de 1,5x. O "4x" da manchete não é a mesma medida do parágrafo. A confusão começa na fonte.
Uma nota de honestidade sobre o meu próprio trabalho: tentei abrir o PDF primário para conferir o "8x" na origem e não consegui — o arquivo é imagem embutida, não texto extraível. Então o "8x" eu vi em sumário secundário e na página oficial, não verifiquei palavra por palavra no primário. Por isso ele não aparece na abertura deste artigo. Os únicos números que eu ancoro aqui são os que li na fonte: 8,3% → 12,3% e 25% → menos de 10%.
É o padrão da série se repetindo. O nicho raramente inventa número do zero. Ele desloca número verdadeiro para o contexto errado — e ninguém confere, porque conferir dá trabalho e o número já soa bem.
O contra-argumento honesto: duplicação nem sempre é pecado
Se eu terminasse aqui, seria mais um texto de DRY como religião. Não é.
Sandi Metz — autora de Practical Object-Oriented Design in Ruby, uma das vozes mais respeitadas em design de código — escreveu em 2016 a frase que todo mundo que prega DRY devia ter na parede: "duplication is far cheaper than the wrong abstraction". A abstração errada cobra juros para sempre — cada caso novo vira mais um parâmetro, mais um if, até a função virar um monstro que ninguém entende. Duplicação, ao menos, é honesta: está tudo ali, aberto.
Em protótipo, em spike, em código que vai morrer em duas semanas, velocidade vence DRY — e clonar é a escolha certa. O gráfico da GitClear não distingue essas duas populações. Parte daquele 12,3% pode ser duplicação perfeitamente racional em código descartável.
O problema não é a duplicação existir. É ela existir sem decisão. Metz duplica de propósito, sabendo que duplicou, para não se prender cedo demais. O agente duplica sem saber que duplicou. A primeira é estratégia; a segunda é ruído — e ruído não se paga na hora.
Onde a conta chega: na revisão
O custo da duplicação não aparece no commit. O commit fica ótimo: funciona, os testes passam, o diff é grande e verde.
A conta chega quando você revisa. E revisar código que a máquina escreveu é uma tarefa mentalmente diferente de revisar o seu — você não está relendo um raciocínio que já teve, está fazendo engenharia reversa de um raciocínio que nunca teve. Some a isso quinhentas linhas onde cabiam cem, e o esforço não cresce um pouco: ele muda de natureza. É dor documentada: uma thread do Hacker News sobre usar IA pra escrever código melhor mais devagar está cheia de gente relatando exatamente essa compressão: o ciclo de escrever, revisar e reiterar que antes tinha respiro agora se espreme numa tarde.
E o pior é o segundo tempo. Cada bloco duplicado cria uma obrigação futura: quando você mudar uma cópia, precisa achar as irmãs — em arquivos que talvez você não conheça — e decidir, uma a uma, se a mudança propaga. Esse imposto ninguém cobra no dia do merge.
Por que ele duplica: não é o modelo, é o que ele não sabe
Volte à tese. O agente não tem o seu projeto na cabeça. Ele tem o que está no contexto agora.
Se a função que resolve aquilo mora num arquivo que ele nunca leu, ela não existe para ele. E aí ele faz a única coisa que pode fazer: escreve uma que funcione. O resultado passa nos testes, cumpre o pedido, e adiciona a segunda cópia de algo que já existia.
Repare que "peça para ele não duplicar" não resolve nada. Não é uma questão de vontade ou de obediência — é ausência de informação. Você não pode instruir alguém a reusar o que ele não sabe que existe.
A resposta que eu dei — e onde eu mesmo tinha duplicado
A minha resposta não foi um prompt melhor. Foi arquitetura: ponto único declarado.
Antes de descrever: eu quebrei o repo em 12 projetos isolados, e o código que serve mais de um deles não é copiado pra dentro de nenhum. Um arquivo-manifesto — uma lista, em texto — diz onde cada capacidade compartilhada mora e quem consome ela.
Está registrado como ADR no meu repo — a decisão, o motivo e o que eu abri mão. O código que serve dois ou mais sistemas não é copiado para dentro de cada projeto — e, importante, também não é movido. Ele fica onde está e passa a ser declarado. A regra que abre o manifesto é essa: "este codigo NAO e movido nem duplicado; vive onde esta; os micro-projetos o consomem via manifesto". Hoje são 12 projetos, cada um declarando o que consome.
Isso muda o problema de lugar. Não dependo do agente lembrar que a função existe: um script roda antes de cada pedido, descobre em qual projeto o pedido cai, e cola no contexto a lista do que aquele projeto consome. Ele passa a saber o que existe — que era o buraco.
Agora a parte que me interessa mais contar. O meu próprio sistema estava duplicado.
A trava de acentuação em PT tinha um ponto único em social/pt_acentuacao.py — e uma cópia paralela vivendo dentro de social/reel.py. A mesma lógica, dois lugares, exatamente o padrão que este artigo descreve. Hoje o reel.py importa o ponto único, e o comentário que eu deixei no topo do import é quase uma confissão: "garante o diretório do próprio arquivo no sys.path pra importar o PONTO ÚNICO da trava de acentuação (não duplicar)".
E tem mais. Enquanto escrevia este texto, fui conferir o manifesto e achei duas coisas erradas nele:
- Numa linha, o manifesto diz que o
reel.pyimporta o ponto único "sem copia duplicada". Três dezenas de linhas abaixo, o mesmo arquivo ainda descreve "(e copia emreel.py)". O documento se contradiz: uma das duas ficou para trás quando a duplicação foi resolvida. - Um módulo meu de anúncios continua listado como capacidade compartilhada do núcleo, com "Consumido por: (nenhum projeto)". Uma capacidade "compartilhada" que ninguém compartilha é um ponto único de nada.
Ou seja: o cara que construiu o anti-duplicação duplicou, e o manifesto que declara os pontos únicos tem uma linha que envelheceu sem ninguém notar. Se isso soa como derrota, é o contrário — é exatamente o argumento. Declaração em prosa apodrece. Por isso existe roteador/validate_routes.py, que confere por código se o que o manifesto afirma bate com o disco e sai com código de erro quando não bate.
E aqui vai o limite honesto dele: o validate_routes.py não detecta clone. Ele valida a integridade do manifesto — se todo caminho declarado existe, se o espelho de agentes confere byte a byte, se as arestas de consumo fecham. Ele não sabe ler duas funções e dizer que são a mesma. As duas linhas contraditórias do manifesto passaram justamente porque prosa não é validada por ninguém. Quem achou foi eu, no olho, escrevendo isto.
O tempo de estrada, declarado
Esta arquitetura nasceu no commit 4296eb4, em 14 de julho de 2026 — a mesma data em que escrevo. Ela tem dias de vida.
Então não tem benchmark, não tem antes-e-depois, não tem número de resultado. Eu não vou te dizer que reduzi clonagem em X% porque eu não medi, e quem afirma isso com dias de uso está fazendo o hype que este artigo critica. O que eu tenho é uma decisão arquitetural e o raciocínio atrás dela. O resultado vem depois, medido — ou não vem, e eu conto também.
Perguntas frequentes
Então a IA está piorando meu código? O dado não diz isso, e eu não vou dizer. O dado diz que a forma do código mudou — menos reorganização, mais repetição — num período que coincide com a adoção de assistentes. A causa é inferência plausível, não resultado medido. Quem transforma essa correlação em causa está fazendo exatamente o que este artigo critica.
Duplicação não é sempre um erro? Não. "Duplication is far cheaper than the wrong abstraction" (Sandi Metz) continua verdade: abstrair cedo demais cobra juros piores. Em protótipo ou código descartável, clonar costuma ser certo. A diferença é decisão: duplicar de propósito é estratégia, duplicar sem saber é ruído.
Não basta escrever "não duplique código" no CLAUDE.md? Não, porque o problema não é obediência — é informação. O agente não deixa de reusar por má vontade; ele não sabe que a função existe, porque ela não está no contexto dele. Instrução não substitui conhecimento ausente.
Isso só serve para quem tem micro-projetos e roteador? Não. O princípio é independente da minha estrutura: (1) tenha um ponto único de verdade para cada capacidade; (2) declare onde ele está, em algum lugar que o agente leia junto com o pedido; (3) tenha algo automático conferindo a declaração, porque documento em prosa envelhece — o meu envelheceu. Um README honesto no topo do módulo já é mais do que a maioria dos repositórios tem.
Voltando ao placar
8,3% para 12,3%. Refatoração de 25% para menos de 10%. Copy/paste passando "moved" pela primeira vez na história.
Esse placar não é um retrato de modelos ficando piores. É o retrato de uma ferramenta muito capaz operando sem saber onde está. Todo agente, o dia inteiro, responde a uma pergunta implícita: "o que já existe aqui?". Quando ninguém responde, ele responde sozinho — escrevendo de novo.
A régua que eu passei a usar é essa. Não "o modelo é bom?", mas "ele sabe o que já existe?". Enquanto a resposta for não, ele vai clonar. E vai estar certo em clonar.