Os "Maus Cheiros" do código

dfirmino

Davi Firmino

Posted on October 26, 2020

Os "Maus Cheiros" do código

Descrição

Esse post tem o intuito de conversar um pouco sobre os "Maus Cheiros" do código, tendo como base o livro Refactoring: Improving the Design of Existing Code do Martin Fowler.
Se você nunca leu esse livro, você está perdendo uma ótima leitura que com certeza irá adicionar muito ao longo de sua carreira.

Os maus cheiros

Os maus cheiros do código são indícios de que um código precisa ser refatorado. Se trata de determinadas estruturas problemáticas que se repetem e podem causar problemas com o passar do tempo.
Não existe uma receita de bolo, iremos tratar de alguns indícios de que pode haver um problema e cabe a sua experiência e intuição decidir se vale ou não a pena refatorar.
Vamos entrar em detalhes sobre esses "cheiros".

Nome misterioso

Esse talvez seja o mais simples e comum de encontrarmos no dia a dia.
Quantas vezes não encontramos aquela variável teste no código ou até mesmo collection (coleção de que cara pálida?).
O livro constantemente nos lembra da importância de escolhermos bons nomes.
Ler um bom código tem que ser tão natural quanto ler um bom livro.
Existem alguns métodos que podemos usar para ajudar nesse ponto:

Pode parecer óbvio essa recomendação mas passamos o dia inteiro nomeando as coisas e escolher bons nomes realmente é uma tarefa difícil.

Código duplicado

Se você encontrar o mesmo código em 2 lugares diferentes pode ter certeza que não demora muito você modificar um e esquecer do outro e acabar quebrando alguma parte do seu sistema.
Um código pode se repetir em diversas formas e estruturas diferentes.
Se você encontrar uma expressão que está se repetindo podemos utilizar:

Função longa

Não existe uma regra para determinar quantas linhas uma função tem que ter.
Eu gosto da definição: "Uma função deve fazer bem uma coisa e apenas uma".
Podemos utilizar as seguintes técnicas:

Lista longa de parâmetros

Uma grande quantidade parâmetros na função pode ser um sinal de que ela não está fazendo somente uma coisa ou pode ser sinal de um código bem confuso de ler.
Algumas técnicas que nos ajudam:

Dados globais

Se você é programador javascript você sabe melhor que ninguém o problema de se possuir dados globais.
O problema de dados globais é que eles podem ser modificados em qualquer parte da sua aplicação tornando quase impossível (dependendo do tamanho da mesma) descobrir quem foi o infeliz que modificou eles.
Para isso, podemos utilizar:

Dados mutáveis

Mudança constante de dados pode acabar resultando em consequências inesperadas.
Mudamos no ponto A e as vezes ocorre um erro no ponto B pois esse novo ponto esperava algo diferente do que veio.
A programação funcional tem como um dos princípios a imutabilidade de dados, eles devem evoluir não mudar.
Vale a pena da uma olhada nesse conceito..
Uma lista de técnicas que nos ajudam:

Alteração divergente

Com certeza você já lidou com um projeto em que você olhou e pensou: "bom caso eu precise adicionar tal coisa é fácil é só alterar esses 5 funções dessa classe".
Nesse caso ambos os métodos estão na mesma classe e se você tem que mexer em vários lugares para fazer uma alteração convém tentar centralizar isso em um único método.
Podemos utilizar:

Cirurgia com rifle

Eu adoro essa definição, é ligeiramente parecida com a alteração divergente mas ao invés de ser a mesma classe para mudar uma determinada funcionalidade você tem que mexer em várias classes diferentes.
Se você tem que mexer em vários lugares, fica fácil esquecer de alterar algum ponto.
Podemos utilizar:

Inveja de Recursos

