Software · Soluções na Prática
Modernização de Sistemas Legados: Estratégias Práticas sem Reescrita Big Bang
Como substituir sistemas legados de forma incremental usando o padrão Strangler Fig, camadas anticorrupção (ACL) e Branch by Abstraction sem interromper a operação.
Neste artigo
A tentativa de modernizar sistemas corporativos legados por meio de uma reescrita completa e abrupta (conhecida como Big Bang Rewrite) figura historicamente entre os maiores causadores de prejuízos em engenharia de software. Interromper o lançamento de novas funcionalidades no negócio durante meses ou anos para reescrever uma aplicação do zero subestima a quantidade massiva de regras implícitas e casos especiais acumulados no código antigo. Na data agendada para a virada de chave, o novo sistema raramente contempla a complexidade real da operação e o projeto descamba para atrasos severos ou cancelamento.
A alternativa moderna comprovada pela indústria substitui a ruptura pelo estrangulamento incremental. Inspirada na metáfora botânica da figueira-estranguladora observada por Martin Fowler, essa abordagem constrói o novo sistema em torno do antigo, capturando fluxos aos poucos até que o legado possa ser desligado com segurança e sem impacto para os clientes.
A Arquitetura do Padrão Strangler Fig
O padrão Strangler Fig opera na camada de tráfego de rede e roteamento perimetral. Em vez de exigir que clientes externos aprendam novos contratos ou saibam da existência de múltiplos sistemas, um proxy reverso ou API Gateway é posicionado à frente da infraestrutura existente:
flowchart TD
Clientes["Clientes Web / Mobile / Integrações"]
Gateway["Proxy Reverso / API Gateway<br/>(Fachada Estranguladora)"]
Novo["NOVO SERVIÇO<br/>(Arquitetura Moderna)"]
Legado["SISTEMA LEGADO<br/>(Monólito / Banco Legado)"]
ACL["Anti-Corruption Layer (ACL)<br/>(Tradução e Sincronização)"]
Clientes --> Gateway
Gateway -->|"Rotas Novas Migradas"| Novo
Gateway -->|"Rotas Legadas Originais"| Legado
Novo <-->|"Tradução de Contratos"| ACL
Legado <-->|"Acesso a Dados Legados"| ACL
O Ciclo de Vida da Transição
- Interceptação Transparente: Todas as requisições passam pela Fachada Estranguladora (Strangler Facade), que inicialmente despacha 100% do tráfego para a aplicação legada.
- Criação da Nova Capacidade: Uma funcionalidade específica e bem delimitada (por exemplo, o cálculo de frete ou a autenticação de usuários) é desenvolvida do zero em uma arquitetura limpa, moderna e testável.
- Desvio Gradual de Tráfego: A regra de roteamento no gateway é alterada para encaminhar as chamadas daquela rota específica para o novo serviço, mantendo as demais rotas no legado.
- Descomissionamento Final: Conforme os módulos antigos perdem responsabilidades operacionais, o código legado atrofia gradualmente até transformar-se em uma casca vazia que pode ser desligada com risco controlado.
Protegendo o Domínio com a Anti-Corruption Layer (ACL)
Durante os meses em que o sistema novo e o sistema legado convivem em produção, o novo serviço inevitavelmente precisará consultar clientes, pedidos ou tabelas mantidas no armazenamento antigo. O maior perigo nesse período é permitir que as decisões arcaicas de modelagem do legado (nomes crípticos de colunas, chaves compostas despadronizadas ou regras misturadas) contaminem as classes do novo software.
A Anti-Corruption Layer (Camada Anticorrupção) atua como um tradutor bidirecional de fronteira entre os dois mundos:
// 1. Interface pura do novo domínio moderno
public interface IConsultaClienteLegacy
{
Task<ClienteModerno?> ObterClientePorDocumentoAsync(string cpf);
}
// 2. Implementação da ACL que isola as esquisitices do legado
public class LegacyClientAntiCorruptionLayer : IConsultaClienteLegacy
{
private readonly ILegacySoapClient _soapClient;
public LegacyClientAntiCorruptionLayer(ILegacySoapClient soapClient) => _soapClient = soapClient;
public async Task<ClienteModerno?> ObterClientePorDocumentoAsync(string cpf)
{
// Chama o endpoint SOAP legado com payloads antigos
var legacyDto = await _soapClient.BuscarRegistroClienteAsync(new LegacyParam { NR_DOC = cpf });
if (legacyDto == null || legacyDto.STATUS_FLG != "A") return null;
// Traduz e sanitiza os dados para a entidade moderna e rica
return new ClienteModerno(
id: Guid.Parse(legacyDto.CD_UUID),
nome: legacyDto.NM_RAZAO_SOCIAL.Trim(),
cpf: legacyDto.NR_DOC,
ativo: true
);
}
}
O novo serviço consome apenas a abstração limpa. Caso a estrutura do banco legado mude, apenas a classe da ACL é ajustada, preservando a higidez do novo modelo.
Modernização Interna: Branch by Abstraction
Quando o objetivo é substituir um módulo interno altamente acoplado dentro de um monólito sem a viabilidade imediata de separá-lo em um serviço de rede, aplica-se o padrão Branch by Abstraction:
- Uma interface abstrata é declarada em frente ao componente interno obsoleto.
- Todo o código do monólito é refatorado para consumir exclusivamente a interface abstrata.
- A nova implementação moderna é construída em paralelo satisfazendo a mesma interface.
- Um mecanismo de controle de funcionalidade (Feature Toggle) comuta a execução em tempo de execução para a nova implementação, permitindo testes graduais e reversão instantânea em caso de divergência.
public class RepositorioUsuarioProxy : IRepositorioUsuario
{
private readonly IRepositorioUsuario _legado;
private readonly IRepositorioUsuario _novo;
public RepositorioUsuarioProxy(RepositorioLegado legado, RepositorioNovo novo)
{
_legado = legado;
_novo = novo;
}
public async Task<Usuario> ObterAsync(int id)
{
// Alternância segura baseada em configuração ou porcentagem de usuários
if (FeatureManagement.HabilitarNovoMotorPersistencia)
{
return await _novo.ObterAsync(id);
}
return await _legado.ObterAsync(id);
}
}
Estratégias Práticas para Migração Strangler Fig
Em iniciativas de transformação arquitetural em grandes empresas, a modernização gradual costuma seguir um roteiro técnico bem delimitado:
- Começar pelas bordas: Nunca iniciar pela entidade central mais conectada do sistema. Iniciar por fluxos periféricos de baixo risco e alto valor (como relatórios ou notificações) para validar a esteira de entrega contínua e as regras do gateway.
- Sincronização passiva por eventos: Utilizar Change Data Capture (CDC) no banco legado para replicar dados em tempo real para os novos armazenamentos, permitindo testes comparativos (shadow traffic) sem risco de corrupção de dados.
- Transparência para a diretoria e usuários: Ao entregar melhorias funcionais a cada iteração quinzenal em vez de um hiato de dois anos, a liderança percebe retorno tangível sobre o investimento contínuo.