Atualizando ferramentas legadas um passo de cada vez
TL;DR - Tínhamos runtimes velhos, frameworks velhos e um app Android preso num toolchain antigo. Não atualizei tudo de uma vez. Fiz uma lista, ordenei por risco e atualizei uma camada por vez, com a pipeline como rede de segurança. A IA fez boa parte do trabalho mecânico; os testes decidiram quando estava pronto.
Parte do legado não era o código em si. Era tudo em volta: o backend em Play Framework (que contei no post da migração para Spring Boot), versões antigas de runtime e de biblioteca, pacotes de frontend com vulnerabilidade conhecida, e um app Android que quebrou quando o coletor RFID de um cliente recebeu atualização de sistema. Nada estava pegando fogo, mas toda biblioteca nova que a gente queria pedia uma versão mais nova de alguma coisa.
O inventário
Comecei com uma tabela simples: cada projeto, o runtime, o framework, a ferramenta de build e o quanto cada um estava atrasado. Só escrever isso já mostrou a ordem. Primeiro o que tinha problema de segurança. Depois o que travava outros upgrades. Upgrade cosmético por último.
Uma camada por vez
A regra era nunca atualizar duas camadas no mesmo MR. Primeiro o runtime, com o mesmo framework. Depois o framework. Depois as bibliotecas. Quando algo quebra, sei qual mudança causou.
flowchart LR
Inv[Inventário] --> Sec[Correções de segurança]
Sec --> Runtime[Runtime: Java / Node]
Runtime --> Framework[Major do framework]
Framework --> Libs[Bibliotecas]
Libs --> Build[Imagens de build e CI]
O caso do Android
O app dos coletores foi o mais doloroso. Uma atualização no aparelho do cliente trouxe uma versão mais nova do Android, e o nosso setup antigo de Kotlin e Gradle começou a falhar. Aqui tive que ir além do planejado: Gradle mais novo, Kotlin mais novo, target SDK mais novo. Testei nos aparelhos reais que os clientes usam, não só no emulador, porque o leitor de hardware se comporta diferente.
Onde a IA ajudou
Upgrade é cheio de mudança mecânica: pacote renomeado, API depreciada, formato novo de configuração. Passei para a IA o guia de migração e os erros de compilação e deixei ela propor as mudanças, um módulo de cada vez. Foi rápido e quase sempre certo. Quando errou, os testes pegaram. Sem testes, eu não teria confiado isso a ela.
Pra não acontecer de novo
Depois do grande catch-up, coloquei uma checagem automática de dependências na pipeline e um horário fixo por mês para aplicar as atualizações menores. Atualização pequena todo mês sai barato. Um salto de três anos é um projeto.