Acontece quando uma determinada função ou classe de um módulo gasta mais tempo se comunicando com outra função de outro módulo do que com o próprio módulo que ela está.
"É claro que há vários padrões sofisticados que violam essa regra. Da gangue dos quatro (GOF), Strategy e Visitor. Self Delegation de Kent Beck é outro. A regra geral básica é colocar junto aquilo que muda junto. Dados e os comportamentos que referenciam esse dado em geral mudam juntos - mas há exceções. Quando exceções ocorrem, movemos o comportamento para manter as alterações em um só lugar. Strategy e Visitor lhe permitem modificar facilmente o comportamento porque isolam a pequena dose de comportamento que deve ser sobrescrita, ao custo de mais acessos indiretos."
Podemos utilizar:

Agrupamento de dados

Dados que constantemente são usados juntos, deveriam possuir um agrupamento para eles.
Podemos utilizar:

Obsessão por primitivos

Normalmente encontramos códigos que são obcecados pelos usos primitivos ao invés de criarem seus próprios tipos (leia como classe).
Podemos utilizar:

Switches repetidos

A grande maioria das instruções switch podem ser substituídas por polimorfismo.
O problema com o switch duplicados é que sempre que tiver uma mudança você terá que alterar eles.

Laços

Quase sempre podemos alterar laços por funções mais declarativas que fazem mais com menos (map, filter, reduce...)

Elemento ocioso

É aquela classe ou função que imaginávamos que poderia crescer mas esse dia nunca chegou.
Podemos utilizar:

Campo temporário

As vezes em uma classe você vê um campo que só é definido em uma determinada circunstância, um código assim pode ser difícil de entender.
Tentar entender o porquê do campo aparecer em um momento e em outro não pode te deixar louco.
Podemos utilizar:

Cadeia de mensagem

Quando você pede um objeto que esse por sua vez pede outro objeto que esse pede outro objeto que pede outro (Já deu pra entender né?).
Isso gera um grande acoplamento na cadeia de navegação e uma mudança pode fazer com que tenhamos que alterar toda essa cadeia.
Podemos utilizar:

Intermediário

As vezes você encontra um objeto que não faz nada além de delegar para outros objetos.
Se tornando apenas um intermediário sem função concreta. Nesse contexto removemos esse intermediário deixando os objetos se comunicarem diretamente.
Podemos utilizar:

Classe Grande

As vezes encontramos classes que fazem mais de uma coisa ou com códigos duplicados.
Podemos utilizar:

Classes alternativas com interfaces diferentes

Quando você encontra classes diferentes com métodos diferentes mas que na prática fazem a mesma coisa.
Podemos utilizar:

Herança Recusada

Quando uma classe herda os dados mas não usa eles ou utilizam quase nenhum.
Podemos utilizar:

Comentários

Comentários não são ruins mas se eles são usados em excesso pode ser um sinal de que o código esteja muito difícil de compreender.

Conclusão

Como podemos ver escrever um código é uma tarefa complexa que em grande parte é tratado como se fosse algo trivial sem a atenção necessária.
Se você chegou a conclusão que ainda tem muito que melhorar quero te dizer que estamos juntos (eu também tenho muito que aprender inclusive muitas dessas técnicas listadas eu ainda estou longe de dominar).
Vou transcrever uma parte do livro clean code que acho que se encaixa com esse post (com quase tudo na verdade).
"lembre-se daquela piada sobre o violinista que se perdeu no caminho para a apresentação em um concerto? Ele aborda um senhor na esquina e lhe pergunta como chegar no Carnegie Hall. O senhor observa o violinista com seu violino debaixo do braço e diz: "Pratique, filho. Pratique!"

Nota

Ficou um post extenso e acredito que a grande maioria não irá ler até o fim, escrevo mais como uma forma de fixar o conteúdo aprendido e de distrair a cabeça nessa quarentena.
Sinta-se a vontade para oferecer sugestões de melhorias (Quem sabe não podemos aprender juntos) ou xingamentos.
Espero que não tenha violado nenhum direito autoral com esse post...
Esse post toca apenas a superfície de todo material oferecido no livro caso queira aprofundar sobre o assunto sugiro fortemente a compra do mesmo.
No mais é isso, pra quem chegou até aqui valeu falou.

💖 💪 🙅 🚩
dfirmino
Davi Firmino

Posted on October 26, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related