La modernizzazione più costosa è la riscrittura che non finisce mai. I sistemi maturi contengono anni di regole di business documentate solo nel codice. Per questo modernizziamo in modo incrementale: ogni passo è abbastanza piccolo da poter essere testato, rilasciato e annullato, e l'attività aziendale prosegue senza interruzioni.

Aggiornamenti di Java e Spring senza sorprese

Passare da Java 8 o 11 a 17, 21 o 25, e da Spring Boot 2 a 3 e 4, non significa solo cambiare un numero di versione: c'è il passaggio dal namespace javax a jakarta, la configurazione di Spring Security, le API rimosse, i default modificati e le librerie di terze parti che potrebbero non essersi adeguate. Il supporto open source di Spring Boot 3.5 è terminato a metà 2026, quindi molti team devono ora affrontare due salti di versione maggiore insieme. Mappiamo prima tutti gli ostacoli, pianifichiamo l'ordine degli aggiornamenti e automatizziamo la parte meccanica con ricette OpenRewrite dove sono affidabili. Le decisioni che richiedono giudizio restano agli ingegneri.

Da Java EE a Jakarta EE, Spring o Quarkus

Molte applicazioni girano ancora su application server Java EE datati. A volte la scelta giusta è un runtime Jakarta EE moderno, altre volte Spring Boot o Quarkus. Analizziamo che cosa usa davvero l'applicazione (transazioni, messaggistica, sicurezza, interfacce remote) e scegliamo la destinazione con il rischio e il costo di lungo periodo più bassi, non quella di moda.

Aggiornamenti di Hibernate e del livello di persistenza

Hibernate 6 e 7 hanno cambiato il motore delle query, il sistema dei tipi e diversi default. Query che funzionavano da anni possono restituire risultati diversi o generare SQL molto diverso. Confrontiamo l'SQL prima e dopo, copriamo le query critiche con test su un database reale e correggiamo i mapping in modo consapevole, invece di silenziare i warning.

Ridurre il debito tecnico dove costa di più

Non tutto il debito tecnico merita attenzione. Guardiamo dove si incontrano frequenza delle modifiche e complessità: i moduli che il vostro team tocca ogni settimana e teme ogni volta. In quei punti eliminare dipendenze inutilizzate e codice morto, chiarire i confini tra moduli e aggiungere test si ripaga in fretta. Il debito nel codice stabile, che nessuno modifica, spesso può aspettare.

Scomposizione incrementale

Quando un monolite è diventato un collo di bottiglia, la risposta raramente è dividerlo in decine di servizi tutti insieme. Di solito partiamo trasformandolo in un monolite modulare ben strutturato, poi estraiamo servizi solo dove rilascio o scalabilità indipendenti lo giustificano, con il pattern strangler fig e livelli anti-corruzione, così che vecchio e nuovo possano funzionare fianco a fianco.

Gestire il rischio di regressione

Ogni passo della modernizzazione è protetto: test di caratterizzazione che fissano il comportamento attuale, esecuzioni in parallelo che confrontano i risultati vecchi e nuovi, feature flag, rilasci canary e un piano di rollback concordato prima di ogni rilascio. La stabilità della produzione è il vincolo su cui si misura ogni decisione.