5

A abstração errada custa mais que a duplicação (e é isso que separa júnior de sênior)

Você vê dois trechos de código parecidos e o instinto te diz na hora: "isso aqui dá pra reaproveitar". Extrai um método, cria uma classe base, um helper, e sai feliz porque não repetiu. Um mês depois chega um requisito que só vale para um dos casos. Você mete um if. Depois uma flag. Depois um parâmetro opcional. Seis meses depois aquele helper "reutilizável" virou um monstro que ninguém tem coragem de tocar.

Se você já viveu isso, você já pagou o preço da abstração errada. E ela é mais cara do que o problema que você achou que estava resolvendo.

DRY virou dogma

O DRY nasceu para você não duplicar conhecimento, não para banir toda linha repetida. São coisas diferentes. Dois trechos que se parecem hoje podem pertencer a dois domínios distintos que vão evoluir para lados opostos amanhã. Nesse caso, a duplicação é intencional: é a mesma lógica vivendo em duas entidades diferentes, e forçar uma abstração ali só amarra dois contextos que deviam andar sozinhos.

A regra prática que fica: duplicou uma vez, ainda é barato. Espere a terceira ocorrência antes de abstrair. Na terceira você finalmente entende o formato do que se repete, e a abstração sai certa em vez de sair chutada.

A frase que resume tudo

Tem uma frase da Sandi Metz que devia estar pregada em todo code review:

A abstração errada é muito mais cara que a duplicação.

O motivo é simples. Com duplicação, quando os casos divergem, você muda uma cópia e pronto. Com a abstração errada, você luta contra a abstração: vai empilhando flag, condicional e caso especial para forçar ela a servir a dois donos que não são iguais. Desfazer uma duplicação é trivial. Desfazer uma abstração ruim que já se espalhou pelo código é cirurgia.

Complexidade essencial vs. complexidade acidental

Todo código tem complexidade, mas não é tudo igual.

A complexidade essencial é a do negócio. Um sistema financeiro é complexo por natureza, você não tem como desejar que essa complexidade suma. Já a complexidade acidental é a que você escolheu adicionar: dez camadas de indireção, sete ferramentas, um padrão de projeto para cada if. Simplicidade é reduzir a acidental, não a essencial.

E aqui mora o vício que quase todo dev tem em alguma fase: as "pattern-itis". A pessoa aprende System Design, aprende os padrões, e sai caçando lugar para aplicar. Aí abstrai coisas que nem têm sobreposição real, só para usar a técnica bonita. Complexidade acidental pura.

Plot twist: às vezes o "avançado" é o errado

Numa mesa sobre System Design, alguém perguntou para duas referências da área quando valia a pena usar Event Sourcing. Antes de responderem, a própria pessoa que perguntou se respondeu: "a gente usou, mas toda mudança gerava complexidade, tinha que mexer num monte de camada".

Event Sourcing não é errado. Aplicar ele onde o problema não pedia, sim. O padrão avançado que parece maturidade muitas vezes é só custo que você comprou sem precisar. O simples costuma resolver, e resolver é o objetivo.

Abstração boa existe (e ela é invisível)

Não é para sair duplicando tudo, calma. Abstração boa é uma das melhores ferramentas que a gente tem: ela esconde complexidade para você não precisar pensar nela.

O SQL é o exemplo perfeito: Você pede os dados e o banco decide o algoritmo de busca, a ordenação, se usa memória ou disco. Você não quer saber de nada disso, e é ótimo. Esse é o teste de uma boa abstração: quando o código precisa ser alterado, um colega consegue olhar o fluxo e entender o que ele faz sem se aprofundar em cada detalhe. A abstração ruim faz o contrário: para entender uma coisa, você precisa pular por três ou mais camadas.

O princípio por trás de tudo

A diferença entre pleno e sênior não é não errar. É saber quando você está adicionando complexidade e por quê.

Tem uma definição de legado que ficou comigo: um sistema virou legado quando a sua capacidade de adquirir dívida técnica passa a ser maior que a sua capacidade de pagar. Cada abstração desnecessária é uma parcelinha nessa dívida. Ela parece grátis no dia que você escreve, e cobra juros em todo bug e mudança que você for resolver depois.

Simplicidade não é falta de sofisticação, é a disciplina de só pagar pela complexidade que o problema realmente exige.


Esse papo saiu do nosso clube do livro sobre Designing Data-Intensive Applications. Acabamos de fechar o Capítulo 2 (requisitos não funcionais, incluindo manutenibilidade), e o próximo encontro é dia 20/07, sobre modelos de dados.

Fica aqui o convite, vamos ler juntos!
https://craftcodeclub.io/book-clubs/designing-data-intensive-applications

Gravação do último encontro:
https://www.youtube.com/live/YEmTPYwv5NY


E aí, qual foi a pior abstração "reutilizável" que você já teve que manter?
E tem alguma duplicação que você deixou de propósito porque abstrair ia doer mais?
Conta nos comentários.

Carregando publicação patrocinada...