Desenvolvimento

24 nov, 2014

Refatoração – aperfeiçoamento e projeto

Publicidade

O que há de errado em um código simples feito de forma rápida e imperfeita? Aparentemente nada, desde que ele funcione! Seria um julgamento meramente estético? O usuário final e o compilador não se importam se o código é ou não elegante. Mas, quando alteramos uma solução, há um humano envolvido e humanos se importam. Uma solução mal projetada é difícil de ser alterada. Se for difícil descobrir onde e como alterar, há uma grande chance desse humano cometer um erro e introduzir falhas, principalmente se caso o pedaço de código esteja inserido dentro de uma solução complexa.

Refatoração é o processo de alteração de uma solução de modo que o comportamento externo do código não mude, mas que sua estrutura interna seja melhorada. É uma maneira disciplinada e sistemática de aperfeiçoar o código que minimiza a chance de introdução de falhas.

Sem refatoração, o projeto termina por se deteriorar. À medida que as pessoas alteram o código, alterações para executar objetivos de curto prazo, alterações sem uma compreensão total do projeto da solução e principalmente alterações por pessoas sem experiência reais de design OO levam o projeto para o caminho da inflexibilidade e rigidez. Isso tem um efeito cumulativo. Quanto mais difícil é entender a solução a partir do código, mais difícil será de preservá-lo e rapidamente ele se desestruturará.

A seguir, vou resumir cada dica desse livro com o objetivo de ser utilizado com material de referência e estudos:

Maus cheiros #1

Será que você já passou pela experiência de pegar uma criança recém-nascida que acabou de fazer cocô nas fraldas? No mesmo momento que você se aproxima, já percebe instantaneamente aquele cheiro desagradável. Da mesma forma isso acontece em desenvolvimento de software, quando você pega o código fonte de uma solução para dar manutenção já logo de cara sente que alguma coisa não esta cheirando muito bem. Seguindo essa visão, estarei postando os “maus cheiros” mais básicos referindo-se na verdade em um catálogo de anti-padrões que precisam ser, a todo custo, evitado e refatorado.

Código duplicado

Ocorre quando encontramos pedaços de código duplicado em vários lugares diferentes na solução. Você tem que decidir onde faz mais sentido centralizar esse método e garantir que ele fique exclusivamente em apenas um lugar.

Método longo

Ocorre quando encontramos um método com muitas linhas de código, normalmente fazendo muitas responsabilidades ao mesmo tempo. Quanto maior o método, mais difícil é de entender. Por isso, sempre seja agressivo na decomposição de métodos menores.

Maus cheiros #2

Classes grandes

Ocorre quando uma classe tenta fazer muitas coisas, pois ela frequentemente se torna um solo fértil para código duplicado, excesso de variáveis e confusão. Elimine as redundâncias internas e divida uma classe em classes menores, separando logicamente em pedaços que façam sentido dentro do contexto. Use a política de coesão na separação de classes.

Lista de parâmetros longa

Ocorre quando encontramos um método com listas de parâmetros longas, normalmente acima de quatro parâmetros. São difíceis de entender e de usar e por isso, sempre seja agressivo na redução.

Alteração divergente

Ocorre quando qualquer alteração para lidar com uma variante gera mudanças em vários métodos diferentes dentro uma mesma classe. Quando as alterações estão espalhadas em vários métodos diferentes, ela se torna difícil de encontrar, difícil de fazer e fácil de ser esquecido. Você deve identificar tudo que pode mudar e centralizar isso em um único método de alteração.

Maus cheios #3

Alteração divergente

Ocorre quando qualquer alteração para lidar com uma variante gera mudanças em vários métodos diferentes dentro uma mesma classe. Quando as alterações estão espalhadas em vários métodos diferentes, ela se torna difícil de encontrar, difícil de fazer e fácil de ser esquecido. Você deve identificar tudo que pode mudar e centralizar isso em um único método de alteração.

Cirurgia com rifle

Ocorre quando qualquer alteração para lidar com uma variante gera mudanças em vários pontos em classes diferentes. Quando as alterações estão espalhadas em varias classes diferentes, elas se tornam difíceis de encontrar, difíceis de fazer e fácil de ser esquecido. Você deve identificar tudo que pode mudar e centralizar isso em uma única classe de alteração ou na criação uma nova classe.

