Strangler Fig pattern: guida per modernizzare il legacy
Matteo Migliore

Matteo Migliore è un imprenditore e architetto software con oltre 27 anni di esperienza nello sviluppo di soluzioni basate su .NET e nell'evoluzione di architetture applicative per imprese e organizzazioni di alto profilo.

Ha guidato progetti enterprise, formato centinaia di sviluppatori e aiutato aziende di ogni dimensione a semplificare la complessità trasformando il software in guadagni per il business.

Un distributore di materiale elettrico di Padova, novanta dipendenti, 38 milioni di fatturato, ha un gestionale scritto tra il 2009 e il 2011 in ASP.NET Web Forms su .NET Framework 4.8. Sono 380.000 righe, 40 moduli e un database SQL Server con 410 tabelle. Lo mantengono cinque persone, tra interni ed esterni, e ogni modifica costa quasi il doppio di quanto costerebbe su un'applicazione moderna.

Il direttore generale ha due preventivi sul tavolo. Il primo propone di riscrivere tutto da zero in 24 mesi. Il secondo propone di non toccare niente "finché regge". Nessuno dei due gli piace, e ha ragione: sono le due strade più rischiose che esistano, solo che una rischia subito e l'altra rischia dopo.

Esiste una terza strada, e ha un nome: Strangler Fig pattern. Si mette una facciata davanti al sistema vecchio, si costruisce il nuovo accanto al vecchio un pezzo alla volta, e ogni pezzo che funziona prende il posto di quello che sostituisce. Il vecchio non viene spento: viene soffocato, come fa il ficus con l'albero che lo ospita.

In questo articolo trovi come funziona, quanto costa in euro nei cinque anni, e il numero che decide da dove cominciare: la quota di modifiche che cade nel 20% dei moduli. Trovi anche la facciata in codice, il nodo dei dati, il test che dice se un pezzo è pronto e i casi in cui il pattern non conviene.

Una premessa onesta. Dal 1999 modernizzo sistemi che sono in produzione da quindici anni, e ho costruito e venduto un gestionale legale multi-tenant. Il caso di Padova è composto, non è di un cliente reale, ma i numeri sono ordini di grandezza che ho visto più volte. Le ipotesi sono scritte, e puoi sostituirle con le tue.

Che cos'è lo Strangler Fig pattern?

Il nome lo ha dato Martin Fowler nel 2004, ispirandosi ai ficus strangolatori delle foreste australiane. Il seme germoglia sui rami alti di un albero, manda radici verso il suolo e cresce attorno al tronco. Dopo qualche decennio l'albero ospite è morto e il ficus sta in piedi da solo, con la stessa forma.

Nel software la metafora è precisa. Il sistema vecchio resta in produzione per tutto il tempo. Il sistema nuovo cresce intorno, funzione dopo funzione. A un certo punto il vecchio non serve più a niente e si spegne senza che nessuno se ne accorga.

Il pattern ha tre mosse, sempre le stesse.

  1. Mettere una facciata. Un punto d'ingresso unico davanti al sistema vecchio, che per ora inoltra tutto com'è. Gli utenti non vedono nessuna differenza.
  2. Costruire un pezzo nuovo e deviare il traffico. Si riscrive una funzione, la si mette in produzione dietro la facciata e si cambia la regola: quella richiesta ora va al nuovo.
  3. Spegnere il pezzo vecchio. Quando il nuovo ha lavorato abbastanza a lungo senza sorprese, il codice vecchio di quella funzione si cancella. Si ripete con la funzione successiva.

Sembra ovvio, ed è questo il motivo per cui funziona. Ogni passo è piccolo, si può annullare in un minuto e porta valore subito. Una riscrittura completa fa l'opposto: non porta niente per due anni e poi chiede un salto nel buio in una notte di sabato.

Il pattern non è una tecnologia. Si fa con un reverse proxy, con un'applicazione web, con un servizio, e si fa anche dentro un programma desktop con un po' più di fatica. Quello che conta è che esista un punto in cui si può decidere, richiesta per richiesta, chi risponde.

Perché la riscrittura da zero non è la risposta?

Quando un sistema è vecchio e doloroso, l'idea di rifarlo da capo ha un fascino fortissimo. Le ragioni per cui di solito va male sono quattro, e le ho viste tutte.

Il vecchio contiene regole che nessuno ricorda. In quindici anni il codice ha assorbito centinaia di casi particolari: il cliente che paga a 75 giorni, lo sconto che non vale sui cavi, l'arrotondamento che il commercialista pretende alla terza cifra. Nessuno li ha scritti in un documento. Stanno nel codice, e la riscrittura li perde finché un cliente non protesta.

Il vecchio continua a cambiare. Mentre il team scrive il nuovo, il business chiede modifiche al vecchio. O si congelano le modifiche per due anni, e l'azienda se ne accorge, oppure si scrivono due volte.

Il valore arriva alla fine. Per 18 o 24 mesi si spende e non si consegna niente. Se il progetto si ferma al ventesimo mese, per un cambio di budget o un cambio di direttore, si è buttato tutto.

