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.