I vecchi sistemi hanno due cose in comune: funzionano e rendono tutti nervosi. Funzionano perché anni di uso reale li hanno modellati attorno all'azienda effettiva. Rendono le persone nervose perché nessuno vuole toccarli, la documentazione è scarna e uno degli sviluppatori originali se n'è andato tre lavori fa.
Cosa conta davvero come "legacy"
Non ogni vecchio sistema è legacy. Un'applicazione di 10 anni che gira su uno stack supportato, ben testata, con manutenzione attiva, è semplicemente matura. Legacy tipicamente significa:
- Versioni di piattaforma o framework che non ricevono più aggiornamenti di sicurezza.
- Conoscenza concentrata in una o due persone.
- Paura di cambiare le cose perché piccole modifiche rompono funzionalità distanti.
- Deployment manuali, test manuali, tutto manuale.
- Un divario crescente tra ciò di cui l'azienda ha bisogno e ciò che il sistema può fare.
I due approcci fallimentari
- Non fare nulla. Il rischio si accumula. Alla fine qualcosa di critico si rompe in un brutto momento.
- Riscrivere da zero. Una riscrittura big-bang richiede quasi sempre più tempo del previsto, scopre requisiti nascosti troppo tardi e gira in parallelo con il vecchio sistema così a lungo che il team si arrende.
Gli approcci che funzionano davvero si collocano tra questi due estremi.
Strategia 1: Strangola il vecchio sistema
Mantieni in esecuzione il sistema legacy, ma instrada gradualmente le nuove funzionalità attraverso un nuovo livello. Col tempo, sempre più funzionalità vivono nel nuovo sistema; il vecchio si riduce finché non viene finalmente spento.
Questo funziona per i siti web (sposta pagina per pagina), gli strumenti interni (sposta modulo per modulo) e le integrazioni (introduci un nuovo gateway API, poi reindirizza i chiamanti ad esso).
Strategia 2: Modernizza sul posto
A volte l'architettura va bene, ma lo stack è troppo vecchio. In quel caso, aggiorna un livello alla volta: linguaggio/runtime, poi librerie, poi framework, poi deployment. Aggiungi test automatizzati man mano, così ogni passo è verificabile. Non glamour, ma molto efficace.
Strategia 3: Dividi, poi modernizza
I grandi sistemi monolitici sono spesso più facili da modernizzare pezzo per pezzo una volta che le giunture sono chiare. Significa prima definire i confini all'interno del sistema esistente (moduli, contesti delimitati), poi sostituire i moduli in modo indipendente. I confini contano più della scelta tecnologica.
Cosa fare prima di scrivere qualsiasi codice
- Scrivi cosa fa davvero il sistema oggi, non cosa avrebbe dovuto fare.
- Identifica le funzionalità su cui le persone fanno affidamento ogni giorno, quelle devono continuare a funzionare durante la transizione.
- Identifica le funzionalità morte, sono spesso una quota significativa del codice e dovrebbero essere ritirate in silenzio.
- Fai un inventario di dati, integrazioni, permessi ed esportazioni. È qui che i progetti di modernizzazione di solito incontrano problemi.
- Decidi cosa significa "fatto" in termini misurabili.
Controlli del rischio che fanno una vera differenza
- Backup e ripristini testati, prima di qualsiasi modifica.
- Test automatizzati per il comportamento che ti interessa, introdotti gradualmente.
- Feature flag così le modifiche possono essere annullate in produzione senza un deploy.
- Osservabilità, log, tracciamento degli errori, metriche aziendali chiave, così scopri rapidamente se qualcosa è regredito.
- Un rollout graduale: il nuovo codice gira prima per gli utenti interni, poi per una piccola percentuale di utenti reali, poi per tutti.
Pattern strangler fig. Invece di una rischiosa riscrittura big-bang, instradi il traffico attraverso una sottile facciata che inoltra gradualmente sempre più richieste a nuovi servizi, mentre il sistema legacy continua a gestire il resto finché non è vuoto.
Esempio: una rotta facciata minima
Un piccolo gateway può decidere per ogni rotta se una richiesta va al monolite legacy o al nuovo servizio. Scritto in modo neutro rispetto al framework:
app.use((req, res, next) => {
if (req.path.startsWith('/api/v2/invoices')) {
return proxy(req, res, NEW_SERVICE_URL);
}
return proxy(req, res, LEGACY_URL);
});
Ogni modulo migrato sposta un prefisso da LEGACY_URL a NEW_SERVICE_URL. Gli utenti non vedono mai un cutover big-bang; il team rilascia passi piccoli e reversibili.
Trappola comune: scrivere il nuovo sistema e il vecchio come se dovessero essere equivalenti per funzionalità dal primo giorno. Non è così. Inizia dal pezzo più piccolo che ha un reale valore aziendale, dimostra il percorso di migrazione, poi ripeti.
Errori comuni
- Far ruotare la modernizzazione attorno alla scelta tecnologica. Nuovi stack alla moda non aiutano se il modello dei dati e le integrazioni restano misteriosi.
- Aspettare un redesign completo prima di sistemare i problemi visibili. Gli utenti ne pagano il costo; lo slancio muore.
- Spegnere troppo presto il vecchio sistema. Esegui entrambi in parallelo abbastanza a lungo da fidarti del nuovo.
- Perdere la conoscenza istituzionale. Lavora in coppia con chi conosce il sistema. La loro conoscenza è la vera risorsa.
Una tempistica realistica
- Stabilizza: backup, monitoraggio, patch di sicurezza, test minimi.
- Mappa: documenta cosa esiste e cosa viene effettivamente usato.
- Prioritizza: scegli il pezzo che è doloroso ora e prezioso da modernizzare per primo.
- Sostituisci: costruisci la nuova versione di quel pezzo accanto al vecchio.
- Commuta: instrada il traffico, monitora, correggi i problemi.
- Ritira: dismetti il vecchio pezzo solo dopo che è rimasto tranquillo per un po'.
- Ripeti per il pezzo successivo.

