Pillar page

Modernizzazione sistemi legacy

Refactoring incrementale da monolite a microservizi, migrazione da tecnologie obsolete verso stack moderni, migrazione al cloud — senza downtime di business, con piano di rollback e audit trail completo.

Ogni azienda ha qualche sistema legacy. Alcune ne hanno diversi. Un'applicazione contabile del 2008 che in qualche modo funziona ancora. Un CRM scritto da consulenti che nessuno ricorda più. Un magazzino in Access. Ognuno di essi dovrà essere prima o poi sostituito — la domanda non è se, ma quandocome.

La modernizzazione di sistemi legacy è uno dei tipi di progetto IT più difficili. Richiede di bilanciare tre forze: continuità di business (il sistema deve continuare a funzionare per tutto il tempo), introduzione di tecnologie moderne (microservizi, cloud, IA) e controllo del rischio (ogni refactoring può rompere qualcosa che ha funzionato per anni).

Perché non basta „riscrivere da zero"?

Dalla nostra esperienza, 9 modernizzazioni di successo su 10 sono refactoring incrementali, non riscritture. Le riscritture sono concettualmente allettanti („inizieremo con una pagina pulita"), ma in pratica hanno tre problemi fondamentali:

  • Logica di business invisibile. Il vecchio sistema contiene anni di regole di business — condizioni speciali per i clienti più grandi, esenzioni fiscali per settori specifici, workaround per regolamenti del 2015. La maggior parte non è documentata. Una riscrittura deve ricostruire tutto dalla memoria delle persone o dall'analisi del codice.
  • Lavoro duplicato. Mentre il nuovo sistema viene scritto, il business continua a richiedere modifiche a quello vecchio (regolamenti, nuovi clienti, piccoli bug). Il team o duplica il lavoro (modifiche in due posti), o congela il sistema vecchio (rischio di business).
  • Big bang deployment. Dopo un anno di lavoro, il nuovo sistema è „quasi pronto". Spostare tutti gli utenti in una notte genera un rischio enorme. Ogni problema imprevisto significa tornare al sistema vecchio, perdere il morale del team ed erodere la fiducia del business.

Il refactoring incrementale (di solito seguendo il pattern Strangler Fig) risolve tutti e tre: la logica di business viene scoperta gradualmente, una sola fonte di verità per ogni entità, deployment in fasi con feature flag.

Sei pattern di modernizzazione

Ognuno affronta un rischio specifico. Nella maggior parte dei progetti ne combiniamo diversi, scegliendo un pattern per modulo.

Strangler Fig

„Avvolgimento" graduale del vecchio sistema con nuovi componenti. Il codice vecchio gira ancora, ma ogni nuova feature va in un nuovo microservizio e i moduli esistenti vengono sostituiti uno per uno. Dopo 12-24 mesi il vecchio monolite viene spento.

Anti-corruption layer

Un adattatore che protegge il nuovo codice dalle stranezze del vecchio sistema (nomi di campo illeggibili, formati di data strani, tipi incoerenti). Tutta la logica „brutta" è isolata in un unico posto — il nuovo codice opera su un modello di dominio pulito.

Database refactoring

Pattern da Refactoring Databases (Ambler/Sadalage): expand-and-contract per le migrazioni di schema, validazione dei dati prima di rimuovere le vecchie colonne, esecuzione di entrambi gli schemi in parallelo durante la migrazione dell'applicazione.

Branch by abstraction

Introduzione di un livello di astrazione attorno al vecchio componente, implementazione del nuovo componente in parallelo, switch graduale del traffico dallo 0% al 100% (feature flag). Senza deploy „big bang".

Shadow mode

Il nuovo codice gira in parallelo con quello vecchio — entrambi processano le stesse richieste, ma solo i risultati del sistema vecchio raggiungono l'utente. I risultati vengono confrontati offline. Dopo aver confermato la compatibilità (tipicamente 2-4 settimane) spostiamo il traffico sul nuovo codice.

Event sourcing per la migrazione

Registriamo lo stream di eventi di business dal vecchio sistema e lo riproduciamo nel nuovo. Questo permette una validazione preliminare della nuova architettura senza rischio di produzione, e la capacità di tornare a qualsiasi stato storico.

Roadmap tipica di modernizzazione

Per un sistema di medie dimensioni (un monolite di ~200k righe di codice, 5-10 moduli di business):

  1. Mese 1: discovery e documentazione. Reverse engineering dell'architettura, mappatura delle dipendenze, identificazione dei flussi di dati, documentazione dei processi di business con l'aiuto degli stakeholder di business.
  2. Mese 2: architettura target e pilota. Progettazione della nuova architettura, scelta della tecnologia, pilota sul modulo più semplice (proof of concept). Prima validazione dell'approccio.
  3. Mesi 3-4: estrazione del primo modulo di produzione. Pattern Strangler Fig, shadow mode per 2-3 settimane, cutover del traffico, hypercare. Primo valore di business reale.
  4. Mesi 5-12: estrazione iterativa dei moduli successivi. Ognuno in un ciclo di 4-6 settimane: refactor → test → shadow → produzione → hypercare. Miglioramento continuo del processo, riduzione del tempo per modulo.
  5. Mesi 12-18: migrazione dei dati e decommissionamento del monolite. Una volta estratti tutti i moduli critici, finalizziamo la migrazione dei dati storici, spegniamo il vecchio sistema, archiviamo. Festeggiamo.

Sistema legacy vs. modernizzato

AspettoSistema legacy (tipico)Dopo la modernizzazione
Tempo per rilasciare una nuova feature4-8 settimane (alto rischio di regressione)3-7 giorni (test automatizzati minimizzano il rischio)
Copertura dei test5-15% (o nessuna)>80%, nella pipeline CI/CD
Disponibilità di sviluppatoriBassa (tecnologia obsoleta)Alta (stack popolari e moderni)
SicurezzaVecchie librerie con CVE non patchateScansione OWASP, gitleaks, aggiornamenti automatici
ScalabilitàVerticale (più risorse per il monolite)Orizzontale (scaling di microservizi specifici)
OsservabilitàLog in file, nessuna metricaPrometheus + Grafana + Sentry + SIEM
Compliance (GDPR, EU AI Act, ISO 27001)Impegnativa, costosa da dimostrareIntegrata nell'architettura, pronta per audit

Sei rischi tipici — e come li affrontiamo

Rischio: nessun test nel sistema legacy

Mitigazione: Per prima cosa costruiamo test di caratterizzazione (capture test) — registrando il comportamento attuale del sistema sulla base di log di produzione e cattura del traffico. Solo dopo iniziamo il refactoring, con i test come rete di sicurezza.

Rischio: conoscenza concentrata in una sola persona („truck factor 1")

Mitigazione: Il trasferimento di conoscenza inizia nella prima settimana di progetto. Tutti gli incontri con la persona che conosce il sistema vengono registrati e trascritti, i processi chiave documentati, le decisioni architetturali motivate. Dopo il progetto l'intero team comprende il sistema.

Rischio: rallentamento temporaneo del team

Mitigazione: Per i primi 2-3 mesi il team mantiene il vecchio sistema + costruisce il nuovo. Rallentamento naturale della velocità di cambiamento. Lo mitighiamo: dando priorità alle modifiche che vanno solo nel nuovo sistema, congelando le modifiche a bassa priorità nel codice vecchio.

Rischio: migrazione dei dati

Mitigazione: Ogni migrazione di dati ha tre fasi: dry-run (su una copia di produzione), staging (in ambiente di test con dati a scala reale), produzione (in finestra di servizio o incrementalmente). Piano di rollback pronto prima dell'avvio.

Rischio: resistenza organizzativa

Mitigazione: Comunicazione con il business fin dal primo giorno: perché modernizziamo, cosa cambia per l'utente, qual è il calendario, come misuriamo il successo. La prima iterazione viene scelta per mostrare rapidamente valore tangibile (es. una nuova UI o un report più veloce).

Rischio: sottostima dei costi

Mitigazione: Discovery (1-2 settimane) prima del pricing del progetto. Iterazioni di 2-3 settimane con consegne concrete — più facile correggere la rotta che in un lungo progetto „tutto in una volta". Budget con un buffer del 20-30% per gli imprevisti.

Domande frequenti

Cos'è un sistema legacy?
Un sistema legacy è software che gira ancora nell'organizzazione ma si basa su tecnologie obsolete, ha un debito tecnico profondo, manca di test, manca di documentazione o manca dello sviluppatore che l'ha scritto. Esempi classici: un'applicazione monolitica PHP 5.x o .NET Framework 4.0, un database senza migrazioni, un frontend in jQuery, deploy via FTP. Funziona, ma ogni modifica è ad alto rischio e ad alto costo.
Perché modernizzare se il sistema funziona?
Tre motivi principali. Primo: il costo di manutenzione cresce esponenzialmente con l'età del sistema — sempre meno sviluppatori conoscono la tecnologia, ogni modifica richiede più tempo, ogni bug ha un raggio d'impatto più ampio. Secondo: rischio di sicurezza — i vecchi framework hanno vulnerabilità non patchate, niente supporto del vendor, non conformità con GDPR/ISO 27001. Terzo: blocco della crescita di business — i nuovi requisiti (mobile, API, integrazioni, IA) sono difficili o impossibili da aggiungere.
Non è più facile riscrivere tutto da zero?
Il classico dilemma „rewrite vs. refactor". Le riscritture sono concettualmente allettanti, ma in pratica durano 2-3 volte più del previsto, il progetto affonda sotto il peso della ricostruzione della logica di business invisibile, e nel frattempo il vecchio sistema deve essere ancora sviluppato (lavoro duplicato). Dalla nostra esperienza: 9 modernizzazioni di successo su 10 sono refactoring incrementali (pattern Strangler Fig) — sostituire gradualmente pezzi del vecchio sistema preservando la continuità di business. Una riscrittura ha senso solo per sistemi molto piccoli.
La modernizzazione richiede downtime di business?
Nella maggior parte dei progetti, no. Usiamo pattern che permettono di scambiare componenti „in diretta": blue-green deployment, feature flag, dark launch, esecuzione in parallelo di codice vecchio e nuovo con confronto dei risultati (shadow mode). Brevi finestre di servizio possono essere necessarie per migrazioni di database con cambi di schema significativi, ma le pianifichiamo in anticipo (tipicamente di notte, nel weekend) con un piano di rollback completo.
Quanto dura una modernizzazione tipica?
Dipende dalla scala. Un singolo modulo monolite estratto come microservizio: 1-2 mesi. Una modernizzazione più ampia (5-10 moduli, nuovo database, nuova API): 6-12 mesi in iterazioni di 2-3 settimane. Una trasformazione completa di un monolite enterprise: 18-36 mesi, ma il valore di business appare dopo la prima iterazione — ogni modulo estratto fornisce immediatamente benefici (modifiche più rapide, rischio inferiore, miglior osservabilità).
Da quali tecnologie migriamo più spesso?
I percorsi più comuni: PHP 5/7 → PHP 8 o Python (FastAPI) o Node.js (Express/Fastify). .NET Framework 4.x → .NET 8 o Java/Spring Boot. Java EE (JBoss/WebSphere) → Spring Boot o Quarkus. jQuery + template monolitici → React/Vue/Astro. Oracle DB → PostgreSQL (significativi risparmi di licenza). On-premise → cloud (AWS, Azure, GCP, cloud privato locale).
E le integrazioni esistenti con altri sistemi?
Ogni integrazione esistente viene mappata nella fase di discovery. Il piano di migrazione copre: preservazione dei contratti esistenti (i client interni ed esterni non notano cambiamenti), introduzione del versionamento (v1 contratto vecchio, v2 nuovo), migrazione graduale dei consumatori a v2, poi ritiro di v1. Piena compatibilità all'indietro durante la migrazione.
Come riducete il rischio di business?
Cinque livelli: 1) incrementalità — sostituiamo un modulo alla volta, non tutto insieme; 2) test di caratterizzazione — prima del refactoring catturiamo il comportamento attuale del sistema (capture test), che poi verificano che nulla si sia rotto; 3) feature flag — la nuova funzionalità viene rilasciata gradualmente (1% utenti → 10% → 50% → 100%); 4) piano di rollback per ogni deploy (<5 min); 5) hypercare dopo il rilascio (monitoring intensivo 2-4 settimane).
E la documentazione del sistema che non esiste?
Un problema comune nel legacy. Prima fase del progetto: reverse engineering della documentazione. Gli agenti IA analizzano il codice, lo schema del database, i log di produzione e generano: diagramma dell'architettura, lista degli endpoint, mappa delle dipendenze, descrizioni dei processi di business. Questa documentazione viene poi verificata con le persone di business (il processo è come l'abbiamo capito dal codice). Risultato: documentazione completa prima dell'inizio del refactoring, utile non solo per il progetto di modernizzazione ma anche per il team di prodotto.
Come si confrontano i costi di modernizzazione con quelli di manutenzione del vecchio sistema?
Nel breve termine, la modernizzazione è più costosa della manutenzione (investimento nel refactoring + manutenzione del vecchio sistema in parallelo). Il punto di break-even (dove il nuovo sistema diventa più economico da mantenere del vecchio) si verifica tipicamente dopo 12-18 mesi. Dopo di che il nuovo sistema: costa meno da mantenere (meno sviluppatori, più automazione), permette cambiamenti più rapidi (time-to-market più breve), riduce il rischio (miglior osservabilità, più test, fallimenti isolati).

Iniziamo con un audit

Un audit tecnico di una settimana: mappatura dello stato attuale, identificazione delle aree di modernizzazione più urgenti, un piano in fasi con risultati di business concreti nella prima iterazione.