Il salto è unico. Il giorno del rilascio si sposta ogni utente, ogni dato e ogni integrazione in un colpo. Il piano di rientro, se c'è, riporta indietro un sistema che nel frattempo ha scritto dati nuovi.

DomandaRiscrittura da zeroStrangler Fig
Quando arriva il primo valore?Alla fine, dopo 18 - 24 mesiDopo 3 - 4 mesi, con il primo modulo
Che cosa succede alle modifiche richieste?Congelate o scritte due volteSi fanno nel nuovo, per i moduli già migrati
Quanto si perde se il budget si ferma?Quasi tuttoNiente: i moduli migrati restano in produzione
Quanto è grande il rilascio?Un salto unicoUn modulo alla volta, annullabile
Chi scopre le regole nascoste?Gli utenti, dopo il rilascioI test sul vecchio, prima della sostituzione
Quanto costa se tutto va bene?Meno, perché si evita la facciata e la convivenzaDi più: nel caso di Padova il 16%

Nell'ultima riga c'è un fatto che chi vende questo pattern non dice sempre: se la riscrittura va bene, costa meno. Non devi costruire la facciata, non devi far convivere due sistemi, non devi mantenere due versioni dei dati. Il punto è la probabilità che vada bene, e quanto costa quando non va. Lo misuriamo più sotto, con i numeri.

Quanto costa il legacy se non si fa niente?

Prima di confrontare le strade bisogna dare un prezzo allo stato attuale, perché "non fare niente" non è gratis. Costa tutti i mesi, e il conto è quello che quasi nessuno scrive. Il metodo completo è nella guida al costo del software legacy. Qui ne uso la forma più corta.

Per l'azienda di Padova le ipotesi sono quattro.

  • Modifiche richieste ogni anno: 600 giornate, misurate a velocità "normale", cioè a quanto costerebbero su un'applicazione moderna e ben testata.
  • Moltiplicatore del legacy: 1,8. Ogni modifica sul vecchio costa l'80% in più, per tempo di orientamento, rischio di regressione e collaudi manuali. È l'ipotesi più discutibile, e più sotto la faccio variare.
  • Tariffa media: 450 euro a giornata, tra interni ed esterni.
  • Infrastruttura: 18.000 euro l'anno per i server Windows, le licenze e il backup del sistema vecchio, 9.000 per un'infrastruttura moderna equivalente.

Il costo annuale del sistema com'è oggi:

600 giornate × 1,8 × 450 euro = 486.000 euro, più 18.000 di infrastruttura, cioè 504.000 euro l'anno. In cinque anni sono 2.520.000 euro.

Il numero fa effetto, ed è giusto che lo faccia. Ma attenzione a non leggerlo come "buttiamo 2,5 milioni": una parte di quella spesa è il costo normale di cambiare il software, e comparirebbe anche con un sistema nuovo. Quello che il sistema nuovo toglie è la differenza tra 1,8 e 1,0, cioè 216.000 euro l'anno di attrito puro, più 9.000 di infrastruttura.

Un sistema legacy non costa perché è vecchio. Costa perché ogni modifica paga una tassa dell'80%, e la paga ogni volta.

Qual è il numero che decide da dove cominciare?

Se la tassa si paga sulle modifiche, la domanda diventa dove cadono le modifiche. Il sistema ha 40 moduli, ma le richieste non sono distribuite in modo uniforme. Quasi mai lo sono.

Il numero che decide è questo: la quota delle modifiche degli ultimi dodici mesi che cade nel 20% dei moduli. Ordini i moduli per numero di interventi, prendi il primo quinto, e guardi quanta parte del totale è lì dentro.

A Padova l'ho misurata così. Dodici mesi di storico, 1.240 interventi tra correzioni e richieste di modifica, ciascuno attribuito a un modulo. Gli otto moduli più toccati, il 20% di quaranta, ricevono 880 interventi: il 71%.

Interventi in dodici mesi sui 40 moduli del gestionale: gli otto più toccati ricevono 880 interventi su 1.240, il 71%

Questo numero serve a tre decisioni.

  • Se conviene. Sopra il 50% il pattern ripaga in fretta, perché basta migrare pochi moduli per togliere la maggior parte della tassa. Sotto il 32%, nel mio modello, non ripaga nemmeno in cinque anni: il dolore è sparso ovunque e conviene un altro metodo.
  • Da dove si parte. Si parte dai moduli dove cadono le modifiche, non da quelli più facili e non da quelli più brutti. Più sotto spiego perché partire dai facili costa 88.658 euro in più, a parità di traguardo.
  • Dove ci si ferma. Dopo gli otto moduli caldi il vecchio può restare in vita per altri anni, a costo basso, con i trenta moduli quasi fermi. Fermarsi è una scelta legittima, e il pattern è l'unico che la permette.

Come si misura in un pomeriggio

Se il codice sta in Git e le cartelle corrispondono ai moduli, basta una riga sullo storico. Questa conta i file toccati dai commit degli ultimi dodici mesi, per cartella di primo livello sotto src:

