Refatoração de código legado em Java: por onde começar e como não quebrar o projeto
Todo desenvolvedor Java, mais cedo ou mais tarde, se depara com código legado. Pode ser uma aplicação monolítica escrita há dez anos, ou um projeto com padrões obsoletos, falta de testes e "números mágicos". Refatorar esse código não é uma tarefa fácil, mas é absolutamente necessária para manter a viabilidade do sistema.
Neste artigo, vamos analisar as principais estratégias de refatoração de código legado em Java, mostrar exemplos concretos e dar dicas práticas que ajudarão você a melhorar o código sem o risco de quebrar a produção.
Por que o código legado precisa de refatoração?
Código legado não é apenas "código antigo". É um código que:
- É difícil de manter e estender
- Não tem cobertura de testes suficiente
- Contém duplicação e "maus cheiros" (code smells)
- Usa bibliotecas e abordagens obsoletas
A refatoração permite melhorar a legibilidade, o desempenho e a testabilidade do código. No entanto, a regra principal é não alterar o comportamento externo do sistema. Cada mudança deve ser segura e controlada.
Estratégias de refatoração de código legado em Java
1. Criar uma rede de proteção com testes
Antes de mexer no código, escreva testes. Isso pode ser difícil se o código não for bem testável. Use a abordagem Characterization Tests (testes baseados no comportamento atual).
Exemplo: você tem um método que processa pedidos:
public class OrderProcessor { public double calculateTotal(Order order) { double total = 0; for (Item item : order.getItems()) { if (item.getPrice() > 100) { total += item.getPrice() * 0.9; // desconto de 10% } else { total += item.getPrice(); } } if (order.isPremium()) { total *= 0.95; // desconto adicional de 5% } return total; }}Escrevemos um teste que fixa o comportamento atual:
@Testpublic void testCalculateTotal_WithPremiumAndExpensiveItems() { Order order = new Order(); order.addItem(new Item("Laptop", 1000)); order.addItem(new Item("Mouse", 50)); order.setPremium(true); double expected = (1000 * 0.9 + 50) * 0.95; // 902.5 assertEquals(expected, new OrderProcessor().calculateTotal(order), 0.001);}Agora você tem uma "rede de proteção". Pode refatorar sem medo de alterar a lógica.
2. Dividir métodos grandes (Extract Method)
Um dos problemas mais comuns em código legado são métodos-"monstros" com centenas de linhas. Divida-os em métodos pequenos e bem nomeados.
Antes da refatoração:
public void processInvoice(Invoice invoice) { // 50 linhas de validação if (invoice.getCustomer() == null) throw new IllegalArgumentException(); if (invoice.getItems().isEmpty()) throw new IllegalStateException(); // ... mais 20 linhas de validações // 100 linhas de cálculo de descontos e impostos // 80 linhas de envio de email e salvamento no banco}Após a refatoração:
public void processInvoice(Invoice invoice) { validateInvoice(invoice); double total = calculateTotal(invoice); saveInvoice(invoice, total); sendConfirmationEmail(invoice);}
private void validateInvoice(Invoice invoice) { if (invoice.getCustomer() == null) throw new IllegalArgumentException(); if (invoice.getItems().isEmpty()) throw new IllegalStateException();}
private double calculateTotal(Invoice invoice) { // lógica de cálculo return invoice.getItems().stream() .mapToDouble(Item::getPrice) .sum();}
private void saveInvoice(Invoice invoice, double total) { // salvamento}
private void sendConfirma
```