Os "Maus Cheiros" do código
Published: 2020-10-26 23:49:45

# 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](https://www.amazon.com.br/Refatora%C3%A7%C3%A3o-Aperfei%C3%A7oando-Design-C%C3%B3digos-Existentes/dp/8575227246/ref=asc_df_8575227246/?tag=googleshopp00-20&linkCode=df0&hvadid=379792215563&hvpos=&hvnetw=g&hvrand=1699732427100617635&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1031786&hvtargid=pla-913708764871&psc=1) 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:
* [Mudar declaração de função](https://refactoring.com/catalog/changeFunctionDeclaration.html)
* [Renomear Variável](https://refactoring.com/catalog/renameVariable.html)
* [Renomear Campo](https://refactoring.com/catalog/renameField.html)

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: 
* [Extrair função](https://refactoring.com/catalog/extractFunction.html).
* [Deslocar instrução](https://refactoring.com/catalog/slideStatements.html)
* [Subir método](https://refactoring.com/catalog/pullUpMethod.html)

## 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:
* [Extrair função](https://refactoring.com/catalog/extractFunction.html).
* [Substituir variável temporária por consulta](https://refactoring.com/catalog/replaceTempWithQuery.html)
* [Introduzia objeto de parâmetro](https://refactoring.com/catalog/introduceParameterObject.html)
* [Preservar objeto inteiro](https://refactoring.com/catalog/preserveWholeObject.html)
* [Decompor condicional](https://refactoring.com/catalog/decomposeConditional.html)
* [Substituir condicional por polimorfismo](https://refactoring.com/catalog/replaceConditionalWithPolymorphism.html)
* [Dividir laço](https://refactoring.com/catalog/splitLoop.html)

## 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:
* [Substituir parâmetro por consulta](https://refactoring.com/catalog/replaceParameterWithQuery.html)
* [Preservar objeto inteiro](https://refactoring.com/catalog/preserveWholeObject.html)
* [Introduzir objeto de parâmetro](https://refactoring.com/catalog/introduceParameterObject.html)
* [Remover argumento de flag](https://refactoring.com/catalog/removeFlagArgument.html)
* [Combinar funções em classe](https://refactoring.com/catalog/combineFunctionsIntoClass.html)

## 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:
* [Encapsular variável](https://refactoring.com/catalog/encapsulateVariable.html)

## 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:
* [Encapsular variável](https://refactoring.com/catalog/encapsulateVariable.html)
* [Separar variável](https://refactoring.com/catalog/splitVariable.html)
* [Deslocar instrução](https://refactoring.com/catalog/slideStatements.html)
* [Separar Consulta de modificador](https://refactoring.com/catalog/separateQueryFromModifier.html)
* [Remover método de escrita](https://refactoring.com/catalog/removeSettingMethod.html)
* [Combinar funções em transformação](https://refactoring.com/catalog/combineFunctionsIntoTransform.html)
* [Mudar referência para valor](https://refactoring.com/catalog/changeReferenceToValue.html)

## 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:
* [Separar em fases](https://refactoring.com/catalog/splitPhase.html)
* [Mover função](https://refactoring.com/catalog/moveFunction.html)
* [Extrair função](https://refactoring.com/catalog/extractFunction.html)
* [Extrair classe](https://refactoring.com/catalog/extractClass.html)

## 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:
* [Mover função](https://refactoring.com/catalog/moveFunction.html)
* [Mover campo](https://refactoring.com/catalog/moveField.html)
* [Separar em fases](https://refactoring.com/catalog/splitPhase.html)
* [Internalizar Classe](https://refactoring.com/catalog/inlineClass.html)

## 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:
* [Mover função](https://refactoring.com/catalog/moveFunction.html)
* [Extrair função](https://refactoring.com/catalog/extractFunction.html)

## Agrupamento de dados
Dados que constantemente são usados juntos, deveriam possuir um agrupamento para eles.
Podemos utilizar:
* [Extrair classe](https://refactoring.com/catalog/extractClass.html)
* [Introduzir objeto de parâmetro](https://refactoring.com/catalog/introduceParameterObject.html)
* [Preservar objeto inteiro](https://refactoring.com/catalog/preserveWholeObject.html)

## 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:
* [Substituir primitivo por objeto](https://refactoring.com/catalog/replacePrimitiveWithObject.html)
* [Substituir código de tipos por subclasses](https://refactoring.com/catalog/replaceTypeCodeWithSubclasses.html)
* [Substituir condicional por polimorfismo](https://refactoring.com/catalog/replaceConditionalWithPolymorphism.html)

## 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.
* [Substituir condicional por polimorfismo](https://refactoring.com/catalog/replaceConditionalWithPolymorphism.html)

## Laços
Quase sempre podemos alterar laços por funções mais declarativas que fazem mais com menos (map, filter, reduce...)
* [Substituir laços por pipeline](https://refactoring.com/catalog/replaceLoopWithPipeline.html)

## Elemento ocioso
É aquela classe ou função que imaginávamos que poderia crescer mas esse dia nunca chegou.
Podemos utilizar:
* [Internalizar Função](https://refactoring.com/catalog/inlineFunction.html)
* [Internalizar Classe](https://refactoring.com/catalog/inlineClass.html)
* [Condensar hierarquia](https://refactoring.com/catalog/collapseHierarchy.html)

## 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:
* [Extrair classe](https://refactoring.com/catalog/extractClass.html)
* [Mover função](https://refactoring.com/catalog/moveFunction.html)
* [Introduz caso especial](https://refactoring.com/catalog/introduceSpecialCase.html)

## 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:
* [Ocultar delegação](https://refactoring.com/catalog/hideDelegate.html)
* [Extrair função](https://refactoring.com/catalog/extractFunction.html)
* [Mover função](https://refactoring.com/catalog/moveFunction.html)

## 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:
* [Remover Intermediário](https://refactoring.com/catalog/removeMiddleMan.html)
* [Internalizar Função](https://refactoring.com/catalog/inlineFunction.html)
* [Substituir superclasse por delegação](https://refactoring.com/catalog/replaceSuperclassWithDelegate.html)
* [Substituir subclasse por delegação](https://refactoring.com/catalog/replaceSubclassWithDelegate.html)

## Classe Grande
As vezes encontramos classes que fazem mais de uma coisa ou com códigos duplicados.
Podemos utilizar:
* [Extrair classe](https://refactoring.com/catalog/extractClass.html)
* [Extrair Superclasse](https://refactoring.com/catalog/extractSuperclass.html)
* [Substituir códigos de tipos por subclasse](https://refactoring.com/catalog/replaceTypeCodeWithSubclasses.html)

## 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:
* [Mudar declaração de Função](https://refactoring.com/catalog/changeFunctionDeclaration.html)
* [Mover função](https://refactoring.com/catalog/moveFunction.html)
* [Extrair Superclasse](https://refactoring.com/catalog/extractSuperclass.html)

## Herança Recusada
Quando uma classe herda os dados mas não usa eles ou utilizam quase nenhum.
Podemos utilizar:
* [Descer método](https://refactoring.com/catalog/pushDownMethod.html)
* [Descer campo](https://refactoring.com/catalog/pushDownMethod.html)
* [Substituir superclasse por delegação](https://refactoring.com/catalog/replaceSuperclassWithDelegate.html)
* [Substituir subclasse por delegação](https://refactoring.com/catalog/replaceSubclassWithDelegate.html)

## 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](https://www.amazon.com.br/Refatora%C3%A7%C3%A3o-Aperfei%C3%A7oando-Design-C%C3%B3digos-Existentes/dp/8575227246/ref=asc_df_8575227246/?tag=googleshopp00-20&linkCode=df0&hvadid=379792215563&hvpos=&hvnetw=g&hvrand=1699732427100617635&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1031786&hvtargid=pla-913708764871&psc=1) caso queira aprofundar sobre o assunto sugiro fortemente a compra do mesmo.
No mais é isso, pra quem chegou até aqui valeu falou.