git log --since="12 months ago" --name-only --pretty=format: -- src \
  | awk -F/ 'NF>2 {print $2}' \
  | sort | uniq -c | sort -rn | head -20

È una misura grezza: conta file e non interventi, e un commit grande pesa come uno piccolo. Per una decisione da centinaia di migliaia di euro va raffinata con il registro dei ticket, che dice quali richieste erano correzioni e quali erano funzioni nuove. Ma l'ordine dei moduli cambia di rado. Se il primo quinto della classifica contiene più della metà dei tocchi, hai già la risposta.

Un avvertimento. Lo storico dice dove si è modificato, non dove si vorrebbe modificare. Se un modulo è così fragile che nessuno osa toccarlo, comparirà in fondo alla classifica per paura e non per stabilità. Chiedi al team quali sono i moduli "che nessuno tocca volentieri": spesso sono i primi da sostituire, e lo storico non li mostra.

Quanto costa farlo davvero, in cinque anni?

Metto in fila cinque strade sullo stesso caso e sullo stesso orizzonte. Le ipotesi comuni sono quelle sopra. Quelle specifiche sono otto.

  1. Migrazione totale: 1.100 giornate per tutti i 40 moduli.
  2. Moduli caldi: gli otto moduli con il 71% delle modifiche costano 480 giornate, 60 ciascuno, perché sono i più grandi. I trentadue restanti ne costano 620, circa 19 ciascuno.
  3. Facciata: 40 giornate, fatte nel primo anno.
  4. Costo del nuovo: una modifica sul nuovo costa 1,0 e non 1,8.
  5. Anno 1: le modifiche costano ancora come prima, perché il primo modulo arriva in produzione a fine anno.
  6. Riscrittura da zero: 1.650 giornate, cioè il 50% in più della migrazione modulo per modulo, perché non si riusa niente. Due anni di lavoro, durante i quali si fa solo il 25% delle modifiche richieste. Venti mila euro di affiancamento nel secondo anno.
  7. Rischio della riscrittura: la probabilità che si fermi prima del traguardo è del 30%. È un'opinione di mestiere, e la discuto sotto.
  8. Valore delle modifiche congelate: 450 euro per ciascuna giornata non fatta, cioè solo il costo di sviluppo e non il beneficio che portavano. È una stima prudente.

Ecco i totali a cinque anni, in euro.

StradaAnno 1Anno 2Anno 3Anno 4Anno 5Totale
Non fare niente504.000504.000504.000504.000504.0002.520.000
Strangler, moduli caldi e poi il resto742.500499.140467.820279.000279.0002.267.460
Strangler, solo i moduli caldi742.500359.640359.640359.640359.6402.181.060
Strangler, moduli facili per primi742.500558.245497.373279.000279.0002.356.118
Riscrittura, se va tutto bene515.250535.250279.000279.000279.0001.887.500
Riscrittura, con blocco e rischio1.887.500 + 405.000 di modifiche congelate + 222.750 di rischio atteso2.515.250
Costo in cinque anni: non fare niente 2.520.000 euro, Strangler sui moduli caldi 2.181.060, Strangler con il resto 2.267.460, Strangler partendo dai facili 2.356.118, riscrittura 1.887.500 se va bene e 2.515.250 con blocco e rischio

Leggo la tabella con te, perché dice cose meno ovvie di quelle che si aspetta chi cerca una risposta unica.

La riscrittura, se va tutto bene, vince. 1.887.500 euro contro 2.181.060: 293.560 euro in meno. Lo dico apertamente perché chi consiglia lo Strangler Fig senza ammetterlo vende. Se hai la certezza che la riscrittura riesce nei tempi, in cinque anni costa meno.

La riscrittura con il blocco e il rischio non vince più. Ai 1.887.500 si aggiungono 405.000 euro di modifiche che per due anni non hai fatto, e 222.750 euro di rischio atteso, cioè il 30% di probabilità di perdere i 742.500 euro spesi. Il totale supera quello di non fare niente. Il rischio e il blocco sono quello che separa il preventivo dalla realtà.

Strangler sui soli moduli caldi fa risparmiare 338.940 euro rispetto a non fare niente. Il primo anno costa più di tutti, 238.500 euro in più, perché si paga la migrazione e si continua a pagare il vecchio. Dal secondo anno ogni anno risparmia 144.360 euro. Il pareggio arriva intorno al trentaduesimo mese.

Partire dai moduli facili costa 88.658 euro in più. Il traguardo è lo stesso, tutti i moduli migrati, ma la strada "facili per primi" arriva a 2.356.118 euro e quella "caldi e poi il resto" a 2.267.460. I moduli facili tolgono solo la loro quota di tassa, e la quota è bassa perché nessuno li tocca. Il sollievo arriva tardi. Il team, che si aspettava miglioramenti subito, si demoralizza al secondo anno.

