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...
3
1

O que separa o júnior do sênior é o pleno :D Ok, falando sério, o que conta para determinarmos se a pessoa é iniciante ou experiente (mas as pessoas não experientes de forma correta, chamam de júniores e sêniores, que é só uma classificação de RH), é a pessoa saber criar algo de valor hoje e facilitado para amanhã, sem desperdícios desnecessários e fazendo escolhas que entregam os melhores resultados. O que o experiente não faz é seguir receitas de bolo, ou seja, não fazer algo sempre porque alguém disse que é para ser assim.

Então muitos dos artigos, livros, palestras e outras fontes, podem estar vendendo uma ideia específica, e que pode ter muito valor, mas é comum elas não demonstrarem que não deve ser usado sempre daquele jeito.

Assim como vender o DRY como solução única está errado, vender outras coisas como a melhor estratégia sempre, também é errado.

A minha experiência mostra que o DRY é uma das coisas mais importantes (talvez a mais) de seguir na programação, em organização de dados, documentação e outros aspectos até fora da engenharia de software. Mas é claro que ele não funciona bem se adotado errado. Já deveria ser um pressuposto que DRY errado não é DRY. Veja mais: https://pt.stackoverflow.com/q/120931/101.

Em função de muitos erros assim alguém um dia escreveu algo falando sobre abstrações erradas. E é correto dizer isso. Mas não podemos seguir cegamente alguma regrinha para não fazer DRY, por exemplo, não faz sentido esperar aparecer a terceira ocorrência. Se deve ser DRY deveria ser mesmo com uma ocorrência, ou seja, você cria a abstração porque ela é adequada, mesmo que acabe nunca tendo uma segunda ocorrência. Inclusive porque deve eliminar isto: https://pt.stackoverflow.com/q/354926/101.

Quando se fala em ter 3 ocorrências, parece que está se confundindo DRY com repetição. E porque deveríamos aceitar duas cópias de algo que é canônico? Porque você teria dificuldades de manter a integridade do conceito com 3 ocorrências, mas não com duas?

Por isso pegar requisitos é tão importante e difícil, que exige muita experiência qualitativa. E mesmo assim, será comum as pessoas errarem, temos exemplos de monte nos produtos mais populares e criados por pessoas perto da genialidade. Se está difícil entender a abstração, use técnicas para melhorar isso, faça protótipos, discussões abertas, aprenda fazer as perguntas certas, use ferramentas que possam ajudar (algumas podem atrapalhar, depende de como se usa, oooiiii IA), ache a abstração certa e tente validar melhor antes que não possa mais mudar. E não tenha medo de criar outra abstração evoluída se no futuro for necessário.

Em alguns cenários é o adequado, em outros pode ser que esperar pela terceira ocorrência ou até mais seja mais adequado. Não tem fórmula mágica, só a experiência determinará o melhor caminho.

O primeiro vídeo do meu canal falará justamente sobre essa questão de seguir "boas práticas" ser uma péssima prática (calma, quando você ver o conteúdo, verá que não é maluquice).

A falta de abstração onde precisa é intrinsicamente a abstração errada.

Só uma pessoa inexperiente acha que é fácil desfazer uma duplicação. Isso foi escrito por uma pessoa que teve uma experiência de programação na vida em ambiente de mainframe, que muito diferente de como fazemos software hoje em dia e depois em ambiente acadêmico, aí ele virou professor/consultor. Algumas más línguas costumam dizer que quem sabe faz, quem não sabe, ensina :D Por isso precisamos saber de onde vem a fonte, precisamos questionar a motivação e a capacidade da pessoa que prega algo.

Não quer dizer que a regra esteja errada, só que ela é uma simplificação. Tem cenários que ela pode ser ótima, mas esses cenários são cada vez menos prevalentes.

Eu tenho extensiva experiência em código duplicado e na maioria dos casos é tão trágico que reescrever tudo começa parecer algo mais adequado do que tentar consertar as abstrações.

Quando se fala de DRY como se fosse repetição já sabemos que a abstração errada será feita. Sem entender o conceito corretamente, o problema ainda é muito mais grave do que duplicar.

Tem até cenários que fazer sem engenharia alguma dá certo.

Sabe quando as pessoas falam que o código deve dizer o que ele faz em vez de pôr um comentário? Então, só dá certo fazendo as abstrações certas, mesmo que use apenas uma vez.

Quem faz errado poderá fazer com 2, 3, 4 ou muito mais ocorrências. Talvez a maior deficiência que programadores têm hoje em dia seja criar abstrações, independente de DRY. Olhe para as bibliotecas padrões das linguagens. Olhe para os casos que recriaram alguma API porque a original foi mal feita. Adquira experiência com o erro dos outros (bons) programadores.

Nem todo mundo concorda que o SQL é a abstração perfeita, até porque foram colocando uma batelada de novas formas de uso para compensar a abstração ruim.

Tem casos que oferecer algo com maior abstração e algo menos abstraído para o consumidor usar o que for melhor em cada caso é a solução adequada.

Ninguém sabe o que é legado. Tem tantas definições que ele pode ser visto de formas muito diferentes por pessoas diferentes em momentos diferentes. Ah, como um DRY aqui faz falta...

A frase acima usada para definir legado é recursiva, porque dívida técnica é você ter adquirir mais problemas que pagar soluções.

Acho que não conseguirei acompanhar o clube para avaliar se o encontro foi na direção certa, espero que tenham percebido que o livro não é estabeleceu uma verdade absoluta, apenas deu uma ideia interessante e útil para alguns casos, ou seja, é bom saber que existe, melhor ainda saber que não vale para tudo. De qualquer forma pouco depois que publiquei percebi que o clube não pode ser levado a sério, belo clube que só pode existier uma verdade (ironicamente acaba sendo a abstração errada por não permtir informação divergente).

Algumas pessoas para ouvir: Fabrice Bellard, Walter Bright, Casey Muratori, Andy Kekkey, Jonathan Blow, Mike Pal, Guy L. Steele Jr., Dave Cutler, Matt Godbolt, Howard Chu, só para dizer alguns que são pouco conhecidos.

Pode ajudar: https://www.tabnews.com.br/maniero/faq-do-programador-perdidao.

S2


Farei algo que muitos pedem para aprender a programar corretamente, gratuitamente (não vendo nada, é retribuição na minha aposentadoria) (links aqui).

1

Insights fantásticos. Vale a pena participar do encontro, há muita troca de experiência e um ambiente muito bacana para nos fazer refletir e discutir de forma mais profunda temas que está no nosso dia a dia, mas que por vezes negligenciamos.

1