← Blog Architectural refactoring

Legacy-to-microservices migration: the realistic 6-month plan

TL;DR

[EN draft] Un monolite legacy maturo si migra a microservizi in 18-24 mesi, non in sei. In sei mesi si arriva a estrarre il primo bounded context critico e a impostare l'infrastruttura. Pretendere di piu' produce big-bang fallimentari. Strangler pattern + automazione + discovery seria, in quest'ordine.

English version draft — full translation in F3. Italian content preserved for technical fidelity.

La proposta di migrazione legacy a microservizi e' una delle conversazioni piu' frequenti che abbiamo con i CTO delle PMI italiane che hanno un monolite vivo da 10-15 anni. Le motivazioni sono sempre simili: i deploy richiedono ore, le release sono rischiose, ogni cambiamento impatta aree lontane, la velocita' del team rallenta.

La risposta sbagliata e' "bene, microservizi in sei mesi". La risposta giusta e' un piano disciplinato che riconosca la complessita' vera. Vediamo cosa funziona e cosa non funziona.

Perche' i progetti big-bang falliscono

Negli ultimi anni abbiamo visto fallire tre progetti di migrazione big-bang (con team interni di nostri clienti) per ragioni quasi identiche.

Stima del lavoro x3 piu' del previsto. Un monolite legacy ha logica di business sparsa, accoppiamenti taciti, casi limite documentati solo nel codice. Estrarre un bounded context senza rotture richiede archeologia significativa.

Zero capacita' di rollback. Big-bang significa lanciare tutto insieme. Se qualcosa non funziona in produzione, non c'e' versione precedente a cui tornare.

Operations non pronte. Microservizi richiedono observability distribuita, CI/CD per ogni servizio, container orchestration, service mesh. Tutte cose che il team monolitico non ha.

Il pattern Strangler Fig che funziona

Il pattern proposto da Martin Fowler nel 2004 e' tuttora la migliore strategia: invece di sostituire il monolite, lo si "strangola" gradualmente sostituendo una funzionalita' alla volta.

Funziona cosi':

  1. Si introduce un reverse proxy (API gateway) davanti al monolite.
  2. Si identifica un bounded context con caratteristiche favorevoli (poche dipendenze, valore alto, basso rischio).
  3. Si estrae quel context in un servizio separato.
  4. Il gateway instrada il traffico vecchio al monolite, il traffico relativo al nuovo context al servizio nuovo.
  5. Se qualcosa non funziona, si torna a instradare al monolite (rollback semplice).
  6. Quando il nuovo servizio e' stabile, si estrae il successivo.

In sei mesi, su un monolite tipico, si arriva a estrarre 1-3 bounded context. Non di piu'.

Fase 0 — Discovery (settimane 1-3)

Investimento iniziale spesso saltato. Discovery seria significa:

  • Mappare il monolite tramite analisi statica + interviste agli sviluppatori senior.
  • Identificare i bounded context tramite tecnica DDD (Event Storming workshop, 2-3 giorni).
  • Selezionare il primo candidato all'estrazione: basso accoppiamento, valore alto, owner chiaro.
  • Disegnare l'architettura target high-level, senza scendere nei dettagli.

Output: documento di 30-50 pagine con mappa monolite, mappa target, roadmap di estrazione, ROI stimato.

Fase 1 — Infrastruttura (settimane 4-7)

Senza infrastruttura adeguata, estrarre servizi e' un boomerang.

  • API gateway davanti al monolite. Nginx custom o Kong o Traefik. Configurazione iniziale instrada tutto al monolite.
  • Containerizzazione del monolite. Anche senza estrarne pezzi, mettere il monolite in container migliora deploy e consistency.
  • CI/CD pipeline. GitHub Actions o GitLab CI con stage build/test/deploy per ogni futuro servizio.
  • Observability stack. Logs centralizzati (Loki), metriche (Prometheus + Grafana), tracing distribuito (Jaeger o OpenTelemetry).
  • Container orchestration. Kubernetes se l'organizzazione ha competenza, altrimenti Docker Swarm o ECS o anche solo Docker Compose multi-host.

Fase 2 — Primo servizio estratto (settimane 8-16)