La riga che non puoi saltare è l'ultima: il pattern non è il più economico in assoluto, è il più economico di cui puoi fidarti. Costa il 16% in più della riscrittura perfetta (2.181.060 euro contro 1.887.500) e il 13% in meno di quella con blocco e rischio (contro 2.515.250), e non richiede di credere in nessuna previsione.

Il modello in codice

Il calcolo sta in poche righe, e conviene averlo in forma eseguibile per cambiare le ipotesi con quelle della tua azienda. Questo è il cuore, quello che stima il costo delle modifiche in un anno data la quota già spostata sul nuovo:

record Ipotesi(double Tariffa, int GiornateModifiche, double MoltiplicatoreLegacy);

static double CostoModifiche(Ipotesi h, double quotaSulNuovo) =>
    h.GiornateModifiche * h.Tariffa *
    (quotaSulNuovo * 1.0 + (1 - quotaSulNuovo) * h.MoltiplicatoreLegacy);

var padova = new Ipotesi(450, 600, 1.8);
Console.WriteLine(CostoModifiche(padova, 0.0));  // 486000, tutto sul vecchio
Console.WriteLine(CostoModifiche(padova, 0.71)); // 332640, il 71% sul nuovo

Il resto del modello è una somma per anno: costo delle modifiche, giornate di migrazione per la tariffa, infrastruttura vecchia e nuova. Non serve altro. Se in una riunione qualcuno obietta che il moltiplicatore è troppo alto, si cambia il numero e si guarda il totale. È una discussione che finalmente ha un oggetto.

Quanto sono fragili questi numeri?

Molto, e meglio saperlo. Le due ipotesi che muovono tutto sono la concentrazione delle modifiche e il moltiplicatore del legacy. Le ho fatte variare una alla volta, sulla strada "solo i moduli caldi", e ho tenuto fermo il resto.

Quota di modifiche nel 20% dei moduliRisparmio in cinque anni rispetto a non fare nienteLettura
30%- 15.300 euroCosta più di non fare niente
45%114.300 euroRipaga poco, rischio alto
60%243.900 euroRipaga, va bene
71%338.940 euroIl caso di Padova
85%459.900 euroRipaga in modo netto
Moltiplicatore del legacyCosto annuale di non fare nienteRisparmio in cinque anni
1,2342.000 euro- 121.140 euro
1,4396.000 euro32.220 euro
1,8504.000 euro338.940 euro
2,2612.000 euro645.660 euro

Due soglie, chiare. Sotto una concentrazione del 32% il pattern non ripaga, perché non c'è un posto dove la tassa si concentra. Sotto un moltiplicatore di 1,4 non ripaga lo stesso, perché la tassa è troppo bassa per giustificare la migrazione. Se il tuo legacy è abbastanza sano da costare solo il 20% in più, probabilmente va lasciato dov'è e curato.

Il moltiplicatore è il numero più difficile da misurare. Il modo che uso è mettere a confronto le stime del team con i tempi reali su due o tre interventi dello stesso tipo, uno sul vecchio e uno su un'applicazione recente della stessa azienda. Se manca il confronto, chiedo di contare le ore passate a capire il codice prima di scrivere la prima riga. Spesso sono più della metà.

Come si costruisce la facciata?

La facciata è l'unico pezzo che si scrive subito. È un reverse proxy davanti al sistema vecchio, e per un'applicazione web in .NET la scelta più semplice è YARP, il reverse proxy di Microsoft, che è una libreria dentro un'applicazione ASP.NET Core normale. Quaranta giornate per metterla in produzione sono un'ipotesi prudente: la parte tecnica ne richiede molte meno, il resto è per i test, i certificati e il monitoraggio.

Il primo giorno la facciata deve fare una cosa sola: inoltrare tutto al vecchio. Le due regole di instradamento sono queste, nel file appsettings.json:

{
  "ReverseProxy": {
    "Routes": {
      "ordini-nuovo": {
        "ClusterId": "nuovo",
        "Order": 1,
        "Match": { "Path": "/ordini/{**resto}" }
      },
      "tutto-il-resto": {
        "ClusterId": "legacy",
        "Order": 100,
        "Match": { "Path": "{**resto}" }
      }
    },
    "Clusters": {
      "nuovo":  { "Destinations": { "d1": { "Address": "http://nuovo.interno:8080/" } } },
      "legacy": { "Destinations": { "d1": { "Address": "http://legacy.interno/" } } }
    }
  }
}

E il programma che la fa partire è di quattro righe:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));

var app = builder.Build();
app.MapReverseProxy();
app.Run();

La regola con Order più basso vince. Quando il modulo ordini è pronto si accende la prima, e tutto il traffico che comincia con /ordini va al nuovo. Per tornare indietro si toglie la riga e si riavvia la facciata: un minuto, senza rilasciare il vecchio.

La facciata davanti al sistema vecchio: all'inizio inoltra tutto al legacy, dopo il primo modulo il percorso ordini va al nuovo, alla fine il legacy resta vuoto e si spegne

Tre modi di accendere un modulo senza paura

