Migrazione da monolite a microservizi: il metodo Strangler Fig applicato a Laravel
Il pattern più pericoloso nell'ingegneria del software non è un bug - è la riscrittura totale. Il CTO che dice "buttiamo via tutto e riscriviamo da zero" sta commettendo un errore che in vent'anni di consulenza ho visto ripetersi con precisione chirurgica: il nuovo sistema richiede il doppio del tempo previsto, costa il triplo del budget, e quando finalmente arriva in produzione non ha la metà delle funzionalità del vecchio sistema - funzionalità che nessuno aveva documentato perché "erano ovvie" e che emergono come requisiti mancanti solo quando gli utenti iniziano a lamentarsi. Joel Spolsky lo ha scritto nel 2000 e resta vero nel 2025: "la cosa peggiore che un'azienda di software può fare è riscrivere il proprio codice da zero."
L'alternativa si chiama Strangler Fig - un pattern architetturale che prende il nome dal fico strangolatore, un albero tropicale che cresce intorno all'albero ospite e gradualmente lo sostituisce, ramo per ramo, senza mai ucciderlo di colpo. Applicato ai sistemi software, il Strangler Fig significa estrarre funzionalità dal monolite una alla volta, redirigere il traffico verso il nuovo servizio, e ridurre progressivamente il monolite fino a quando non resta un guscio vuoto che puoi spegnere. Nel frattempo, il monolite resta in produzione e continua a funzionare per tutto ciò che non è ancora stato migrato. Zero downtime, zero big bang, rischio controllato ad ogni passo.
Ho applicato questo pattern per un'azienda del settore logistico con un monolite Laravel da 90.000 righe di codice, 12 sviluppatori, e un sistema in produzione da cinque anni che gestiva tracking spedizioni, fatturazione elettronica, gestione magazzino e portale clienti. In due anni di lavoro incrementale - non due anni a tempo pieno, ma interventi periodici distribuiti nel tempo - abbiamo estratto tre microservizi autonomi (tracking, fatturazione e notifiche), ridotto il monolite del 40% in termini di righe di codice, e mantenuto il servizio operativo per gli utenti senza un singolo giorno di interruzione. Il monolite che resta gestisce ancora il magazzino e il portale clienti, ed è più veloce e più manutenibile di prima perché ha meno responsabilità.
Come funziona il Strangler Fig in pratica su un monolite Laravel?
Il concetto è semplice nella teoria e richiede disciplina nell'esecuzione. Il processo si articola in quattro fasi ripetute ciclicamente per ogni funzionalità da estrarre:
Fase 1: identificare il confine. Scegli la funzionalità da estrarre in base a tre criteri: ha un confine di dominio chiaro (pochi punti di contatto con il resto del monolite), ha un valore di business nell'essere indipendente (scaling separato, deploy separato, o team dedicato), e ha una complessità gestibile come primo esperimento (non la funzionalità più critica del sistema). Nel caso della logistica, il modulo di tracking era il candidato ideale: dominio chiaro (riceve aggiornamenti dai corrieri, espone lo stato al portale clienti), requisiti di scaling specifici (i webhook dei corrieri arrivano in burst di migliaia al minuto), e bassa criticità transazionale (un ritardo nel tracking non blocca un ordine).
Fase 2: costruire il nuovo servizio in parallelo. Il nuovo servizio viene costruito da zero con la tecnologia appropriata (Symfony per il tracking, perché il team aveva competenze su entrambi i framework), con il suo database separato, la sua API e i suoi test. Il monolite non viene toccato in questa fase - il nuovo servizio esiste ma non riceve traffico di produzione. Questa fase può durare settimane o mesi, senza impatto sul business.
Fase 3: il proxy layer - il cuore dello Strangler. Questo è il passaggio tecnico cruciale. Invece di cambiare il monolite per chiamare il nuovo servizio, si introduce un proxy layer davanti al monolite che intercetta le richieste dirette alla funzionalità estratta e le redirige verso il nuovo servizio. In Laravel, il proxy può essere un middleware o un reverse proxy Nginx:
# Configurazione Nginx come Strangler Fig proxy
# Le richieste al tracking vanno al nuovo servizio
# Tutto il resto va al monolite
location /api/tracking/ {
# Nuovo servizio di tracking (Symfony su porta 8081)
proxy_pass http://127.0.0.1:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /webhooks/corrieri/ {
# Webhook dei corrieri al nuovo servizio
proxy_pass http://127.0.0.1:8081;
proxy_set_header Host $host;
}
location / {
# Tutto il resto va al monolite Laravel (porta 8080)
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}Fase 4: migrazione dei dati e spegnimento della vecchia funzionalità. Una volta che il nuovo servizio è stabile in produzione (tipicamente dopo 2-4 settimane di funzionamento parallelo), migri i dati storici dal database del monolite al database del nuovo servizio, rimuovi il codice del tracking dal monolite, e il Strangler ha completato un ciclo. Il monolite è più piccolo, il nuovo servizio è autonomo, e puoi procedere con la prossima funzionalità da estrarre.
Nel mio profilo professionale trovi il dettaglio dell'esperienza che porto in queste migrazioni incrementali - e la differenza tra un consulente che "ha letto il pattern" e uno che l'ha applicato su sistemi reali sta nella gestione dei casi edge che emergono solo in produzione.
I tre problemi che nessun tutorial sullo Strangler Fig ti dice
Problema 1: la sincronizzazione dei dati durante la fase parallela. Quando il monolite e il nuovo servizio coesistono e gestiscono gli stessi dati (ad esempio, durante le 2-4 settimane di funzionamento parallelo del tracking), devi decidere chi è la fonte di verità. Se il monolite riceve ancora aggiornamenti dai vecchi webhook che non sono ancora stati redirezionati, e il nuovo servizio riceve quelli nuovi, i dati sono inconsistenti. La soluzione che uso è un dual-write temporaneo: il proxy layer inoltra i webhook a entrambi i sistemi durante la fase di transizione, e un job di riconciliazione notturno verifica che i dati siano allineati. È un compromesso - l'architettura è temporaneamente più complessa - ma dura solo 2-4 settimane e garantisce zero perdita di dati.
Problema 2: le foreign key cross-service. Nel monolite, la tabella ordini ha una FK verso la tabella tracking_events. Quando estrai il tracking in un servizio separato con un database separato, quella FK non esiste più. Il monolite deve cambiare il modo in cui accede ai dati di tracking: da un JOIN SQL diretto a una chiamata API verso il nuovo servizio. Questa modifica è un cambiamento del monolite che va fatto con cautela, perché introduce latenza di rete dove prima c'era una query locale. La mitigazione è una cache Redis nel monolite che conserva gli ultimi stati di tracking dei pacchi più recenti - la cache viene aggiornata da un consumer RabbitMQ che riceve gli eventi dal servizio di tracking. In questo modo, il monolite accede alla cache locale (2 ms) invece di fare una chiamata API (20-50 ms) per ogni visualizzazione di ordine.
Problema 3: il rollback. Cosa succede se il nuovo servizio di tracking ha un bug critico in produzione? Con uno Strangler Fig ben implementato, il rollback è semplice: cambi la configurazione Nginx per redirigere il traffico al monolite, che ha ancora tutto il codice (non l'hai rimosso fino alla fine della fase 4). Il servizio malfunzionante viene isolato, il monolite riprende a gestire il tracking, e nessun utente se ne accorge. Questo è il vantaggio fondamentale dello Strangler rispetto al big bang: il rollback è una modifica di configurazione di 30 secondi, non una riscrittura di emergenza. Ho applicato lo stesso principio di reversibilità nel mio lavoro di refactoring di codice PHP legacy, dove ogni modifica deve essere annullabile senza perdita di dati e senza interruzione del servizio.
Il risultato dopo due anni: tre servizi estratti, monolite ridotto del 40%
I tre servizi estratti dal monolite della logistica sono stati: tracking (mese 3-5), fatturazione elettronica verso SDI (mese 8-11), e notifiche push e email (mese 14-16). Ogni estrazione ha seguito il ciclo di quattro fasi descritto sopra, con variazioni nella durata ma non nella struttura. Il monolite che rimane gestisce magazzino e portale clienti - due domini che non hanno ancora bisogno di estrazione perché non hanno requisiti di scaling indipendenti e sono gestiti da un solo team.
I benefici misurabili dopo due anni sono: il tempo di deployment del monolite è sceso da 18 minuti a 9 minuti (meno codice da testare e buildare), il servizio di tracking scala autonomamente durante i picchi del venerdì pomeriggio (fino a 6 istanze, contro il monolite che resta su 2), la fatturazione elettronica ha il suo ciclo di rilascio indipendente (deploy giornaliero per adeguarsi ai cambiamenti del tracciato SDI senza coinvolgere il resto del team), e le notifiche gestiscono burst di 50.000 email senza impattare le prestazioni del portale clienti.
Il costo di due anni di migrazione incrementale è stato significativamente inferiore a quello che sarebbe stato una riscrittura totale - e soprattutto, durante quei due anni il sistema ha continuato a funzionare, a generare fatturato e a servire i clienti. Con una riscrittura big bang, quei due anni sarebbero stati spesi a costruire un sistema che non esiste ancora, con un team diviso tra mantenere il vecchio e costruire il nuovo, con il rischio concreto che il nuovo non arrivi mai a feature parity con il vecchio.
Checklist operativa: sei pronto per uno Strangler Fig?
Prima di iniziare un percorso Strangler Fig, verifico sempre con il cliente che i prerequisiti minimi siano soddisfatti. Senza questi prerequisiti, il rischio di fallimento è alto e il consiglio onesto è rimandare la migrazione e lavorare prima sulla maturità operativa del team.
- Version control e CI/CD funzionanti: se il monolite non ha una pipeline di test automatici e un processo di deploy ripetibile, la migrazione a microservizi moltiplica il caos invece di risolverlo. Prima automatizza il deploy del monolite, poi pensa a estrarre servizi
- Almeno un membro del team con esperienza su infrastruttura distribuita: qualcuno nel team deve capire concetti come service discovery, circuit breaker, consistenza eventuale e distributed tracing. Se nessuno li conosce, la formazione deve precedere la migrazione, non accompagnarla
- Monitoring e logging centralizzato: senza la capacità di correlare log tra servizi diversi, il debugging post-migrazione è impossibile. Un ELK stack o un Grafana Loki devono essere operativi prima di estrarre il primo servizio
- Mapping chiaro dei domini di business: i confini dei servizi devono seguire i confini del dominio di business, non i confini tecnici. Un servizio "DatabaseService" o "UtilityService" è un segnale che stai decomponendo per layer tecnico invece che per responsabilità di business, e il risultato sarà un distributed monolith - il peggiore dei due mondi
- Sponsor esecutivo informato: il CTO o il product owner devono capire che lo Strangler Fig è un investimento distribuito nel tempo, non un progetto con una data di fine. Se il management vuole "i microservizi pronti per il Q2", il pattern non è lo Strangler - è il big bang, con tutti i rischi che comporta
Se anche solo due di questi prerequisiti mancano, il mio consiglio è investire prima nel consolidamento del monolite - ristrutturazione interna, test automatici, bounded context nel codice - e rimandare l'estrazione dei servizi a quando il team è maturo per gestirla. Un monolite ben strutturato è sempre meglio di microservizi mal gestiti, e lo dico con la convinzione di chi ha visto entrambi gli scenari più volte di quanto avrebbe voluto.
Lo Strangler Fig non è il pattern più glamour - non c'è un "giorno del lancio" con i palloncini, non c'è il commit dove cancelli il vecchio repository e parti con il nuovo. È un lavoro incrementale, disciplinato, che produce risultati misurabili settimana dopo settimana. Ed è esattamente il tipo di lavoro che le PMI italiane hanno bisogno quando il monolite inizia a pesare ma il business non può permettersi di fermarsi per una riscrittura. Se hai un monolite che sta diventando troppo grande e stai considerando una migrazione a microservizi, contattami per una valutazione: partiamo dall'analisi dei confini di dominio, identifichiamo il candidato ideale per la prima estrazione, e costruiamo un piano Strangler Fig con tappe, tempi e indicatori di successo chiari.