Identificato il candidato, l'estrazione segue questi step:

  1. Schema database separato. Il nuovo servizio ha il proprio DB, anche se inizialmente sync con monolite.
  2. Implementazione del servizio con stack moderno scelto (tipicamente Node/TypeScript, Python/FastAPI, o Go).
  3. Test di parita': chiamare entrambi (monolite e nuovo servizio) per le stesse richieste, confrontare output. Solo quando differenze sono spiegabili si procede.
  4. Migration dati con processo dedicato, run-book di rollback.
  5. Cutover graduale: 1% traffico al nuovo, 10%, 50%, 100% in 2-4 settimane.
  6. Rimozione codice obsoleto dal monolite solo quando il nuovo servizio e' stabile per 30 giorni.

Fase 3 — Secondo servizio (settimane 17-24)

Avendo imparato dal primo, il secondo va piu' veloce. Tipicamente 4-6 settimane invece di 8-10. Da qui in poi si accelera.

Dopo 24 settimane di lavoro, lo stato del sistema e' tipicamente:

  • Monolite ancora in produzione, ma con 2 funzionalita' estratte.
  • Infrastruttura di microservizi consolidata.
  • Team che ha capito il pattern e puo' eseguire estrazioni in autonomia.
  • Roadmap aggiornata per i 12-18 mesi successivi.

Errori da non fare

Errore 1 — Estrarre il piu' difficile per primo. Tentazione comune ("se ce la facciamo con il pezzo difficile, il resto e' facile"). E' l'opposto: il primo serve a imparare il pattern. Estrarre prima il pezzo piu' isolato, anche se non e' il piu' impattante.

Errore 2 — Database condiviso. Microservizi che condividono lo stesso database non sono microservizi: sono moduli di un monolite distribuito. Database separati sono obbligatori, anche se richiedono sync iniziale.

Errore 3 — Niente test automatici. Migrazione senza suite di test completa e' suicidio. Investimento prioritario: portare la suite di test del monolite ad almeno 60% coverage prima di iniziare.

Errore 4 — Sottostimare la fase di osservazione post-cutover. Dopo il 100% del traffico al nuovo servizio servono 30 giorni di osservazione attiva. Tagliare questa fase produce regressioni in produzione.

Costi realistici

Un progetto di migrazione 6 mesi con team di 4-6 persone (1 architetto, 2-3 senior developer, 1 SRE, 1 PM part-time):

  • Discovery: 25-40 k€
  • Infrastruttura: 35-60 k€
  • Primo servizio: 40-70 k€
  • Secondo servizio: 25-45 k€
  • Totale 6 mesi: 125-215 k€

Per i 12-18 mesi successivi, mantenere il team produce 2-4 servizi/anno. Migrazione completa di un monolite medio in 2-3 anni totali.

Quando NON migrare

Non tutti i monoliti vanno migrati. Tre situazioni dove e' meglio fermarsi.

1. Il monolite funziona, il team e' piccolo. Microservizi richiedono overhead operativo. Sotto i 10-15 sviluppatori, monolite ben modulato spesso e' la scelta migliore.

2. Il prodotto e' a fine vita. Investire 200k+ su un prodotto che scomparira' in 2-3 anni non ha ROI.

3. I problemi sono di processo, non di architettura. Se i deploy sono lenti perche' non c'e' CI/CD, microservizi non risolveranno. Sistemare prima il CI.

FAQ

Si puo' fare full-stack rewrite invece di strangler?

Si', ma di solito sbagliato. Rewrite richiede mantenere parita' di feature mentre si scrive da zero, di solito impossibile su monoliti maturi. Strangler riduce il rischio.

Kubernetes e' obbligatorio?

No. Per progetti piccoli-medi, Docker Compose + Swarm o ECS managed bastano. Kubernetes ha senso quando si gestiscono 20+ servizi e team multipli.

Quanto durera' il monolite legacy in produzione?

Tipicamente 18-36 mesi. Coesistenza con servizi estratti durante tutta la migrazione. Da pianificare manutenzione minima del monolite durante tutto il periodo.

Quale linguaggio usare per i microservizi?

Quello che il team conosce, salvo motivazioni forti. Cambiare linguaggio raddoppia la complessita' del progetto. Migrazione architetturale + migrazione linguaggio insieme e' troppo. Prima una, poi eventualmente l'altra.

Conclusione

La migrazione legacy a microservizi e' un investimento pluriennale che richiede disciplina, pazienza e team adeguato. Promesse di "in sei mesi tutto pronto" sono spesso sintomo di sottostima profonda. Per discutere il vostro caso, apriamo un confronto tecnico.

A software problem you don't know who to entrust?

A free 30-minute conversation to scope the project.

Open a conversation