O canivete suíço que ninguém usa inteiro
Existe um canivete suíço com 87 ferramentas — e ninguém nunca usou o abridor de charuto embutido. Ele é pesado, caro e desconfortável justamente pelo que 'talvez um dia' seja útil. YAGNI é escolher o canivete de três lâminas que resolve 99% dos casos; KISS é preferir a faca simples quando você só vai cortar pão; e DRY é não ter três canivetes idênticos na mesma gaveta — mas também não fundir a chave de fenda com o saca-rolhas só porque os dois giram.
A duplicação que não era duplicação
O erro mais caro do DRY é unir código que só parecia igual. Dois trechos idênticos hoje podem representar regras diferentes que mudam por motivos diferentes — um desconto de RH e um imposto que por acaso são ambos 10%.
Unificá-los cria um acoplamento invisível: quando a alíquota fiscal muda e alguém edita a função 'compartilhada', o desconto de RH muda junto, sem ninguém pedir. A abstração errada é mais cara que a duplicação que ela tentou eliminar.
A regra prática é olhar o motivo da mudança, não a aparência do código — é o SRP disfarçado. Se dois trechos sempre vão mudar juntos, são o mesmo conhecimento: unifique. Se podem mudar por motivos independentes, são coincidência: deixe separados, mesmo que o código fique igual por enquanto.
Daí a regra dos três: espere a terceira repetição antes de abstrair. Com uma ocorrência não há duplicação; com duas, ainda não dá para saber qual parte é a regra e qual é o acidente; na terceira, o padrão real fica visível e a abstração acerta o recorte. Abstrair na primeira é adivinhar — e 'a abstração errada é muito mais cara que a duplicação', como resume Sandi Metz.
Como isso aparece na prática
O framework interno que ninguém pediu
Cenário
Para 'evitar repetição no futuro', um time construiu um framework de configuração genérico antes do segundo caso de uso existir. Meses depois, o segundo caso não encaixava, e o framework foi contornado com gambiarras.
Como o padrão entra
O framework foi removido e o código voltou a resolver cada caso diretamente. A generalização só voltou a ser considerada quando surgiu o terceiro caso real, aí sim com o padrão claro.
Trade-off: Houve retrabalho de desmontar o que já existia. Em troca, o código ficou legível de novo, e a abstração futura passou a ser guiada por casos reais, não por adivinhação.
A função utilitária que acoplou dois mundos
Cenário
Um formatarValor compartilhado formatava tanto preços de produto quanto valores de relatório contábil. Um pedido do time contábil (casas decimais diferentes) quebrou a exibição de preços na loja.
Como o padrão entra
A função foi dividida em duas — formatarPreco e formatarValorContabil — apesar de o código ser quase idêntico, porque as duas mudam por motivos diferentes.
Trade-off: Voltou a existir código parecido em dois lugares. Em troca, cada contexto passou a evoluir sozinho, sem que uma mudança fiscal quebrasse a vitrine.
- 1
Olhar o motivo da mudança
Dois trechos iguais mudam pelo mesmo motivo? É conhecimento duplicado. Mudam por motivos diferentes? É coincidência — deixe separado.
- 2
Esperar a terceira repetição
Com uma ou duas ocorrências, ainda não dá para acertar o recorte. Na terceira, o padrão real aparece e a abstração cabe.
- 3
Extrair só o que é a mesma regra
DRY une conhecimento, não texto. Unifique a regra de negócio compartilhada; não funda RH com fiscal porque ambos são 10%.
- 4
Parar no mínimo que funciona
KISS e YAGNI: resolva o problema de hoje. Generalize quando o terceiro caso real pedir — não antes.
O DRY que acoplou dois mundos
Compila, roda, passa no code review. E quebra depois.
Dois cálculos 'iguais' (desconto de RH e imposto) viram uma função única. O diff ficou menor — e uma mudança fiscal passa a alterar a política de RH sem ninguém pedir.
// Dois 10% "iguais" — DRY apressado unifica.
function aplicarDezPorcento(valor: number) {
return valor * 0.1;
}
const descontoRH = aplicarDezPorcento(salario); // politica de RH
const imposto = aplicarDezPorcento(salario); // regra fiscal
// Aliquota fiscal vira 12%. Alguem edita a funcao unica.
// Desconto de RH muda junto. A abstracao acoplou dois mundos.O que quebra
- Na reforma tributáriaEditar a função compartilhada muda o desconto de RH junto — bug silencioso em outro domínio.
- No testeCobrir fiscal exige raciocinar sobre RH, porque os dois compartilham o mesmo ponto de mudança.
- Na revisãoO nome genérico (
aplicarDezPorcento) esconde que há duas regras de negócio distintas atrás.
A saída: Separe por motivo de mudança: descontoRH e impostoRetido podem parecer iguais e ainda assim ser conhecimento diferente. Unifique só o que sempre muda junto.
Onde isto dá errado
Aplicar DRY a texto, não a conhecimento
Dois trechos iguais nem sempre são a mesma regra. Se eles mudam por motivos diferentes, unificá-los acopla o que devia ser independente, e uma mudança num contexto vaza para o outro sem aviso.
Usar KISS para justificar o simplista
Simples não é o mesmo que fácil. Espremer complexidade essencial (concorrência, falha, consistência) para 'ficar simples' só empurra o problema para produção, onde ele volta mais caro.
Usar YAGNI contra requisito conhecido
YAGNI vale para o que talvez venha, não para o que já se sabe que vem. Ignorar um requisito iminente em nome de 'você não vai precisar' é confundir simplicidade com míopia.
Duplicação legítima × falsa
// DRY diz: uma regra, um lugar. Mas cuidado com a FALSA duplicacao.
// Estes dois calculos SAO iguais hoje — e mudam pelo MESMO motivo:
function totalPedido(itens) { return itens.reduce((s, i) => s + i.preco, 0); }
// -> extrair para uma funcao unica e DRY legitimo.
// Estes dois PARECEM iguais, mas mudam por motivos DIFERENTES:
const descontoFuncionario = salario * 0.1; // politica de RH
const impostoRetido = salario * 0.1; // regra fiscal
// -> unificar em "aplicar10Porcento" acopla RH a fiscal.
// Quando a aliquota fiscal mudar, o desconto de RH muda junto. Bug.
// A regra dos tres: so abstraia na TERCEIRA repeticao. Antes disso,
// voce ainda nao sabe se e a mesma regra ou uma coincidencia.Quando usar × quando evitar
Use quando
3- DRY quando o mesmo conhecimento se espalha e muda junto.
- KISS quando há solução mais simples para o mesmo problema.
- YAGNI diante da vontade de generalizar sem caso real.
Evite quando
2- DRY quando a semelhança é coincidência.
- YAGNI como desculpa contra requisito conhecido e iminente.
Testar o que ficou
3 armadilhas de DRY, KISS e YAGNI viram perguntas, com o nome do padrão escondido, misturadas com padrões parecidos.
Onde isto aparece de verdade
Você já usa isto, talvez sem saber o nome.
a regra dos trêsSó abstrair na terceira repetição: antes disso, duplicar é mais barato que a abstração errada que um DRY apressado cria.a feature flag que nunca ligouCódigo escrito 'para o futuro' que passou anos desligado é o YAGNI cobrando: não se paga hoje pelo que talvez não venha.o MVPEntregar a versão mínima que resolve o problema, sem os enfeites que ninguém pediu, é KISS e YAGNI virando estratégia de produto.
O padrão em uma linha
Sem nome de domínio, sem cerimônia. Só a ideia.
// Três freios: não repita, não complique, não antecipe.
// Extraia quando a duplicação doer de verdade.O que ele cobra
Nenhum salto a mais entre a chamada e o efeito.
- DRY apressado acopla coisas que só pareciam iguais, e desfazer isso depois é caro
- YAGNI mal lido vira desculpa para não desenhar nem o mínimo necessário
Não vale se: a duplicação é coincidência e as cópias evoluem por motivos diferentes — unificá-las cria um acoplamento que atrapalha mais do que ajuda.
Onde isto aparece
Continue por aqui
- SRP — Responsabilidade ÚnicaUm módulo deve ter apenas uma razão para mudar — ou seja, deve responder a um único interessado do negócio, e não acumular decisões que evoluem por motivos diferentes.
- OCP — Aberto/FechadoMódulos devem ser abertos para extensão e fechados para modificação: adicionar comportamento novo deveria significar escrever código novo, não reabrir e alterar o que já funciona.
- Composição sobre herançaHerança promete reúso e entrega acoplamento: a subclasse herda tudo do pai, inclusive o que não queria, e a árvore engessa numa dimensão só. Compor comportamento a partir de peças encaixáveis dá o mesmo reúso sem amarrar quem usa a quem fornece — por isso o conselho antigo de preferir composição, e só herdar quando a relação 'é um' é honesta.