Inveja dos dados

Ocorre quando um objeto usa dados de outros objetos para fazer operações ou lógicas, fazendo com que o objeto fique mais interessado no estado de outro do que o seu próprio estado. A essência dos objetos é encapsular tanto os dados e as operações que manipulam esses dados. Diante disso, você deve atribuir as responsabilidades a um objeto que seja o mais coerente com suas informações e nuca para um objeto externo. Inveja dos dados é um antipadrão conhecido com Anemic Domain Model.

Maus cheiros #4

Classes de dados

Ocorre quando você encontra classes que contêm apenas dados sem métodos de manipulação. Na maioria das vezes, o estado dessas classes de dados está sendo usados por outras classes. Por isso, evite fazer isso, uma vez que classes devem conter dados e métodos. Classe de dados é um antipadrão conhecido com Anemic Domain Model.

Grupo de dados

Ocorre quando encontramos grupos de campos sendo utilizado de forma duplicada dentro de classes e ou de parâmetros. Estes agrupamentos de dados que perambulam juntos, na verdade deveriam ser agrupados como objeto.

Obsessão primitiva

Ocorre quando encontramos códigos relutantes em usar objetos para pequenas tarefas tais como dinheiro, CPF, CEP, telefone etc., preferindo o uso de tipos primitivos como int, long etc e a classe String. Sempre prefira criar pequenos objetos que façam o devido encapsulamento de primitivos que representem o valor de algum tipo. Futuramente você poderá acrescentar outras operações relacionadas ao tratamento do determinado tipo.

Maus cheios #5

Classe ociosa

Cada classe que você cria custa dinheiro para manter e compreender. Uma classe que não esteja fazendo o suficiente para se pagar deve ser eliminada, principalmente aquelas que foram acrescentadas para suportar alterações futuras de forma antecipada, mas que nunca aconteceu.

Generalidade especulativa

Ocorre quando é implementado estruturas genéricas e flexíveis ao ponto de compor situações futuras que ainda não aconteceram no projeto, sem uma real previsão de acontecer. O resultado muita vezes é a dificuldade de se entender e manter, mais atrapalhando que ajudando. Diante disso, se livre de todas elas. Ou seja, faça somente o que for realmente necessário, deixando o futuro para uma futura refatoração.

Campo temporário

Ocorre quando você encontra um objeto no qual uma variável de instância recebe um valor apenas em determinadas circunstancias de execuções e ou algoritmos, deixando difícil de ler e entender, uma vez que o normal é esperar que um objeto precise de todas as suas variáveis. Diante disso, separe estes campos órfãos em algum lugar diferente, de acordo com o contexto da situação, podendo ser uma nova classe especifica chamada de “objeto método”.

Maus cheiros #6

Cadeias de mensagens

Ocorre quando você encontra longas cadeias de mensagem quando um objeto pede para outro objeto, que por sua vez pede outro objeto e assim por diante… Gerando um acoplamento na cadeia de navegação. Diante disso, sempre tente ocultar ao máximo a delegação.

Intermediário

Ocorre quando você encontra um objeto que extrapola no uso da delegação para outros objetos, sem códigos adicionais, transformando o objeto em apenas um intermediário vazio e sem sentido. Nesse contexto, remova o intermediário fazendo com que o objeto cliente fale diretamente com o objeto que realmente sabe o que está acontecendo.

Intimidade inadequada

Ocorre quando você encontra classes manipulando partes privadas de outras, principalmente no uso de herança que permite que subclasses acessem partes protegidas. Seja radical com premissa básica do encapsulamento: sempre oculte o máximo que puder, evitando expor detalhes internos de um objeto.

Maus cheios #7

Classes alternativas com interfaces diferentes

Ocorre quando você encontra classes diferentes, com assinatura de métodos diferentes, mas que oferecem o mesmo serviço duplicadamente. Refatore e centralize em apenas um único lugar.

Bibliotecas de classes incompletas

Ocorre quando precisamos de um método que está faltando em uma biblioteca, mas não temos como alterar a biblioteca para incluir o método. O método acaba sendo anexados em outra classe. Se você não pode modificar a biblioteca, considere isolar o método.