---
title: "Duplicação em Vez de Extração"
type: "ai-smell"
slug: "duplication-instead-of-extraction"
url: "http://localhost:3000/pt-br/ai-smells/duplication-instead-of-extraction.md"
category: "Estrutura"
description: "Assistentes de IA tendem a colar uma cópia nova e levemente ajustada de uma lógica existente em vez de reutilizar ou extrair uma função compartilhada, inflando o código duplicado enquanto a refatoração desaparece silenciosamente."
---
# Duplicação em Vez de Extração

> Assistentes de IA tendem a colar uma cópia nova e levemente ajustada de uma lógica existente em vez de reutilizar ou extrair uma função compartilhada, inflando o código duplicado enquanto a refatoração desaparece silenciosamente.

## Signs and Symptoms

Um revisor reconhece este smell quando um diff de autoria da IA _adiciona_ um bloco que já existe em algum lugar do repositório, levemente renomeado, em vez de chamar a função que já está lá. A forma reveladora é dois ou mais corpos quase idênticos que diferem apenas em um substantivo (`user`/`order`), um endpoint ou uma constante — o tipo de cópia que um humano teria fatorado.

Sinais comuns:

* Novos handlers/serviços que repetem literalmente o mesmo boilerplate de validação, retry, mapeamento de erros ou fetch.
* Strings mágicas e literais de configuração redigitados em cada novo bloco em vez de referenciados de um único lugar.
* Cada turno do agente reimplementa lógica que o turno anterior já escreveu (o agente não tem memória de que um helper existe).
* `git log` mostra commits consecutivos da IA adicionando linhas, mas quase nenhuma linha "movida"/renomeada — adições sem consolidação.

```ts
// A IA adicionou isto para a nova rota — mas getUser já existe 30 linhas acima
async function getOrder(id: string) {
  const res = await fetch(`${API}/orders/${id}`, { headers: authHeaders() });
  if (!res.ok) throw new Error(`Request failed: ${res.status}`);
  const json = await res.json();
  if (!json?.data) throw new Error("Malformed response");
  return json.data;
}

async function getUser(id: string) {                 // <-- corpo 95% idêntico
  const res = await fetch(`${API}/users/${id}`, { headers: authHeaders() });
  if (!res.ok) throw new Error(`Request failed: ${res.status}`);
  const json = await res.json();
  if (!json?.data) throw new Error("Malformed response");
  return json.data;
}

```

