Para modernizar uma aplicação legada, comece por escrever porque tem de mudar e depois avalie o código e a produção em conjunto. Estabilize o sistema e cubra com testes o comportamento de que o negócio depende antes de mexer na estrutura. Com essa rede de segurança, substitua o sistema parte a parte, migre os dados de forma planeada e reserve a reescrita completa para o caso raro em que pouco vale a pena manter.
Identificar a razão de negócio antes de tocar no código
A modernização é cara, por isso comece pela razão. As mais comuns são um runtime ou uma framework em fim de vida, alterações que levam semanas porque cada versão estraga alguma coisa, um sistema que só uma pessoa compreende, ou uma plataforma que não suporta aquilo de que o negócio vai precisar a seguir. Cada razão aponta para um primeiro passo diferente.
Escreva a razão com uma medida que possa verificar mais tarde, como a frequência das entregas em produção, o número de incidentes ou o tempo que uma alteração típica demora a chegar aos utilizadores. Sem isso, a modernização torna-se um projeto de engenharia sem fim à vista, difícil de defender na próxima revisão orçamental.
Avaliar o código e a produção antes de decidir seja o que for
Uma avaliação mostra o que realmente existe. Deve ser curta e terminar com um relatório escrito e um primeiro passo recomendado. Leia o código, mas leia também a produção: registos, incidentes, consultas lentas e a forma como as entregas são feitas. Os piores problemas estão muitas vezes à volta do código e não dentro dele.
- Versões do runtime, da framework e das bibliotecas, e quais já não recebem correções de segurança
- Que partes mudam com mais frequência e quais avariam com mais frequência, segundo o histórico de versões e o registo de incidentes
- Cobertura de testes nos percursos de que o negócio depende
- Como a aplicação é compilada, configurada e colocada em produção, e quem sabe fazê-lo
- O modelo de dados, a sua dimensão e que outros sistemas leem ou escrevem na mesma base de dados
- As pessoas que conhecem o sistema, e o que só elas sabem
Estabilizar primeiro a produção, para que o trabalho assente numa base firme
Se o sistema falha todas as semanas, a modernização vai ser interrompida todas as semanas. Corrija primeiro o que provoca incidentes: acrescente monitorização e alertas nos percursos críticos, automatize a compilação e o deploy para que as entregas sejam repetíveis, e tire do código os segredos e a configuração.
Estes passos compensam de imediato e tornam cada passo seguinte mais seguro. Mostram também, desde cedo, se a equipa consegue alterar o sistema sem o estragar, o que convém saber antes de se comprometer com um plano maior.
Criar uma rede de testes à volta do comportamento de que o negócio depende
O código legado tem normalmente poucos testes, e o comportamento documentado raramente corresponde ao real. Antes de alterar a estrutura, escreva testes de caracterização: testes que registam o que o sistema faz hoje, incluindo os seus casos-limite estranhos, para que qualquer mudança de comportamento apareça como um teste falhado.
Comece pelas extremidades, com testes que chamam a aplicação através da sua API ou da interface de utilizador e verificam os resultados, porque sobrevivem às alterações internas. Para cálculos e relatórios, faça passar entradas reais pelo código antigo e pelo novo e compare as saídas. Acrescente testes mais finos a cada parte à medida que a refatoriza. O nosso artigo sobre a atualização de uma aplicação Java 8 crítica mostra a mesma rede de segurança aplicada a uma atualização de runtime.
Substituir o sistema parte a parte em vez de o reescrever
Uma reescrita completa parece limpa no papel, mas o sistema antigo continua a funcionar e a mudar enquanto o novo o tenta alcançar, e cada comportamento não documentado tem de ser redescoberto pelo caminho. É por isso que as reescritas demoram tantas vezes mais do que o previsto, enquanto o negócio espera.
A alternativa habitual é o padrão strangler fig (figueira estranguladora). Coloque uma camada de encaminhamento, como um reverse proxy ou um API gateway, à frente da aplicação legada. Construa uma capacidade de cada vez no código novo e encaminhe para ele o tráfego dessa capacidade quando estiver comprovada. O sistema antigo vai encolhendo até poder ser desligado, e o negócio ganha valor a cada passo.
Uma reescrita pode ainda ser a decisão certa: quando a base de código é pequena e o seu comportamento bem compreendido, ou quando a plataforma em que corre não pode ser mantida viva tempo suficiente para uma substituição gradual. Decida com critérios escritos, e não por frustração.
Tratar os dados como uma migração à parte
O código pode ser substituído por fatias; os dados são mais difíceis de dividir. Enquanto o código legado e o novo partilham uma base de dados, cada alteração de esquema tem de ser coordenada. Decida cedo que sistema é a fonte de verdade para cada tipo de dados, e evite que dois sistemas escrevam no mesmo registo sem uma regra que diga qual das escritas prevalece.
Quando uma capacidade muda de sistema, mova ou sincronize os seus dados de forma planeada: scripts de migração testados sobre uma cópia da produção, ou sincronização contínua enquanto os dois sistemas funcionam. Planeie como vai reconciliar os dois, por exemplo com contagens diárias e checksums, e mantenha a possibilidade de voltar atrás até os números baterem certo.
Ordenar o trabalho por risco e valor, e mostrar progresso cedo
Ordene o trabalho de forma a que cada passo reduza o risco ou entregue algo que o negócio consiga ver. Uma sequência habitual é estabilizar e automatizar, acrescentar testes, atualizar o runtime e depois extrair as capacidades que mudam com mais frequência. As partes estáveis e raramente alteradas podem esperar, por vezes indefinidamente.
Mantenha o plano curto e reveja-o depois de cada passo, porque o que se aprende vai mudar a ordem. Os nossos engenheiros trabalharam assim em sistemas críticos. Através da Sopra Steria, lideraram a migração de Java 8 para 16 de uma aplicação crítica de trading diário de gás, e, como parte da equipa do programa cloud do Crédit Agricole, avaliámos cada aplicação que migrámos para decidir se devia ser atualizada ou reconstruída. Se pretende uma avaliação do seu sistema, ou uma equipa para executar o plano, a SDK Enterprises faz as duas coisas ao abrigo de um único contrato.
Pontos essenciais
- Escrever a razão de negócio para modernizar, com uma medida que se possa verificar mais tarde.
- Avaliar o código e a produção em conjunto antes de escolher entre atualização, substituição gradual e reescrita.
- Estabilizar a produção e cobrir o comportamento crítico com testes de caracterização antes de mexer na estrutura.
- Substituir o sistema parte a parte atrás de uma camada de encaminhamento, a menos que uma reescrita seja claramente mais pequena e mais segura.
- Planear a propriedade, a sincronização e a reconciliação dos dados como uma migração à parte.
Perguntas frequentes
Devemos reescrever de raiz a nossa aplicação legada?
Normalmente, não. Uma reescrita compete com um sistema que continua a mudar e tem de redescobrir comportamentos que ninguém documentou. Substitua-o gradualmente, a menos que a base de código seja pequena e bem compreendida, ou esteja presa a uma plataforma que não pode continuar a funcionar.
Quanto tempo demora modernizar uma aplicação legada?
Depende da dimensão do sistema, da cobertura de testes, do grau de emaranhamento dos dados e do que tem de mudar. Uma avaliação curta dá um plano realista e um primeiro passo suficientemente pequeno para ser concluído e medido, em vez de uma única data para todo o esforço.
É possível continuar a lançar funcionalidades durante a modernização?
Sim, e é o que se deve fazer. A substituição gradual permite à equipa entregar funcionalidades no código novo enquanto o sistema legado continua a funcionar. Combine que parte do tempo da equipa vai para a modernização, para que o trabalho em funcionalidades não a absorva sem se dar por isso.