Spostare tutti gli utenti insieme è proprio il tipo di salto che il pattern vuole evitare. Per questo l'accensione di un modulo ha tre gradini, e ciascuno si può annullare.

  • Primo gradino: solo il team. Una regola in più sulla facciata, che abbina un'intestazione HTTP o un cookie e manda al nuovo solo chi lo porta. Il team usa il modulo nuovo per qualche giorno sul lavoro vero, con i dati veri.
  • Secondo gradino: un gruppo pilota. Una filiale, un reparto, cinque utenti che accettano di lavorare per due settimane sul nuovo. Hanno un numero di telefono da chiamare, e il rientro sul vecchio è immediato.
  • Terzo gradino: tutti, con il vecchio acceso. Il percorso passa al nuovo per tutti, ma il codice vecchio resta in produzione per un altro mese. Se succede qualcosa di imprevisto, si rimette la regola di prima.

Solo dopo un mese senza ritorni si cancella il codice del vecchio. Quel giorno, e non prima, il modulo è davvero sostituito. Il costo di tenere due versioni accese per un mese è piccolo, e vale la tranquillità.

Qual è il vero problema: i dati?

Chi ha già provato dice che la parte difficile non è il codice, è il database. Ha ragione. La facciata instrada richieste, ma i dati sono uno solo, e due applicazioni che scrivono sulle stesse tabelle senza una regola producono dati corrotti nel giro di una settimana.

Le strade possibili sono tre, in ordine di difficoltà.

Database condiviso, con un solo scrittore per tabella

È la strada che consiglio per cominciare, ed è quella usata a Padova. Il vecchio e il nuovo leggono e scrivono sullo stesso database, ma ogni tabella ha un solo proprietario. Quando il modulo ordini passa al nuovo, anche le tabelle degli ordini passano al nuovo come scrittore. Il vecchio le legge soltanto, e se ha bisogno di modificarle chiama il nuovo.

La regola si fa rispettare con i permessi del database: l'utente del vecchio perde il diritto di scrittura su quelle tabelle il giorno dell'accensione. Se una funzione dimenticata tenta di scrivere, fallisce subito e rumorosamente, e non in silenzio dopo tre mesi.

Strato di traduzione tra i due mondi

Il vecchio schema ha nomi, tipi e convenzioni che nel nuovo non si vorrebbero portare dietro: colonne di testo che contengono numeri, date salvate come stringhe, uno stato dell'ordine codificato con tre lettere. Si mette uno strato anti-corruzione nel nuovo, che traduce dal modello vecchio a un modello pulito e viceversa. Il resto del nuovo non vede mai lo schema vecchio.

È un pezzo di codice noioso e prezioso. Ha un solo compito, e quando il vecchio sarà spento si cancella insieme a lui.

Database separati e replica

Il nuovo ha il suo database, e i dati passano per una replica o per eventi. È la strada più pulita e la più costosa, e serve quasi solo quando lo schema vecchio è davvero intoccabile oppure il nuovo deve girare in un altro ambiente, per esempio sul cloud. La finestra in cui i due database possono divergere è la parte più rischiosa dell'intero progetto, e per cominciare non la consiglio.

Il criterio è semplice: la strada più semplice che mantiene un solo scrittore per ogni dato. Se due moduli devono scrivere sulla stessa tabella e non si riesce a separarli, sono lo stesso modulo e si migrano insieme.

Accesso e sessione

Il secondo nodo è l'utente. Chi ha fatto il login sul vecchio non deve rifarlo per aprire una pagina servita dal nuovo. Per le applicazioni ASP.NET su .NET Framework esiste una libreria di Microsoft, System.Web Adapters, pensata per la migrazione incrementale: permette al nuovo di riusare l'autenticazione e, se serve, anche la sessione del vecchio, chiamandolo per sapere chi è l'utente.

Se il sistema vecchio è su un'altra tecnologia, la soluzione è meno elegante e più sicura: il login resta nel vecchio fino all'ultimo modulo, la facciata aggiunge un'intestazione firmata con l'identità dell'utente, e il nuovo si fida soltanto di richieste che arrivano dalla facciata. Nel nuovo non si riscrive la password finché non si migra il login, che è quasi sempre l'ultimo modulo.

Come si sceglie il primo modulo?

Il numero della concentrazione dice dove cadono le modifiche. Non basta, perché un modulo caldo può essere anche il più intrecciato col resto, e allora il primo pezzo diventa una battaglia. Uso una griglia con quattro criteri, ciascuno da 1 a 5.

CriterioDomandaPunteggio alto significa
ConcentrazioneQuante delle modifiche degli ultimi dodici mesi cadono qui?Molte, quindi tanto da guadagnare
ConfiniQuanti altri moduli lo chiamano o ne scrivono i dati?Pochi, quindi si stacca bene
TestEsistono modi per verificare che il comportamento sia lo stesso?Sì, quindi il rischio è misurabile
VisibilitàGli utenti si accorgono se funziona meglio?Sì, quindi la fiducia cresce in fretta

