Refatoração de código legado em C#: técnicas e práticas avançadas

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: quando o código se torna legado

Todo desenvolvedor C# que trabalha em uma grande empresa, mais cedo ou mais tarde, se depara com projetos que têm 5, 10 ou até 15 anos. Esse código é chamado de legado. Ele funciona, gera dinheiro, mas cada alteração nele é um risco. Falta de testes, alto acoplamento (tight coupling), classes gigantescas com milhares de linhas, strings mágicas e código copiado e colado — essa é a realidade do legado.

Uma simples refatoração "de olho" não funciona aqui. São necessárias estratégias avançadas que permitam melhorar o código gradualmente, sem quebrar a lógica de negócios. Neste artigo, abordaremos 4 abordagens principais para refatorar sistemas legados em C# (.NET) em nível avançado.



1. Estratégia "Strangler Fig": substituição de módulos sem parar o sistema

O padrão Strangler Fig (figueira estranguladora) é um clássico para substituição gradual de componentes legados. A ideia: você não reescreve todo o sistema de uma vez, mas gradualmente intercepta as chamadas aos módulos antigos e as redireciona para os novos.



Como implementar em C#

A maneira mais simples é usar interfaces e fábricas. Suponha que você tenha uma classe antiga OldOrderProcessor, que é usada em todo o projeto.



// Interface antiga (já existe)public interface IOrderProcessor{    void Process(Order order);}

// Implementação antiga (legado)public class OldOrderProcessor : IOrderProcessor{ public void Process(Order order) { // Código que funciona há muitos anos, mas é bagunçado }}


Criamos uma nova implementação e uma fábrica com feature toggle:



public class NewOrderProcessor : IOrderProcessor{    public void Process(Order order)    {        // Código novo e limpo    }}

public class OrderProcessorFactory{ public IOrderProcessor Create() { // Exemplo: alterna conforme a configuração if (ConfigurationManager.AppSettings["UseNewProcessor"] == "true") return new NewOrderProcessor(); return new OldOrderProcessor(); }}


Agora você pode ativar o novo processador para 5% dos usuários, monitorar erros e aumentar gradualmente a porcentagem. Quando o código antigo não for mais necessário, remova-o.



2. Isolamento do núcleo: Separation of Concerns através de Dependency Injection

O código legado frequentemente sofre de God-classes (classes-deus) e dependência direta do banco de dados, sistema de arquivos, APIs externas. A introdução de Dependency Injection (DI) é o primeiro passo para a modularidade.



Exemplo prático

Imagine que você tem uma classe ReportGenerator que cria um SqlConnection internamente:



public class ReportGenerator{    public void Generate()    {        using (var conn = new SqlConnection("..."))        {            // consultas        }    }}


Isso é impossível de testar sem um banco de dados real. Refatoração:



public interface IDataRepository{    IEnumerable<DataRow> GetReportData();}

public class ReportGenerator{ private readonly IDataRepository _repository;

public ReportGenerator(IDataRepository repository) { _repository = repository; }

public void Generate() { var data = _repository.GetReportData(); // geração do relatório }}


Agora você pode substituir o repositório por um mock em testes de unidade. Use o contêiner DI padrão do .NET Core (Microsoft.Extensions.DependencyInjection) ou o Autofac para injeção de dependências.



3. Teste de código legado: Golden Master e Characterization Tests

Sem testes, refatorar é como pular de paraquedas sem reserva. Para código legado, a abordagem ideal são os Characterization Tests (testes de caracterização) ou Golden Master Testing.



Como funciona

Você executa

Blogs

Book Recommendations