O que é DRY? Não se repita e elimine duplicação de código
Entenda o princípio Don't Repeat Yourself, como remover duplicação de código de verdade, quando tolerar repetição e por que abstrair cedo demais costuma sair mais caro.

Neste artigo
DRY é uma das siglas mais repetidas no desenvolvimento de software — e, ironicamente, uma das mais mal interpretadas. O princípio nasceu em 1999 com Andrew Hunt e David Thomas e propõe algo aparentemente simples: cada pedaço de conhecimento deve ter uma representação única dentro de um sistema. Neste artigo você vai entender o que isso realmente significa, como aplicar DRY na prática, como reconhecer a diferença entre duplicação real e duplicação coincidente e por que persegui-lo de forma cega pode produzir um código pior do que aquele que você tentava melhorar.
O que significa DRY de verdade#
DRY é a sigla de Don't Repeat Yourself ("não se repita"). A formulação original de Hunt e Thomas, em The Pragmatic Programmer, é mais precisa do que a versão popularizada:
"Cada pedaço de conhecimento deve ter uma representação única, não ambígua e definitiva dentro de um sistema." (Hunt e Thomas, 1999)
Repare na palavra conhecimento. O princípio não fala sobre linhas de código idênticas, e sim sobre regras de negócio, decisões e fatos que se repetem. Duas funções podem ter o mesmo código por pura coincidência, sem compartilharem nenhum conhecimento — unificá-las seria um erro. E duas regras de negócio podem estar duplicadas mesmo quando o código que as expressa parece completamente diferente.
Essa distinção é o coração do DRY. A duplicação que importa é a duplicação de conhecimento, não a duplicação textual. Anos depois, Dave Thomas chegou a esclarecer publicamente que o ponto sempre foi sobre conhecimento e intenção, não sobre evitar que dois trechos de texto se pareçam. Muita gente perdeu essa nuance e passou a tratar qualquer repetição de caracteres como pecado — uma leitura que produz mais dano do que benefício.
Conhecimento versus representação#
Vale separar dois conceitos que costumam ser confundidos:
- Conhecimento é a regra ou o fato: "o frete é grátis acima de R$ 200", "o CPF tem 11 dígitos", "usuários inativos há 90 dias recebem um aviso".
- Representação é como esse conhecimento aparece no código: uma constante, uma função, uma linha de configuração, uma coluna de banco.
DRY pede uma única representação definitiva para cada conhecimento. Não importa se essa representação é uma função, uma constante ou um registro de configuração — o que importa é que exista um só lugar para mudar quando o conhecimento mudar.
Por que duplicação é um problema#
Quando o mesmo conhecimento aparece em vários lugares, qualquer mudança precisa ser aplicada em todos eles. O custo não é só o trabalho extra: é o risco de esquecer um dos pontos.
Imagine que a regra "frete grátis acima de R$ 200" esteja codificada no carrinho, no checkout e no e-mail de confirmação. No dia em que o valor mudar para R$ 250, você precisa lembrar dos três lugares. Esquecer um significa um sistema que se contradiz — o carrinho promete frete grátis que o checkout cobra.
Os sintomas clássicos da duplicação de conhecimento são:
- Bugs por inconsistência: a regra foi corrigida em um lugar, mas não nos outros.
- Medo de mudar: ninguém sabe quantas cópias da regra existem, então mudanças viram caça ao tesouro.
- Documentação que mente: o comentário diz uma coisa, o código faz outra, porque um foi atualizado e o outro não.
- Onboarding lento: quem chega no time precisa descobrir, na marra, quantas variações da mesma lógica existem.
DRY combate exatamente isso ao centralizar cada decisão em um único ponto de verdade. Reduzir o número de lugares onde uma regra vive reduz, na mesma proporção, o número de lugares onde ela pode ficar errada.
Tipos de duplicação#
Hunt e Thomas identificam que a duplicação vai muito além de copiar e colar blocos. Vale conhecer as variações, porque cada uma pede uma estratégia diferente de combate.
Duplicação imposta#
Acontece quando o ambiente parece exigir repetição: um schema de banco e a classe que o representa, a documentação e o código, ou múltiplas linguagens descrevendo a mesma estrutura. A saída costuma ser geração de código ou uma única fonte que produz as demais representações. Em vez de manter o schema do banco e a struct da aplicação sincronizados à mão, você gera a struct a partir do schema. A duplicação continua existindo no resultado final, mas ela não é mais editada manualmente — existe um único ponto de autoria.
Duplicação inadvertida#
O desenvolvedor não percebe que está duplicando conhecimento porque ele aparece de formas diferentes. Por exemplo, guardar idade e data_de_nascimento no mesmo objeto: idade é derivável da data, então mantê-la armazenada cria dois pontos que precisam concordar. O mesmo vale para guardar subtotal, imposto e total quando o total é sempre subtotal + imposto — o ideal é calcular o derivado sob demanda.
Duplicação por impaciência#
A mais comum e a mais humana. Sob pressão de prazo, copiar é mais rápido do que abstrair. É uma dívida técnica que parece barata hoje e cobra juros amanhã. O problema não é o ato de copiar em si — é copiar sem deixar registro e seguir em frente como se a dívida não existisse.
Duplicação entre desenvolvedores#
Duas pessoas do time resolvem o mesmo problema de formas distintas porque não conversaram. Combate-se com comunicação, revisão de código e bibliotecas internas bem documentadas. Esse tipo de duplicação é particularmente traiçoeiro porque o código nem se parece — são duas implementações de validação de e-mail, por exemplo, escritas com estilos diferentes, fazendo a mesma coisa.
DRY na prática: um exemplo#
Considere uma validação de desconto espalhada por dois pontos da aplicação:
// carrinho.js
function calcularTotalCarrinho(itens) {
let total = itens.reduce((soma, item) => soma + item.preco, 0);
if (total > 200) {
total = total * 0.9; // 10% de desconto acima de 200
}
return total;
}
// checkout.js
function calcularTotalCheckout(pedido) {
let total = pedido.itens.reduce((soma, item) => soma + item.preco, 0);
if (total > 200) {
total = total * 0.9; // 10% de desconto acima de 200
}
return total;
}A regra "10% de desconto acima de R$ 200" é o conhecimento duplicado. Extraímos para um único lugar:
// politica-desconto.js
const LIMITE_DESCONTO = 200;
const PERCENTUAL_DESCONTO = 0.1;
export function aplicarDesconto(subtotal) {
if (subtotal > LIMITE_DESCONTO) {
return subtotal * (1 - PERCENTUAL_DESCONTO);
}
return subtotal;
}Agora carrinho e checkout consomem a mesma fonte:
import { aplicarDesconto } from "./politica-desconto.js";
function somarItens(itens) {
return itens.reduce((soma, item) => soma + item.preco, 0);
}
const totalCarrinho = aplicarDesconto(somarItens(itens));
const totalCheckout = aplicarDesconto(somarItens(pedido.itens));Quando a regra mudar, você altera politica-desconto.js e pronto. O conhecimento tem uma única representação definitiva. Repare que extraímos também o somarItens, porque ele também era conhecimento repetido (a forma de somar o preço dos itens).
Um passo além: testando o ponto único#
Um benefício colateral importante de centralizar a regra é que ela passa a ser testável de forma isolada. Antes, para testar o desconto, você precisaria montar um carrinho e um checkout inteiros. Agora basta:
import { aplicarDesconto } from "./politica-desconto.js";
test("aplica 10% acima de 200", () => {
expect(aplicarDesconto(300)).toBeCloseTo(270);
});
test("não aplica desconto em 200 exatos", () => {
expect(aplicarDesconto(200)).toBe(200);
});DRY e testabilidade andam juntos: conhecimento centralizado é conhecimento que você consegue verificar em um lugar só.
O perigo do DRY mal aplicado#
Aqui mora a armadilha. Levado ao extremo, o DRY produz abstrações erradas. O caso clássico é unir dois trechos de código que parecem iguais hoje, mas representam conhecimentos diferentes que vão divergir amanhã.
Suponha que aplicarDesconto também passe a ser usada para calcular o bônus de um programa de fidelidade. Hoje a fórmula é idêntica, então é tentador reusar a função. Mas desconto de carrinho e bônus de fidelidade são regras de negócio distintas. No dia em que o time de marketing mudar só o bônus, você terá que desfazer a abstração — e desfazer uma abstração compartilhada é muito mais doloroso do que ter tolerado um pouco de duplicação.
O que costuma acontecer nesses casos é pior do que duplicação: alguém adiciona um parâmetro if (ehFidelidade) dentro da função compartilhada para acomodar a divergência. Aí surge outra exceção, mais um parâmetro, e a função vira um emaranhado de condicionais que ninguém entende. Esse é o sintoma de uma abstração que juntou conhecimentos que deveriam estar separados.
Existe até uma frase que resume o antídoto: uma abstração errada custa mais caro do que duplicação. Sandi Metz popularizou a ideia de que, na dúvida, é melhor duplicar do que abstrair cedo demais.
Como saber se a duplicação é real#
- Pergunte se os trechos mudam pelas mesmas razões. Se mudam juntos, compartilham conhecimento e devem ser unificados. Se podem mudar por motivos independentes, são duplicação coincidente — deixe separados.
- Espere o terceiro caso. A "regra do três" sugere abstrair só quando o padrão aparece pela terceira vez. Duas ocorrências ainda não dão informação suficiente sobre a forma certa da abstração.
- Observe a origem do conhecimento. Duas regras que vêm do mesmo documento, da mesma lei ou da mesma decisão de produto provavelmente são o mesmo conhecimento. Duas regras que só coincidem numericamente, não.
Essa cautela conversa diretamente com YAGNI explicado: você não vai precisar disso, que adverte contra construir generalizações para necessidades que talvez nunca cheguem, e com KISS: o princípio Keep It Simple, Stupid no desenvolvimento de software, que lembra que a solução mais simples costuma ser a mais saudável.
DRY, acoplamento e o equilíbrio com WET#
Aplicar DRY sempre cria um acoplamento: quem usa a abstração passa a depender dela. Esse acoplamento é desejável quando o conhecimento é realmente compartilhado, porque garante consistência. Mas é prejudicial quando ele força módulos independentes a evoluírem juntos sem necessidade.
Por isso, alguns autores defendem uma postura deliberadamente chamada de WET — Write Everything Twice ("escreva tudo duas vezes") — como contraponto bem-humorado. A ideia não é abandonar o DRY, e sim lembrar que a primeira repetição não é problema: ela é informação. É na segunda ou terceira ocorrência que o padrão se revela e a abstração correta fica visível.
O trade-off central, portanto, é este:
- Duplicação custa esforço de manutenção e risco de inconsistência.
- Abstração prematura custa acoplamento e flexibilidade perdida.
Não existe resposta universal. Existe a pergunta certa: esses trechos representam o mesmo conhecimento e mudam pelas mesmas razões?
DRY e os outros princípios#
DRY não vive isolado. Ele faz parte de um conjunto de boas práticas que se reforçam:
- O O que é Clean Code? Guia completo de código limpo trata a duplicação como um dos principais inimigos da legibilidade; Robert C. Martin chega a chamá-la de "o mal raiz de um software bem projetado" (Martin, 2008).
- Os O que é SOLID? Os 5 princípios do design orientado a objetos ajudam a posicionar onde o conhecimento único deve viver — em especial o Princípio da Responsabilidade Única, que pede uma só razão para uma classe mudar. Repare na sintonia: se uma classe tem uma única razão para mudar, é natural que o conhecimento por trás dessa razão tenha uma única representação.
- A duplicação raramente é removida no primeiro rascunho. Eliminá-la com segurança é uma atividade de O que é refatoração e quando aplicar, feita em passos pequenos e idealmente protegida por testes.
Como aplicar DRY no dia a dia#
Algumas práticas tornam o princípio operacional sem cair no exagero:
- Centralize constantes e configurações. Valores como limites, mensagens e chaves não devem aparecer literalmente em vários arquivos.
- Extraia funções para regras de negócio repetidas, não para qualquer linha parecida.
- Use uma única fonte de verdade para dados derivados. Calcule o que pode ser calculado em vez de armazenar e sincronizar.
- Gere o que pode ser gerado. Tipos a partir de schemas, clientes de API a partir de contratos — isso ataca a duplicação imposta.
- Converse com o time. Boa parte da duplicação é de comunicação: alguém já resolveu aquilo.
- Tolere duplicação até entender o padrão. Abstrair com base em uma única ocorrência é adivinhação.
- Documente a intenção quando duplicar de propósito. Um comentário curto ("duplicado de propósito: regra independente da do checkout") evita que um colega 'corrija' sua decisão consciente.
Erros comuns ao perseguir DRY#
- Confundir semelhança visual com conhecimento compartilhado. Dois loops parecidos não são necessariamente o mesmo conceito.
- Criar utilitários genéricos cedo demais. A função helpers.js que faz "um pouco de tudo" costuma ser o cemitério de abstrações apressadas.
- Extrair antes de ter testes. Sem rede de segurança, unificar trechos vira fonte de regressão.
- Acoplar camadas diferentes. Reusar uma validação de domínio dentro da camada de UI pode parecer DRY, mas mistura responsabilidades.
- Ignorar o custo de leitura. Às vezes uma abstração "DRY" exige tantos parâmetros e indireções que ler o código fica mais difícil do que ler a versão duplicada.
Perguntas frequentes#
DRY significa que nunca posso repetir uma linha de código? Não. DRY trata de conhecimento, não de caracteres. Repetir uma linha trivial que não representa nenhuma regra de negócio é perfeitamente aceitável e muitas vezes mais legível do que criar uma abstração para ela.
Qual a diferença entre DRY e reutilização de código? Reutilização é uma das ferramentas para alcançar DRY, mas não a única. Você também respeita DRY usando configuração centralizada, geração de código ou uma única fonte de dados. E nem toda reutilização é boa: reusar código que representa conhecimentos distintos viola o espírito do princípio.
Quando devo deliberadamente violar o DRY? Quando os trechos podem evoluir por razões independentes, quando o padrão ainda não se firmou (menos de três ocorrências) ou quando a abstração necessária seria mais complexa de entender do que a duplicação. Nesses casos, duplicar é a escolha madura.
DRY se aplica a testes? Com cuidado. Testes valorizam clareza e independência mais do que reúso. Um pouco de duplicação entre testes costuma ser saudável, porque cada teste deve ser legível isoladamente. Abstrair demais a configuração de testes pode esconder o que está sendo verificado.
Conclusão#
DRY é um princípio sobre conhecimento, não sobre caracteres. O objetivo é garantir que cada regra, decisão ou fato tenha um único lugar definitivo no sistema, de modo que mudanças sejam feitas em um ponto só e o software permaneça coerente consigo mesmo. Bem aplicado, o DRY reduz bugs, diminui o medo de mexer no código e mantém a documentação e o comportamento em sincronia.
Mas DRY mal interpretado — como "nunca repita uma linha" — leva a abstrações prematuras que acoplam coisas que deveriam evoluir separadas. A pergunta que deve guiar cada decisão não é "esses trechos são parecidos?", e sim "eles representam o mesmo conhecimento e mudam pelas mesmas razões?". Quando a resposta for sim, unifique. Quando for não ou "não sei ainda", tolere a duplicação e espere o padrão se revelar. É essa leitura madura — que entende o acoplamento criado por cada abstração e sabe pesar duplicação contra rigidez — que separa um código limpo de um código artificialmente espremido.
Referências#
- Andrew Hunt, David Thomas (1999). The Pragmatic Programmer: From Journeyman to Master. Addison-Wesley.
- Robert C. Martin (2008). Clean Code: A Handbook of Agile Software Craftsmanship. Prentice Hall.
- Sandi Metz (2016). The Wrong Abstraction. sandimetz.com.
- Martin Fowler (2018). Refactoring: Improving the Design of Existing Code (2nd ed.). Addison-Wesley.