Il primo modulo non è quello che ha il punteggio massimo in concentrazione. È quello che ha il punteggio totale più alto, con la concentrazione che pesa il doppio. Un primo pezzo con confini nitidi, test possibili e un buon vantaggio visibile compra la fiducia di cui il progetto avrà bisogno nei trenta mesi seguenti.

A Padova il primo modulo è stato Preventivi: settimo per interventi con 48 su 1.240, quindi non il più caldo. Ma era staccato dal resto, aveva regole di calcolo documentate e i commerciali erano felici di avere una pagina che non si bloccava. Ha chiuso in 14 settimane. Il secondo è stato Ordini, il più toccato, con 214 interventi: è costato 118 giornate, e in sei mesi ha tolto da solo il 17% della tassa.

Che cosa lasciare per ultimo

Ci sono tre tipi di moduli che conviene toccare per ultimi, anche se sono caldi.

  • Il motore di calcolo centrale. Prezzi, provvigioni, contabilità. Ha più regole nascoste di tutto il resto, e conviene averlo circondato di test prima di riscriverlo. Quando arriva il suo turno il team ha già un anno di mestiere sul sistema.
  • Il login. Tutti i moduli dipendono da lui. Si sposta dopo che il resto è migrato, perché prima sposterebbe il problema dell'accesso su ogni modulo nuovo.
  • Le integrazioni con terzi rigide. Il collegamento con la banca, con il corriere, con la fatturazione elettronica. Se il terzo non cambia, il codice vecchio che lo parla può restare in vita per anni senza fare danni.

Come si capisce che un pezzo nuovo è pronto?

Il rischio vero del pattern è sostituire un pezzo vecchio con uno nuovo che si comporta in modo diverso, senza che nessuno se ne accorga finché non è tardi. Tre difese, in ordine.

Test di caratterizzazione sul vecchio

Prima di scrivere il nuovo, si scrivono test sul vecchio che registrano quello che fa, non quello che dovrebbe fare. È la tecnica che Michael Feathers descrive in Working Effectively with Legacy Code: si danno input reali, si salva l'output attuale e quel risultato diventa la specifica. Se il vecchio calcola uno sconto in un modo bizzarro, il test lo registra, e il nuovo dovrà fare lo stesso oppure la differenza dovrà essere decisa dal business.

Servono anche pochi casi scelti a mano, quelli dei clienti con le regole strane. Una trentina di casi con i dati veri, anonimizzati, valgono più di mille test generati.

Confronto in parallelo

Per le richieste di sola lettura si può far rispondere il nuovo in ombra: la facciata inoltra la richiesta al vecchio, che risponde all'utente, e in parallelo la manda al nuovo, scartando la risposta ma confrontandola con l'altra. Le differenze finiscono in un registro. Dopo due settimane sai quante risposte divergono, su quali percorsi e con quale tipo di differenza.

La regola di uscita che uso è una soglia: sotto lo 0,1% di divergenze non spiegate il modulo può passare al gruppo pilota. Ogni divergenza spiegata, per esempio un arrotondamento sbagliato nel vecchio che il nuovo corregge, si archivia come decisione.

Il minuto del rientro

Prima di accendere un modulo, il team lo spegne di proposito, in un ambiente di prova, e controlla che il rientro funzioni: la regola di instradamento si toglie, il vecchio risponde, i dati scritti nel frattempo restano coerenti. Un rientro mai provato è una promessa, non un piano. Il test si fa una volta per modulo, dura mezz'ora e ha salvato più progetti di qualunque altra pratica.

I gradini per accendere un modulo: test di caratterizzazione, confronto in ombra sotto lo 0,1% di divergenze, solo il team, gruppo pilota, tutti con il vecchio acceso per un mese, cancellazione del codice vecchio

Quanto dura e chi serve?

Per un sistema come quello di Padova il calendario realistico ha quattro fasi.

FaseDurataChe cosa succede
Misura2 - 3 settimaneMappa dei moduli, concentrazione delle modifiche, moltiplicatore, dipendenze e costo di ogni modulo
Facciata e primo modulo3 - 4 mesiReverse proxy in produzione, test di caratterizzazione, primo modulo piccolo acceso con i tre gradini
Moduli caldi9 - 14 mesiGli otto moduli con il 71% delle modifiche, uno ogni 6 - 8 settimane in media
Coda e spegnimento12 - 18 mesi, a sceltaI trentadue moduli quasi fermi, il login, le integrazioni, lo spegnimento del vecchio

I numeri di costo per modulo che uso come punto di partenza sono questi, in giornate: un modulo piccolo e staccato 8 - 15, uno medio con qualche dipendenza 25 - 45, un modulo centrale 60 - 120. Per ogni modulo aggiungo il 15% per la convivenza, cioè strato di traduzione, test di caratterizzazione e confronto in ombra.

Il team minimo è di tre persone. Un architetto o responsabile tecnico che decide l'ordine dei moduli, tiene i confini e dice di no ai ritorni sul vecchio. Due sviluppatori che scrivono il nuovo. Servono anche, a tempo parziale, una persona del business che conosce le regole e collauda, e qualcuno del vecchio team che sa dove sono le trappole.

