Topicos: Conceitos de Engenharia de Software
Publicado em 16/10/2026 por AdminModernizar um sistema legado é um dos desafios mais complexos da arquitetura de software. Muitas aplicações empresariais foram desenvolvidas há anos, utilizando tecnologias que já não acompanham as necessidades atuais do negócio. Apesar disso, continuam a ser fundamentais para operações como faturação, gestão de clientes, processamento de encomendas e integração com outros sistemas.
Nesses cenários, substituir toda a aplicação de uma só vez pode representar um risco elevado. Além dos custos de desenvolvimento, existem dependências desconhecidas, regras de negócio que nem sempre estão documentadas e a possibilidade de interrupções nos serviços.
É nesse contexto que o padrão Strangler Fig se destaca.
Em vez de substituir uma aplicação inteira num único projeto de migração, esta abordagem permite modernizar o sistema progressivamente, transferindo funcionalidades para novos componentes enquanto o sistema legado continua operacional.
Neste artigo, vamos explorar como funciona o padrão Strangler Fig, quais são as suas vantagens e limitações e como aplicá-lo na modernização de sistemas desenvolvidos com tecnologias como .NET, ASP.NET Core e SQL Server.
O Strangler Fig é um padrão arquitetural utilizado para modernizar sistemas existentes através da substituição gradual das suas funcionalidades por novas implementações.
O conceito foi popularizado por Martin Fowler, que utilizou a figueira-estranguladora como metáfora para explicar a substituição progressiva de uma estrutura existente por outra.
Na natureza, esta planta cresce em torno de uma árvore hospedeira e desenvolve gradualmente a sua própria estrutura. Com o tempo, pode tornar-se independente da árvore original.
Na arquitetura de software, a ideia é semelhante: construir novos componentes ao lado da aplicação existente e transferir progressivamente as suas responsabilidades até que o sistema legado deixe de ser necessário.
A principal diferença em relação a uma reescrita tradicional é que a modernização acontece por etapas, permitindo entregar melhorias sem esperar que toda a aplicação esteja concluída.
Segundo a documentação do Azure Architecture Center, o padrão permite migrar funcionalidades específicas para novas aplicações e serviços, mantendo o sistema antigo responsável pelas partes que ainda não foram substituídas.
A referência oficial pode ser consultada na documentação da Microsoft: https://learn.microsoft.com/pt-br/azure/architecture/patterns/strangler-fig
Antes de compreender a implementação do Strangler Fig, é importante perceber por que a substituição de sistemas antigos costuma ser um processo tão arriscado.
Imagine uma aplicação empresarial desenvolvida há mais de dez anos, utilizando ASP.NET MVC, .NET Framework e SQL Server.
Ao longo do tempo, essa aplicação recebeu novas funcionalidades, integrações e correções. Algumas regras de negócio foram implementadas diretamente no código, outras foram transferidas para stored procedures e determinadas integrações dependem de comportamentos que já não estão documentados.
Apesar de funcionar, o sistema apresenta problemas:
O custo de manutenção aumenta a cada alteração.
A arquitetura dificulta a introdução de novas funcionalidades.
As dependências entre módulos tornam as mudanças arriscadas.
A equipa tem dificuldade em atualizar bibliotecas e componentes.
Os testes automatizados não cobrem todas as regras de negócio.
A aplicação depende de tecnologias antigas ou difíceis de suportar.
A implementação de novas funcionalidades demora mais do que o esperado.
Perante esse cenário, uma possibilidade seria desenvolver uma nova aplicação e substituir a antiga quando tudo estivesse pronto.
O problema é que esse projeto pode demorar meses ou anos. Durante esse período, o negócio continua a precisar de novas funcionalidades e correções no sistema existente.
Além disso, reproduzir todo o comportamento de uma aplicação antiga pode ser mais difícil do que parece. Nem todas as regras estão documentadas, e algumas funcionalidades aparentemente simples podem depender de processos complexos.
O resultado de uma reescrita completa pode ser um projeto caro, demorado e com um risco significativo de introduzir regressões.
O Strangler Fig procura reduzir esse risco através de uma abordagem incremental.
O funcionamento do padrão baseia-se numa ideia simples: manter o sistema legado em funcionamento enquanto novas funcionalidades são desenvolvidas e disponibilizadas progressivamente.
Para isso, introduz-se uma camada de encaminhamento entre os clientes e os sistemas responsáveis por processar os pedidos.
Essa camada pode ser implementada através de um proxy, API Gateway, reverse proxy ou outro mecanismo de encaminhamento adequado à arquitetura.
Inicialmente, a maioria dos pedidos continua a ser encaminhada para a aplicação antiga.
À medida que novas funcionalidades ficam disponíveis, o encaminhamento é alterado para que os pedidos correspondentes sejam processados pelos novos componentes.
O processo repete-se até que todas as funcionalidades relevantes tenham sido migradas e o sistema legado possa ser desativado.
Podemos dividir essa estratégia em quatro etapas principais.
O primeiro passo consiste em criar uma camada que permita direcionar os pedidos para o sistema adequado.
Antes da mudança, a arquitetura pode ser representada desta forma:
Cliente → Sistema legado
Depois de introduzir o mecanismo de encaminhamento, temos:
Cliente → Camada de encaminhamento → Sistema legado
Nesta fase, a aplicação antiga continua a executar praticamente todas as operações. A diferença é que os pedidos passam por uma camada que permitirá controlar a migração.
Essa camada pode ser um API Gateway, um reverse proxy ou um componente específico da aplicação.
A escolha depende da arquitetura existente, dos protocolos utilizados, das necessidades de segurança e da granularidade do encaminhamento.
Por exemplo, numa aplicação empresarial com várias APIs, um gateway pode encaminhar pedidos para diferentes serviços com base no caminho, no domínio funcional ou noutras regras.
É importante que a camada de encaminhamento não se transforme num novo ponto único de falha sem mecanismos adequados de disponibilidade, monitorização e recuperação.
Com o encaminhamento preparado, o passo seguinte consiste em escolher uma funcionalidade para migrar.
O ideal é começar por um módulo que tenha valor para o negócio, limites relativamente claros e dependências que a equipa consiga compreender.
Imagine uma aplicação de gestão comercial que contém os seguintes módulos:
Clientes.
Produtos.
Encomendas.
Faturação.
Relatórios.
Em vez de reconstruir tudo, a equipa pode começar pelo módulo de consulta de produtos.
A funcionalidade é implementada numa nova API, utilizando uma arquitetura mais moderna, enquanto os restantes módulos continuam no sistema legado.
A camada de encaminhamento passa então a direcionar os pedidos de consulta de produtos para a nova API.
A arquitetura fica semelhante a esta:
Cliente → Camada de encaminhamento
Consulta de produtos → Nova API.
Clientes → Sistema legado.
Encomendas → Sistema legado.
Faturação → Sistema legado.
Relatórios → Sistema legado.
O sistema antigo continua a funcionar, mas já não é responsável por executar a funcionalidade migrada.
Esta abordagem permite validar a nova implementação num contexto real antes de avançar para módulos mais complexos.
Depois de migrar a primeira funcionalidade, a equipa pode continuar a modernizar outros módulos.
Por exemplo, após a consulta de produtos, pode migrar a gestão de clientes e, posteriormente, parte do processamento de encomendas.
A cada etapa, a camada de encaminhamento passa a enviar mais pedidos para os novos componentes.
O sistema legado vai perdendo responsabilidades até deixar de ser necessário.
No entanto, é importante perceber que migrar uma funcionalidade não significa apenas criar uma nova API.
Também pode ser necessário rever:
As regras de negócio.
A propriedade dos dados.
As integrações com outros sistemas.
Os mecanismos de autenticação e autorização.
O tratamento de erros.
A consistência das transações.
Os processos de auditoria.
Os testes funcionais e de regressão.
Uma migração bem-sucedida exige que a nova implementação reproduza o comportamento necessário para o negócio, sem transportar automaticamente todas as limitações da arquitetura antiga.
A etapa final acontece quando todas as funcionalidades relevantes foram migradas e as dependências restantes foram eliminadas ou substituídas.
Nesse momento, a camada de encaminhamento deixa de direcionar pedidos para a aplicação antiga.
Depois de confirmar que o sistema legado já não é necessário, a equipa pode removê-lo e simplificar a arquitetura.
Contudo, essa decisão deve ser baseada em evidências.
Antes de desativar o sistema antigo, é importante confirmar que:
Não existem clientes ou integrações a utilizar os seus endpoints.
Os dados necessários foram migrados e validados.
Os processos agendados foram substituídos.
Os mecanismos de auditoria e recuperação continuam a funcionar.
Não existem dependências operacionais esquecidas.
Os novos componentes cumprem os requisitos de disponibilidade e desempenho.
Os procedimentos de recuperação foram testados.
A desativação deve ser uma decisão planeada, e não apenas a consequência de a equipa acreditar que já terminou a migração.
Para perceber melhor como o padrão pode ser aplicado, vamos considerar um cenário comum em ambientes empresariais.
Uma empresa possui uma aplicação desenvolvida com ASP.NET MVC sobre .NET Framework, responsável por gerir clientes, produtos e encomendas.
A aplicação está em produção há vários anos e utiliza uma base de dados SQL Server partilhada com outros módulos.
A equipa pretende modernizar a solução, passando a desenvolver novas funcionalidades com ASP.NET Core.
Em vez de reconstruir toda a aplicação, decide adotar uma estratégia incremental.
A aplicação antiga concentra a maioria das responsabilidades.
Os utilizadores acedem à aplicação, que executa as regras de negócio e consulta ou atualiza a base de dados.
A arquitetura pode ser simplificada da seguinte forma:
Utilizador → Aplicação ASP.NET MVC (.NET Framework) → SQL Server
O primeiro objetivo não é substituir imediatamente a base de dados nem migrar todos os módulos.
A equipa começa por identificar as funcionalidades que podem ser separadas com menor risco.
A equipa decide migrar a consulta de produtos.
Para isso, desenvolve uma API com ASP.NET Core, responsável por disponibilizar essa funcionalidade.
A arquitetura passa a incluir dois sistemas:
Utilizador → Camada de encaminhamento
Funcionalidades antigas → Aplicação ASP.NET MVC.
Consulta de produtos → API ASP.NET Core.
Nesta fase, a nova API pode continuar a utilizar a base de dados existente, desde que o acesso seja controlado e compatível com as regras de negócio.
Isso permite modernizar a camada de aplicação sem introduzir imediatamente uma migração de dados adicional.
É importante, porém, evitar que os novos componentes passem a depender indiscriminadamente do esquema interno da aplicação antiga. Essa dependência pode dificultar a separação futura.
Depois de validar a consulta de produtos, a equipa pode começar a transferir as regras de negócio para a nova implementação.
Por exemplo, pode migrar a criação e atualização de produtos, incluindo as validações necessárias.
A migração deve considerar não apenas o código, mas também as regras existentes na base de dados, as permissões e as integrações envolvidas.
Se a aplicação antiga utiliza stored procedures para validar operações, será necessário compreender se essas regras devem permanecer, ser partilhadas temporariamente ou ser transferidas para a nova solução.
O objetivo é evitar que a mesma regra seja implementada de formas diferentes nos dois sistemas.
A modernização da aplicação não exige que a base de dados seja substituída logo no início.
Em muitos cenários, manter temporariamente o SQL Server existente reduz o número de alterações simultâneas.
No entanto, se o objetivo final incluir a separação dos dados por domínio, será necessário planear essa migração.
A equipa pode começar por identificar quais as tabelas, relações e operações pertencentes ao módulo de produtos.
Depois, deve avaliar se faz sentido manter o acesso à base de dados partilhada, criar uma nova base de dados ou migrar os dados em etapas.
Uma eventual migração deve considerar:
A transferência dos dados históricos.
A sincronização das alterações durante o período de transição.
A integridade referencial.
A prevenção de escritas concorrentes inconsistentes.
A validação dos resultados.
A estratégia de reversão.
O momento em que o sistema antigo deixa de aceder aos dados migrados.
Não existe uma única estratégia adequada a todos os cenários. A escolha depende dos requisitos de consistência, da dimensão dos dados e das dependências existentes.
Depois de migrar e estabilizar o módulo de produtos, a equipa pode aplicar a mesma abordagem aos clientes e às encomendas.
Ao longo do processo, a nova solução ganha responsabilidades e a aplicação antiga perde funcionalidades.
A modernização pode também permitir melhorar a cobertura de testes, estabelecer contratos mais claros entre componentes e introduzir mecanismos de observabilidade.
No final, a empresa terá substituído a aplicação antiga progressivamente, sem depender de uma única data de lançamento que concentre todo o risco.
O API Gateway é uma das opções para implementar a camada de encaminhamento utilizada pelo padrão Strangler Fig.
O gateway funciona como ponto de entrada para os pedidos e pode encaminhá-los para a aplicação antiga ou para os novos serviços.
Por exemplo, uma empresa pode definir regras semelhantes às seguintes:
/api/produtos/* → API ASP.NET Core.
/api/clientes/* → Aplicação legada.
/api/encomendas/* → Aplicação legada.
À medida que os módulos são migrados, as regras de encaminhamento são atualizadas.
Esta abordagem permite que os consumidores continuem a utilizar uma interface estável, mesmo quando a implementação interna muda.
Contudo, o API Gateway não é obrigatório.
Dependendo do cenário, o encaminhamento pode ser feito através de um reverse proxy, de um balanceador de carga, de um proxy específico ou de outra infraestrutura já existente.
A decisão deve considerar a topologia da aplicação, os protocolos, os requisitos de segurança e a capacidade de encaminhar pedidos com a granularidade necessária.
Também é importante evitar colocar no gateway regras de negócio que deveriam pertencer aos serviços. A sua responsabilidade principal é gerir o encaminhamento e as preocupações transversais que façam sentido para essa camada.
O padrão Strangler Fig é frequentemente associado à migração de monólitos para microsserviços, mas os dois conceitos não são equivalentes.
O Strangler Fig descreve uma estratégia de modernização incremental. Os microsserviços são uma possível arquitetura de destino.
Isso significa que uma aplicação pode utilizar o padrão Strangler Fig sem adotar microsserviços.
Por exemplo, uma empresa pode migrar uma aplicação ASP.NET MVC antiga para uma aplicação ASP.NET Core modular, mantendo uma única unidade de implantação.
A modernização pode trazer benefícios mesmo sem dividir a solução em dezenas de serviços independentes.
Da mesma forma, uma organização pode utilizar o padrão para separar determinados domínios em serviços independentes, quando essa separação fizer sentido para o negócio.
A decisão deve partir dos requisitos e dos limites funcionais, e não da ideia de que todos os sistemas modernos precisam de ser distribuídos.
Os microsserviços podem ser úteis quando existem domínios com responsabilidades bem definidas, necessidades de implantação independentes ou requisitos de escalabilidade diferentes.
No entanto, também introduzem complexidade operacional.
A equipa passa a lidar com comunicação entre serviços, observabilidade distribuída, tolerância a falhas, segurança entre componentes e consistência de dados em operações distribuídas.
Por isso, o Strangler Fig não deve ser utilizado como justificação automática para decompor uma aplicação em microsserviços.
O objetivo é modernizar o sistema com o menor risco razoável e uma evolução arquitetural sustentável.
A adoção deste padrão pode trazer benefícios importantes, especialmente em sistemas críticos que não podem ser substituídos de forma abrupta.
Numa reescrita tradicional, grande parte do risco concentra-se no momento em que a nova aplicação substitui a antiga.
Com o Strangler Fig, a migração acontece em etapas menores.
Cada funcionalidade pode ser implementada, testada e validada antes de a equipa avançar para a seguinte.
Isso não elimina os riscos, mas permite distribuí-los e gerir melhor os problemas encontrados.
Uma reescrita completa pode obrigar a empresa a esperar muito tempo antes de obter benefícios.
Com uma abordagem incremental, as primeiras funcionalidades modernizadas podem entrar em produção enquanto outras continuam a ser desenvolvidas.
Dessa forma, a organização pode começar a beneficiar das melhorias sem esperar pela conclusão de todo o projeto.
Como o sistema legado permanece disponível durante a transição, a empresa pode continuar a executar os processos que ainda não foram migrados.
Esse aspeto é particularmente importante em aplicações empresariais que suportam operações diárias críticas.
Ainda assim, a continuidade operacional depende de uma implementação correta, de testes adequados e de mecanismos de recuperação.
A modernização incremental permite rever prioridades com base no que a equipa aprende ao longo do projeto.
Se uma funcionalidade apresentar dependências inesperadas, pode ser necessário adiar a sua migração ou dividir o trabalho em etapas menores.
Essa flexibilidade é mais difícil de conseguir quando toda a substituição depende de um único lançamento.
Um sistema antigo pode conter funcionalidades que já não são utilizadas ou que deixaram de fazer sentido para o negócio.
Durante a modernização, a equipa tem a oportunidade de avaliar o que deve ser preservado, simplificado ou eliminado.
Isso evita reproduzir automaticamente comportamentos antigos que apenas aumentariam o custo e a complexidade da nova solução.
Apesar das vantagens, o padrão Strangler Fig não torna a modernização simples por definição.
Durante algum tempo, a organização terá de manter sistemas antigos e novos em funcionamento simultaneamente.
Essa coexistência exige planeamento, monitorização e uma estratégia clara para gerir dependências.
Durante a migração, podem existir duas implementações para partes diferentes do negócio.
A equipa precisa de compreender onde cada funcionalidade está implementada e como os pedidos são encaminhados.
Também pode ser necessário manter processos de integração e mecanismos de compatibilidade entre componentes.
Sem uma estratégia de transição bem definida, essa arquitetura temporária pode tornar-se difícil de gerir.
Se uma funcionalidade for implementada de forma independente no sistema antigo e no novo, existe o risco de as regras divergirem.
Por exemplo, a aplicação antiga pode calcular o preço de um produto de determinada forma, enquanto a nova API aplica regras ligeiramente diferentes.
Essa divergência pode provocar resultados inconsistentes.
A equipa deve identificar as regras de negócio relevantes, estabelecer contratos claros e testar os comportamentos que precisam de permanecer compatíveis.
A base de dados costuma ser um dos maiores desafios da modernização.
Mesmo depois de migrar a camada de aplicação, vários componentes podem continuar a depender das mesmas tabelas.
Se dois sistemas puderem alterar os mesmos dados sem coordenação, podem surgir problemas de consistência.
Por isso, é importante definir a propriedade dos dados, as permissões de escrita e a estratégia de migração antes de separar os componentes.
Nem sempre é evidente onde termina uma funcionalidade e começa outra.
Uma aplicação pode conter módulos que parecem independentes, mas partilham regras de negócio, transações ou dados.
Se a equipa escolher limites inadequados, pode acabar por criar integrações complexas e dependências adicionais.
O trabalho de descoberta arquitetural é essencial para identificar partes que possam ser migradas com segurança.
Uma camada de encaminhamento criada para apoiar a migração pode permanecer durante anos se o projeto não tiver critérios claros de conclusão.
O mesmo pode acontecer com integrações temporárias, acessos diretos à base de dados e mecanismos de compatibilidade.
Para evitar esse cenário, a equipa deve acompanhar o progresso da migração, documentar as dependências restantes e estabelecer condições objetivas para desativar os componentes antigos.
A implementação deve começar pela compreensão do sistema existente e dos objetivos da modernização.
Não é recomendável iniciar a migração apenas porque determinada tecnologia está desatualizada.
É necessário perceber quais os problemas que se pretende resolver e como medir o sucesso.
Uma abordagem prática pode seguir as etapas seguintes.
Antes de escolher tecnologias, identifique o que a organização pretende alcançar.
Alguns objetivos possíveis são:
Reduzir o custo de manutenção.
Diminuir o tempo necessário para entregar funcionalidades.
Melhorar a segurança e a capacidade de atualização.
Aumentar a disponibilidade.
Separar domínios que evoluem de forma independente.
Eliminar dependências de tecnologias sem suporte adequado.
Esses objetivos ajudam a definir prioridades e evitam que a modernização se transforme num exercício exclusivamente tecnológico.
Analise os módulos, as integrações, os dados e os processos que compõem o sistema.
É importante compreender quais as funcionalidades que dependem umas das outras e quais podem ser isoladas.
Em sistemas .NET, isso pode incluir a análise de projetos, bibliotecas partilhadas, chamadas entre módulos, stored procedures, jobs agendados e integrações externas.
O objetivo é construir uma visão suficientemente clara para identificar oportunidades de migração.
Escolha uma funcionalidade que ofereça valor e que possa ser migrada com um nível de risco controlável.
Evite começar necessariamente pelo módulo mais complexo ou pelo que possui maior número de dependências.
Uma primeira migração bem delimitada permite validar a abordagem técnica e operacional.
Implemente a camada responsável por direcionar os pedidos para o sistema adequado.
Defina como serão encaminhados os pedidos antigos e novos, como serão geridos os erros e como será possível reverter uma alteração de encaminhamento.
A estratégia deve incluir testes para confirmar que os pedidos chegam ao destino correto.
Desenvolva a nova implementação com contratos claros e testes adequados.
Quando necessário, compare os resultados produzidos pela nova implementação com os resultados do sistema antigo.
Essa comparação deve ser feita com cuidado para evitar duplicar operações com efeitos secundários, como emitir faturas, criar encomendas ou enviar notificações.
Quando a funcionalidade estiver validada, encaminhe os pedidos para a nova implementação de acordo com uma estratégia de lançamento controlado.
Dependendo da infraestrutura, pode ser possível começar com um conjunto limitado de utilizadores ou operações.
Acompanhe erros, latência, resultados funcionais e indicadores de negócio.
Se surgirem problemas, deve existir um procedimento claro para interromper a migração ou voltar temporariamente à implementação anterior.
Se o objetivo incluir a separação da base de dados, faça essa migração de forma planeada.
Identifique as dependências que ainda ligam a nova funcionalidade ao sistema antigo e defina como serão removidas.
A migração de dados deve incluir validação, controlo de consistência e procedimentos de recuperação.
Depois de confirmar que as funcionalidades foram migradas e que não existem dependências relevantes, planeie a desativação do código, dos endpoints e dos recursos antigos.
Não mantenha indefinidamente componentes que já não têm uma função operacional.
A conclusão do processo deve ser confirmada através de evidências, como métricas de utilização, análise de dependências e testes de aceitação.
Além das etapas anteriores, algumas práticas ajudam a reduzir os riscos durante a modernização.
Os testes de regressão são fundamentais para confirmar que as novas implementações mantêm os comportamentos necessários.
Em sistemas empresariais, isso inclui regras de negócio, validações, permissões e integrações.
Quando não existem testes suficientes, pode ser necessário começar por caracterizar o comportamento atual da aplicação antes de substituir funcionalidades críticas.
A equipa deve conseguir identificar para onde os pedidos são encaminhados e como cada implementação se comporta.
Logs estruturados, métricas e rastreamento distribuído podem ajudar a diagnosticar problemas que envolvem vários componentes.
Também é importante acompanhar indicadores funcionais, e não apenas métricas técnicas.
Uma API pode responder rapidamente e, ainda assim, produzir resultados incorretos.
Antes de transferir tráfego para um novo componente, defina como será possível recuperar de uma falha.
Alterar o encaminhamento pode ser relativamente simples, mas reverter alterações de dados pode ser muito mais complexo.
Por isso, o procedimento de reversão deve considerar o estado da aplicação, as operações já executadas e a compatibilidade entre os sistemas.
Modernizar a aplicação, mudar a base de dados, alterar os contratos das APIs e substituir a infraestrutura ao mesmo tempo pode aumentar significativamente a dificuldade de diagnóstico.
Sempre que possível, planeie as mudanças para que os problemas possam ser identificados e isolados com maior facilidade.
Isso não significa que todas as alterações tenham de acontecer separadamente, mas cada decisão deve ter uma justificação clara.
O número de serviços criados ou a quantidade de código migrado não são, por si só, indicadores suficientes de sucesso.
Acompanhe métricas relacionadas com os objetivos definidos inicialmente.
Por exemplo, pode medir o tempo necessário para entregar funcionalidades, a frequência de falhas, a duração das implementações e a quantidade de dependências antigas ainda existentes.
Essas métricas ajudam a perceber se a modernização está realmente a melhorar a capacidade de evolução do sistema.
Embora seja útil em muitos cenários, o Strangler Fig não é a melhor opção para todas as aplicações.
Se o sistema for pequeno, tiver poucas dependências e puder ser substituído com um esforço controlável, uma reescrita completa pode ser mais simples.
O padrão também pode ser inadequado quando não existe uma forma segura de intercetar ou encaminhar os pedidos para os componentes antigos e novos.
Outro cenário problemático ocorre quando a aplicação antiga não permite modificar os pontos de integração necessários e não existe uma alternativa viável para contornar essas limitações.
Além disso, se a organização precisar de desativar rapidamente o sistema original, a manutenção de duas implementações durante um período prolongado pode não ser compatível com os seus objetivos.
A decisão deve considerar o custo total da transição, a criticidade do sistema, a capacidade da equipa e os riscos operacionais.
A modernização incremental não é necessariamente mais barata em todos os cenários. Durante algum tempo, a organização terá de suportar a infraestrutura antiga e a nova, além dos mecanismos de integração entre ambas.
O benefício está na possibilidade de gerir a mudança por etapas e obter resultados progressivamente, quando essa flexibilidade compensa a complexidade adicional.
A escolha depende do contexto do sistema e dos objetivos da modernização.
Uma reescrita completa pode ser adequada quando a aplicação é relativamente simples, os requisitos estão bem definidos e a substituição pode ser realizada com um risco aceitável.
Uma migração direta, mantendo a arquitetura existente e alterando sobretudo a plataforma tecnológica, pode fazer sentido quando o objetivo principal é sair de uma tecnologia antiga sem redesenhar todo o sistema.
O Strangler Fig é particularmente interessante quando a aplicação é crítica, possui muitas dependências e precisa de continuar a evoluir durante a modernização.
A tabela seguinte resume as diferenças.
| Critério | Strangler Fig | Reescrita completa | Migração direta |
|---|---|---|---|
| Estratégia | Substituição gradual de funcionalidades | Reconstrução global | Transferência para outra plataforma ou ambiente |
| Entrega de valor | Pode acontecer durante a migração | Geralmente depende da disponibilização da nova solução | Depende do âmbito e da estratégia de migração |
| Risco | Distribuído por etapas, mas não eliminado | Pode concentrar-se na substituição final | Depende das alterações realizadas |
| Coexistência de sistemas | Normalmente necessária durante a transição | Pode existir durante testes e preparação | Depende do método de migração |
| Complexidade temporária | Pode ser elevada | Pode concentrar-se no desenvolvimento e no corte final | Varia conforme as dependências |
| Adequação | Sistemas críticos e complexos | Sistemas mais simples ou com requisitos bem delimitados | Cenários em que a arquitetura atual continua adequada |
Não existe uma estratégia universalmente superior.
O mais importante é selecionar uma abordagem que permita atingir os objetivos do negócio sem introduzir riscos desnecessários.
O padrão Strangler Fig oferece uma abordagem estruturada para modernizar sistemas legados sem exigir a substituição de toda a aplicação num único projeto.
Ao transferir funcionalidades progressivamente para novos componentes, as equipas podem reduzir a concentração de risco, entregar melhorias mais cedo e aprender com cada etapa da migração.
Em ambientes .NET, esta estratégia pode ser utilizada para modernizar aplicações desenvolvidas com ASP.NET MVC e .NET Framework, introduzindo novas APIs com ASP.NET Core e definindo gradualmente os limites entre os componentes antigos e os novos.
No entanto, o sucesso não depende apenas da tecnologia escolhida. É fundamental compreender as regras de negócio, controlar as dependências, definir uma estratégia de dados e acompanhar a migração com testes e métricas adequadas.
Também é importante evitar que a arquitetura temporária se torne permanente. A modernização deve ter objetivos claros e critérios que permitam identificar quando os componentes antigos podem ser removidos.
Em última análise, o Strangler Fig não é apenas uma forma de substituir código antigo. É uma estratégia para permitir que sistemas importantes evoluam de forma controlada, acompanhando as necessidades do negócio sem depender de uma mudança abrupta.
Para equipas responsáveis por aplicações empresariais complexas, pode ser uma alternativa valiosa à reescrita completa, desde que os benefícios da migração incremental justifiquem a complexidade adicional de manter sistemas antigos e novos em funcionamento durante a transição.