Não é incomum surgirem dúvidas em relação ao processo de refatoração, principalmente sobre o que é, quando, o porquê, entre outros. Vamos tratar um pouco disso neste artigo!
Surgida na década de 80, refatoração é um processo de melhoria de código sem, necessariamente, envolver a criação de novas features, para transformar um código mal feito ou bagunçado em código limpo e com design simples, melhorando sua legibilidade e eficiência.
É um conceito simples, mas na prática encontramos dificuldades comuns na realização desse processo, principalmente se for um grande projeto com alto grau de complexidade. A melhor abordagem para lidar com isso é o planejamento e a documentação.
Mas por que refatorar código? Refatorar evita a deterioração durante o ciclo de vida de um código, o que não é incomum. Outro motivo é a melhora do entendimento do código, facilitando a manutenção e os famosos bugs.
Além disso, é de fundamental importância que todo o código tenha cobertura de testes automatizada para garantir que o comportamento externo não tenha mudado.
Extreme Programming (XP)
O XP (Extreme Programming ou Programação Extrema) é uma metodologia ágil focada no desenvolvimento de software. Possui valores e princípios que devem ser aplicados durante a etapa de desenvolvimento de software.
Os cinco valores fundamentais são: comunicação, simplicidade, feedback, coragem e respeito.
Nesse sentido, possui princípios básicos como feedback rápido, presumir simplicidade, mudanças incrementais, abraçar mudanças e trabalho de qualidade.
As práticas do Extreme Programming consistem no núcleo principal do processo, evidenciando valores necessários e suficientes para um projeto de sucesso: cliente presente, planejamento, stand up meeting, programação em pares, testes constantes, código coletivo, padronização do código, design simples, integração contínua, releases curtos e, nossa prática tratada neste artigo, refatoração.
Como lidar com software legado: O guia completo!
Refatoração e Código Limpo
Tornar o código limpo também é um processo de refatoração, ou pelo menos pode ser, dependendo se esse cuidado foi tomado durante o desenvolvimento das releases.
Uma literatura referência nesse assunto é o Clean Code: A Handbook of Agile Software Craftsmanship. É uma das melhores referências que podemos ter para entender e aplicar as práticas do Clean Code.
Código limpo nada mais é um código simples, elegante e direto. Facilmente entendível para qualquer desenvolvedor que trabalha no código com o propósito realizar a manutenção. Mas não se deixe levar somente por um conceito ou definição. Robert C. Martin revela que devem haver tantas definições para Clean Code quanto a quantidade de programadores. Alguns práticas do clean code são:
- Utilizar nomes significativos.
- Funções curtas.
- Bons comentários.
- Formatação de código.
- Tratamento de erros.
- etc.
Refatorar um código para deixá-lo limpo significa:
- Remover todo código duplicado.
- Remover classes desnecessárias, tornando o número delas mínimo com responsabilidades bem definidas.
- Fazer de tal forma que todos os teste passem.
Praticar Código Limpo: começando agora!
Quando devemos refatorar?
Podemos e devemos realizar a refatoração quando:
- Estivermos implementando algo pela primeira vez.
- Fizermos algo que já foi feito antes. Refaça de tal modo para não repetir.
- Tivermos que fazer algo de novo, ou mesmo quando realizar uma revisão.
Como realizar a refatoração?
Para começar a refatorar o código, devemos ter sempre em mente que:
Devemos realizar uma série de alterações atômicas, se possíveis, com um escopo pequeno. Isso vai deixar o código existente cada vez melhor com o tempo e programa em geral em funcionamento.
Abaixo, um checklist para o processo de refatoração:
- O código deve estar conforme as práticas do Clean Code.
- Não há desenvolvimento de novas features.
- Os testes passam depois da refatoração, todos eles.
Para isso, existem algumas técnicas que podemos utilizar para refatorar nosso código.
Técnicas de refatoração
- Método de extração.
Problema: você tem um fragmento de código que pode ser agrupado.
Solução: mova esse código para um novo método (ou função) separado e substitua o código antigo por uma chamada ao método.
- Método em linha.
Problema: quando um um corpo de método é mais óbvio que o próprio método, use esta técnica.
Solução: substitua as chamadas para o método pelo conteúdo do método e exclua o próprio método no processo de refatoração.
- Extrair variável.
Problema: você tem uma expressão difícil de entender.
Solução: coloque o resultado da expressão ou de suas partes em variáveis separadas que são auto-explicativas.
- Dividir variável temporária.
Problema: você tem uma variável local usada para armazenar vários valores intermediários dentro de um método (exceto para variáveis de ciclo).
Solução: use variáveis diferentes para valores diferentes. Cada variável deve ser responsável por apenas uma coisa em particular.
- Remover atribuições a parâmetros.
Problema: algum valor é atribuído a um parâmetro dentro do corpo do método.
Solução: use uma variável local em vez de um parâmetro na refatoração.
Técnicas de substituição
- Temp inline.
Problema: você tem uma variável temporária à qual é atribuído o resultado de uma expressão simples e nada mais.
Solução: substitua as referências à variável pela própria expressão na refatoração.
- Substituir Tem por consulta.
Problema: você coloca o resultado de uma expressão em uma variável local para uso posterior no seu código.
Solução: mova a expressão inteira para um método separado e retorne o resultado. Consulte o método em vez de usar uma variável. Incorpore o novo método em outros métodos, se necessário.
- Substituir método por objeto de método.
Problema: você tem um método longo no qual variáveis locais estão tão entrelaçadas que não é possível aplicar o Método de Extração.
Solução: transforme o método em uma classe separada para que as variáveis locais se tornem campos da classe. Em seguida, você pode dividir o método dentro da mesma classe.
- Algoritmo substituto.
Problema: substituir um algoritmo existente por um novo.
Solução: substitua o corpo do método que implementa o algoritmo por um novo algoritmo.
Um pequeno exemplo…
Vamos realizar uma pequena refatoração para extrair método do código Java abaixo:
public class Produto {
private String nome;
private String categoria;
private String descricao;
private Integer codigo;
private ProdutoRepositorio produtoRepositorio;
// construtor
// getters e setters
if (this.getName() == null) {
throw new Exception(“É necessário definir um nome para o produto!”);
}
if (this.getCategoria() == null) {
throw new Exception(“É necessário definir uma categoria para o produto!”);
}
if (this.getDescricao() == null) {
throw new Exception(“É necessário definir uma descricao para o produto!”);
}
if (this.getCodigo() == null) {
throw new Exception(“É necessário definir um codigo para o produto!”);
}
public void salvarBancoDeDados() {
this.produtoRepositorio.save(this);
}
}
Refatorando…
public class Produto {
private String nome;
private String categoria;
private String descricao;
private Integer codigo;
private ProdutoRepositorio produtoRepositorio;
// construtor
// getters e setters
private void propriedadesCheker() {
if (this.getName() == null) {
throw new Exception(“É necessário definir um nome para o produto!”);
} else if (this.getCategoria() == null) {
throw new Exception(“É necessário definir uma categoria para o produto!”);
} else if (this.getDescricao() == null) {
throw new Exception(“É necessário definir uma descricao para o produto!”);
} else if (this.getCodigo() == null) {
throw new Exception(“É necessário definir um codigo para o produto!”);
}
}
public void salvarBancoDeDados() {
this.propriedadesCheker();
this.produtoRepositorio.save(this);
}
}
Poderíamos mostrar vários exemplos para cada técnica de refatoração, mas o artigo ficaria grande e cansativo.
O ideal é ir absorvendo aos poucos os conceitos e as técnicas e isso leva um pouquinho de tempo, mas sempre acabamos por dominar todo escopo da refatoração. É apenas prática!