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.

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:
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:
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
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:
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:
Como aplicar DRY no dia a dia
Algumas práticas tornam o princípio operacional sem cair no exagero:
Erros comuns ao perseguir DRY
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.