Este é o clássico smell de [Código Duplicado](https://refactoring.guru/smells/duplicate-code), mas produzido sistematicamente em vez de por acidente.

## Reasons for the Problem

**Por que os modelos a produzem**

* **Localidade do próximo token.** Um LLM completa o trecho _atual_ a partir do texto mais similar em sua janela de contexto. Reproduzir um bloco próximo e conhecidamente bom é a continuação de maior probabilidade; "pare, vá definir um helper e então chame-o" é um desvio mais longo e de menor probabilidade que abrange vários arquivos.
* **Sem modelo do repositório inteiro.** O assistente raramente sabe que um helper adequado já existe fora de seu contexto. Sem recuperação, ele não pode reutilizar o que não vê, então regenera. Os praticantes descrevem agentes que "recriam lógica similar do zero para cada nova tarefa", e Eno Reyes (Factory) enquadra a própria qualidade do código como o principal preditor de se a IA ajuda ou prejudica uma base de código.
* **Amnésia por turno + escopo do prompt.** Cada requisição é tratada como uma unidade autocontida ("faça _isto_ funcionar"), então o agente faz overfitting de uma solução estreita e de uso único em vez de generalizar. A OX Security chama isso de **Sobre-especificação** (vista em 80–90% do código de IA) e **Evitação de Refatorações** (80–90%): o modelo emite código funcional para o prompt imediato, mas nunca consolida.
* **Bajulação / menor atrito.** Os modelos otimizam por uma saída que satisfaz visivelmente o pedido sem tocar em arquivos não relacionados. Duplicar é "seguro" e local; refatorar arrisca quebrar algo que o modelo não consegue ver, então ele evita.
* **O ferramental torna isso barato.** Como a GitClear observa, o tab-para-aceitar torna inserir um bloco novo quase gratuito, removendo o atrito que costumava empurrar os desenvolvedores para a reutilização.

**Por que isso prejudica**

* **Erosão de qualidade mensurada.** A análise de 2025 da GitClear (211M de linhas alteradas, 2020–2024) descobriu que as linhas copiadas/coladas subiram de 8,3% para 12,3% enquanto as linhas "movidas" (refatoradas) caíram de \~24% para 9,5% — 2024 foi o primeiro ano em que as linhas copiadas/coladas _excederam_ as linhas movidas, e blocos de 5+ linhas duplicadas saltaram \~8×.
* **Dívida de correção — "Bugs Déjà-Vu".** A OX Security encontrou isso em 70–80% do código de IA: um bug corrigido em um clone sobrevive silenciosamente em todos os outros, então defeitos idênticos se repetem e cada um precisa de uma correção redundante. A duplicação transforma um bug em N bugs.
* **Manutenibilidade & carga de revisão.** Cada mudança de comportamento precisa ser encontrada e editada em muitos lugares; os diffs incham com blocos quase idênticos que os revisores precisam comparar linha a linha para confirmar que são _realmente_ idênticos (e não sutil e perigosamente diferentes).
* **Superfície de segurança.** Um padrão vulnerável (verificação de auth ausente, entrada não escapada) se propaga para cada cópia, e uma correção de endurecimento posterior pode deixar clones de fora — a duplicação multiplica a superfície de patch.

## Treatment

**Táticas de revisão & prompting**

* Diga ao modelo onde olhar primeiro: _"Antes de escrever código novo, procure no repositório por um helper existente que faça isto e reutilize-o; não duplique."_ Cole o módulo relevante para que ele esteja no contexto.
* Exija consolidação explicitamente: _"Se dois blocos diferem apenas por parâmetros, extraia uma única função parametrizada (Extrair Função) e chame-a de ambos."_
* Faça-o rodar as ferramentas: _"Rode o linter / jscpd / a verificação de duplicação e resolva qualquer clone que ele relatar antes de retornar o diff."_ Os agentes se autocorrigem bem quando recebem um sinal determinístico.
* Na revisão, trate um bloco com aparência de colado como um convite para fazer grep: procure por uma linha distintiva; se ela já existir, devolva para extração.

**A refatoração — Extrair Função + parametrizar**

```ts
// depois: uma única fonte de verdade, chamada de ambos
async function getResource<T>(path: string): Promise<T> {
  const res = await fetch(`${API}/${path}`, { headers: authHeaders() });
  if (!res.ok) throw new Error(`Request failed: ${res.status}`);
  const json = await res.json();
  if (!json?.data) throw new Error("Malformed response");
  return json.data as T;
}

const getOrder = (id: string) => getResource<Order>(`orders/${id}`);
const getUser  = (id: string) => getResource<User>(`users/${id}`);

```

Agora uma correção no tratamento de erros ou no parsing da resposta aterrissa uma única vez. Onde as duplicatas diferem por uma etapa em vez de um valor, prefira [Formar Template Method](https://refactoring.guru/design-patterns/template-method) ou passe a etapa variável como um callback. Os movimentos canônicos aqui são **Extrair Função**, **Extrair Variável/Constante** (para literais redigitados) e **Subir Método** quando os clones vivem em classes irmãs — todas curas padrão para [Código Duplicado](https://refactoring.guru/smells/duplicate-code).

**Salvaguarda, não apenas limpeza:** conecte um detector de clones ao CI com um limiar baixo para que a _próxima_ duplicata gerada por IA falhe o build em vez de ser mesclada. Combine-o com uma regra da casa de uma linha em `CLAUDE.md`/`AGENTS.md` ("reutilize helpers existentes; nunca cole uma quase-duplicata") para que a restrição acompanhe o contexto do modelo a cada turno.

## Detected by

- **jscpd** `copy/paste duplication (configurable min-tokens / min-lines threshold; supports --threshold gate in CI)` (https://github.com/kucherenko/jscpd)
- **PMD** `CPD (Copy/Paste Detector) — token-based clone detection across 30+ languages` (https://pmd.github.io/pmd/pmd_userdocs_cpd.html)
- **SonarQube / SonarSource** `S4144 — Methods should not have identical implementations` (https://rules.sonarsource.com/javascript/RSPEC-4144/)
- **SonarQube / SonarSource** `S1192 — String literals should not be duplicated` (https://rules.sonarsource.com/javascript/RSPEC-1192/)
- **SonarQube** `Duplicated blocks / duplicated_lines_density metric (built-in clone engine, fails quality gate over threshold)` (https://docs.sonarsource.com/sonarqube-server/latest/user-guide/code-metrics/metrics-definition/)
- **eslint-plugin-sonarjs** `sonarjs/no-identical-functions` (https://github.com/SonarSource/eslint-plugin-sonarjs/blob/master/docs/rules/no-identical-functions.md)
- **eslint-plugin-sonarjs** `sonarjs/no-duplicate-string` (https://github.com/SonarSource/eslint-plugin-sonarjs/blob/master/docs/rules/no-duplicate-string.md)