Se lo si fa con un team interno, il rischio più comune è che il team resti l'unico a manutenere il vecchio mentre scrive il nuovo, e lavori al doppio. Va ridotto il carico sul vecchio, o si assume. Se lo si fa con un fornitore, valgono le regole della guida su come decidere tra tenere, portare e riscrivere: repository nell'account del cliente, subentro misurato, pagamento a fasi.

Quali errori fanno fallire un progetto Strangler?

Ne ho visti sette ricorrere, e quasi sempre sono errori di metodo e non di tecnologia.

  1. Cominciare dai moduli facili. Il team ottiene risultati rapidi e inutili. Il direttore guarda i numeri a fine anno e non vede il risparmio, perché i moduli facili non toccano la tassa.
  2. Non mettere una scadenza al vecchio. I moduli migrati vengono lasciati accesi "per sicurezza", il codice vecchio non si cancella mai e si finisce a mantenere due sistemi. Ogni modulo ha una data di cancellazione scritta, di solito trenta giorni dopo l'accensione.
  3. Due scrittori sulla stessa tabella. Funziona per tre settimane e poi i dati divergono, nel modo che nessun test aveva previsto. È l'errore che costa di più, e si evita con i permessi del database.
  4. Riscrivere "meglio" mentre si migra. Si approfitta del passaggio per cambiare le regole, aggiungere funzioni, ridisegnare le schermate. Il confronto con il vecchio diventa impossibile. Prima si sposta uguale, poi si migliora.
  5. La facciata troppo intelligente. Il proxy comincia ad avere logica di business, trasformazioni, cache speciali. Diventa il nuovo monolite. Deve solo instradare, e al massimo autenticare.
  6. Niente metriche. Nessuno sa che cosa guadagna ogni modulo spostato. La quota di modifiche sul nuovo, il tempo medio per modifica e il numero di regressioni vanno guardati ogni mese, con il valore di partenza scritto prima di cominciare.
  7. Il solo architetto sa come funziona. Se la persona che regge il disegno se ne va, il pattern degenera in una pila di servizi senza senso. Le decisioni vanno scritte, una pagina per modulo.

Quando lo Strangler Fig non conviene?

Ci sono quattro situazioni in cui consiglio un'altra strada, e dirlo fa parte del mestiere.

  • Le modifiche sono sparse. Se nessun gruppo di moduli supera il 32% delle modifiche, non c'è dove concentrare lo sforzo. Il dolore è nell'architettura e non nei moduli, e serve un altro intervento: spesso un riordino del database o l'introduzione di test, più che una migrazione.
  • Il sistema è piccolo. Sotto le 30.000 righe e una dozzina di moduli, la facciata e la convivenza costano più della riscrittura. Si rifà, con test di caratterizzazione per non perdere le regole.
  • Non c'è una cucitura. Un programma desktop monolitico, per esempio in Windows Forms o in VB6, non ha un punto in cui inserire una facciata. Non è impossibile: si può ospitare il nuovo dentro il vecchio con controlli web o con un servizio locale, come descrivo nel caso del sistema SCADA in VB6. Ma è un altro mestiere, più lento.
  • Il moltiplicatore è basso. Se il tuo legacy costa solo il 20 - 30% in più di un sistema moderno, la migrazione non ripaga. Si cura, si aggiungono test e si lascia dov'è.

Per i casi con un'interfaccia da portare sul web, la guida a Blazor e la migrazione aziendale dice quando passare da Web Forms e da WPF, e quella su Razor Pages, MVC e Blazor aiuta a scegliere la tecnologia dei moduli nuovi. Se invece il nuovo deve servire più clienti con la stessa installazione, serve prima la guida all'architettura multi-tenant in .NET.

Che cosa si fa nei primi trenta giorni?

Un piano che puoi cominciare lunedì, senza chiedere un budget grande.

  • Settimana 1: la mappa. Elenca i moduli, dai a ciascuno un responsabile e un conteggio degli interventi degli ultimi dodici mesi. Calcola la quota del primo quinto. Se è sotto il 32%, fermati e rivedi la strada.
  • Settimana 2: il prezzo dell'attrito. Stima il moltiplicatore con tre interventi confrontabili. Scrivi le ipotesi del modello e fai calcolare il costo annuale di non fare niente. Metti il numero davanti a chi decide il budget.
  • Settimana 3: i confini. Per gli otto moduli più caldi, disegna chi li chiama e quali tabelle scrivono. Assegna a ogni tabella un solo proprietario futuro. Dai il punteggio con la griglia a quattro criteri.
  • Settimana 4: il primo modulo e il budget. Scegli il primo modulo, stima le giornate e la facciata, e chiedi il budget per i primi quattro mesi soltanto. Non per i trenta.

Alla fine del mese hai tre cose che prima non avevi: un numero di concentrazione, un costo annuale dell'attrito e un primo passo piccolo e annullabile. Con queste tre, la riunione con la direzione cambia argomento: non si discute più se modernizzare, ma da dove si comincia e quanto si è disposti a spendere per i primi quattro mesi.

Che cosa sarebbe successo a Padova?

Torno al distributore di materiale elettrico. Il direttore generale aveva due preventivi, il rifacimento da zero e l'attesa. Nessuno gli aveva detto che c'era un numero da misurare prima di scegliere.

Con il conto in mano avrebbe visto che non fare niente costava 504.000 euro l'anno, e che il 71% delle modifiche cadeva in otto moduli su quaranta. Avrebbe visto che la riscrittura, se andava bene, costava 293.560 euro meno dell'altra strada, e che con il blocco delle modifiche e il rischio di fermarsi costava quanto non fare niente.

Avrebbe scelto di cominciare con 234.000 euro, la facciata più gli otto moduli caldi, con un pareggio al trentaduesimo mese e la possibilità di fermarsi in qualsiasi momento. Non è la strada più economica in assoluto. È la sola in cui, a ogni passo, può dire basta senza aver perso tutto.

Se hai un sistema simile, scritto anni fa da qualcuno che non c'è più, e vuoi sapere quanto è concentrato il tuo dolore, il percorso comincia con la modernizzazione del software legacy. Per fare il conto dei costi nascosti trovi la guida al costo del software legacy, e se ti serve una persona che guardi il sistema con te c'è la consulenza software.

In cinque righe. Misura la quota di modifiche nel 20% dei moduli, e se è sotto il 32% non usare il pattern. Metti una facciata prima di scrivere una riga di nuovo. Parti dai moduli dove cadono le modifiche, non da quelli facili. Un solo scrittore per ogni tabella, sempre. Ogni modulo ha un rientro provato e una data di cancellazione del vecchio.

Domande frequenti

È un metodo di migrazione in cui si mette una facciata davanti al sistema vecchio e si sostituisce una funzione alla volta con una nuova, deviando il traffico modulo per modulo. Il vecchio resta in produzione finché non serve più. Il nome viene dal ficus strangolatore, che cresce attorno a un albero fino a prenderne il posto. Lo ha descritto Martin Fowler nel 2004.

Se la riscrittura riesce nei tempi, costa meno: nel caso di questo articolo 1.887.500 euro in cinque anni contro 2.181.060. Ma con due anni di modifiche congelate e il 30% di probabilità di fermarsi, la riscrittura arriva a 2.515.250 euro, più di non fare niente. Lo Strangler costa il 16% in più della riscrittura perfetta e il 13% in meno di quella con blocco e rischio, e si può fermare in qualsiasi momento.

Dai moduli dove cadono le modifiche, non da quelli più facili. Si ordinano i moduli per numero di interventi degli ultimi dodici mesi e si guarda la quota del primo 20%. Nel caso descritto, otto moduli su quaranta ricevono il 71% degli interventi. Il primo modulo si sceglie con quattro criteri: concentrazione delle modifiche, confini netti, possibilità di test e visibilità per gli utenti.

Quando le modifiche sono sparse e nessun gruppo di moduli supera il 32% del totale, quando il sistema è piccolo (sotto le 30.000 righe), quando il legacy costa solo il 20-30% in più di un sistema moderno e quando non esiste una cucitura dove inserire la facciata, come in un programma desktop monolitico. In questi casi conviene curare, riordinare i dati o riscrivere.

La strada più semplice è un database condiviso con un solo scrittore per ogni tabella: quando un modulo passa al nuovo, anche le sue tabelle passano al nuovo come scrittore, e il vecchio le legge soltanto. Lo si fa rispettare con i permessi del database. Uno strato anti-corruzione traduce tra il vecchio schema e un modello pulito. I database separati con replica servono solo quando lo schema vecchio è intoccabile.

Per un sistema da 380.000 righe e 40 moduli: 2-3 settimane di misura, 3-4 mesi per facciata e primo modulo, 9-14 mesi per gli otto moduli caldi e 12-18 mesi, a scelta, per la coda e lo spegnimento del vecchio. Il pareggio sul costo arriva intorno al trentaduesimo mese. Il team minimo è di tre persone: un architetto e due sviluppatori.

Lascia i tuoi dati nel form qui sotto

Matteo Migliore

Matteo Migliore è un imprenditore e architetto software con oltre 27 anni di esperienza nello sviluppo di soluzioni basate su .NET e nell'evoluzione di architetture applicative per imprese e organizzazioni di alto profilo.

Nel corso della sua carriera ha collaborato con realtà come Cotonella, Il Sole 24 Ore, FIAT e NATO, guidando team nello sviluppo di piattaforme scalabili e modernizzando ecosistemi legacy complessi.

Ha formato centinaia di sviluppatori e affiancato aziende di ogni dimensione nel trasformare il software in un vantaggio competitivo, riducendo il debito tecnico e portando risultati concreti in tempi misurabili.

Stai leggendo perché vuoi smettere di rattoppare software fragile.Scopri il metodo per progettare sistemi che reggono nel tempo.