Il Modulo 10 si apre con il pattern architetturale che ha definito un decennio di discorso ingegneristico per poi invertirsi silenziosamente. Da circa il 2015 al 2020, la risposta predefinita a “come dovremmo strutturare il nostro backend” era “microservices, ovviamente”. Entro il 2021 le stesse aziende che erano state gli evangelisti più rumorosi stavano pubblicando post sul consolidare di nuovo verso monolith, o verso un ibrido che l’industria iniziò a chiamare modular monolith. Il pendolo non ha oscillato perché gli argomenti originali fossero sbagliati. Ha oscillato perché i costi che nessuno aveva misurato fino in fondo si sono rivelati più grandi dei benefici per la maggior parte dei team.
Questa lezione riguarda quell’arco, per cosa è buono ciascun shape, e come decidere in quale dovrebbe stare il vostro team. È l’apertura del Modulo 10 perché ogni lezione successiva del modulo (event-driven architecture nella lezione 74, multi-region nella lezione 75, e il resto) costruisce sopra una strategia di service-decomposition scelta. Scegliere lo shape sbagliato vi blocca nel set sbagliato di trade-off per anni.
Cosa significa davvero “microservices”
Stripped del branding, un’architettura a microservices è una in cui un singolo prodotto è diviso in molti servizi piccoli, deployabili indipendentemente, che comunicano sulla rete, ciascuno con il proprio data store, la propria deploy pipeline, e idealmente il proprio team.
Il contrasto è con un monolith: una grande codebase, un artefatto deployabile, un database (o un piccolo set), una deploy pipeline. Il monolith è lo shape di partenza predefinito dalle lezioni 1 a 6. I microservices sono ciò a cui i team si aggrappano quando il monolith inizia a fare male.
L’argomento per i microservices a metà degli anni 2010 era un fascio di benefici reali. Deployabilità indipendente: il team A spedisce il proprio servizio senza coordinare con il team B. Scalabilità indipendente: il servizio read-heavy gira su una flotta diversa da quello compute-heavy. Polyglot persistence (lezione 24): il servizio utenti usa Postgres, il servizio di ricerca usa Elasticsearch, il servizio carrello usa Redis. Linguaggi di programmazione poliglotti: il team ML scrive Python, il team payments scrive Java, il team front-of-the-stack scrive Go. I servizi più piccoli sono più facili da possedere end-to-end per un singolo team.
Ogni beneficio è reale. La versione onesta della storia è che ogni beneficio ha anche un costo che il marketing non pubblicizzava.
La legge di Conway e l’org chart
Il predittore più chiaro di come apparirà un’architettura non è il diagramma di design ma l’org chart. La legge di Conway, da un paper di Melvin Conway del 1967, lo afferma direttamente: qualunque organizzazione che progetta un sistema produrrà un design la cui struttura è una copia della struttura comunicativa dell’organizzazione.
Nel boom dei microservices questo funzionò in entrambe le direzioni. Le grandi aziende tech con centinaia di team avevano genuinamente bisogno di molti servizi posseduti indipendentemente, perché il loro org chart aveva molti team indipendenti. Le aziende più piccole che copiavano il pattern si sono ritrovate con trenta servizi posseduti da dodici ingegneri, e l’architettura non matchava l’org. Il risultato era una tassa di coordinazione perpetua: ogni cambiamento toccava cinque servizi, ogni cinque servizi erano posseduti da due persone, e le due persone passavano il loro tempo in riunione invece che a spedire.
La manovra Conway inversa, popolare nel periodo 2018-2020, era ridisegnare l’org chart per matchare l’architettura desiderata. A volte funzionava. Più spesso produceva un org chart pieno di team da due persone che non potevano realisticamente possedere un servizio end-to-end, e l’architettura soffriva nello stesso modo di prima. La legge di Conway è descrittiva, non prescrittiva: vi dice cosa accadrà, non a cosa dovreste mirare.
Il pushback dal 2021 in poi
A partire da circa il 2021, una serie di post pubblici da aziende che precedentemente avevano sostenuto i microservices iniziarono a fare un passo indietro sulla posizione. I tre più citati:
Shopify aveva fatto girare un monolith Rails per oltre un decennio e ha scritto una serie di post (“Deconstructing the Monolith”, Shopify Engineering, 2019, https://shopify.engineering/deconstructing-monolith-designing-software-maximizes-developer-productivity, consultato 2026-05-01) su come l’avevano tenuto gestibile man mano che l’azienda cresceva. Il pattern Shopify è ciò che chiamano componentisation: confini di moduli interni chiari dentro un singolo deployable, con regole strette su quale modulo può chiamare quale. L’argomento è che hanno ottenuto la maggior parte dei benefici dei microservices senza pagare il costo operativo.
Basecamp ha portato un argomento simile in linguaggio più rumoroso. David Heinemeier Hansson ha coniato il termine “majestic monolith” e ha sostenuto in scritti e a conferenze che un piccolo team non dovrebbe mai dividersi in microservices, perché il costo operativo della coordinazione è più grande di qualsiasi beneficio.
Amazon Prime Video ha pubblicato un post del 2023 (“Scaling up the Prime Video audio/video monitoring service and reducing costs by 90%”, AWS Open Source Blog, marzo 2023, https://www.primevideotech.com/video-streaming/scaling-up-the-prime-video-audio-video-monitoring-service-and-reducing-costs-by-90, consultato 2026-05-01) che descrive come il loro servizio di monitoring fosse stato costruito come pipeline serverless di microservices, avesse colpito un muro di scaling e di costo, e fosse stato ricostruito come un singolo servizio monolithic che gira su EC2. I costi sono scesi del 90 percento. Il post era impressionante perché veniva da dentro Amazon, l’azienda più associata alla spinta originale verso i microservices.
Il pattern attraverso i tre non è “i microservices erano un errore”. È “i microservices hanno un costo che abbiamo sottostimato, e molti team che li hanno adottati non ne avevano bisogno in primo luogo”.
Quando i microservices vincono
La lista onesta dei casi in cui l’architettura ripaga sé stessa:
Ownership di team indipendente a scala. Quando hai dieci team che hanno bisogno di cadenze di deploy diverse, rotazioni on-call diverse, e stack tecnologici diversi, dividere in dieci servizi è l’architettura che permette loro di lavorare in parallelo. Sotto quella scala, la coordinazione è più economica della divisione.
Profili di scaling diversi per componente. Quando il servizio di lettura sta facendo un milione di letture al secondo e il servizio di analytics sta facendo un migliaio di aggregazioni long-running, metterli nello stesso deployable significa che scalare il servizio analytics ti compra capacità di lettura che non ti serve, o viceversa. Dividere lascia che ogni flotta matchi il proprio carico.
Polyglot persistence per servizio. Quando il servizio utenti è fondamentalmente relazionale, l’activity feed è fondamentalmente uno stream, e il servizio di raccomandazioni è fondamentalmente un vector store, dividere lascia che ogni team scelga il data store che si adatta al problema.
Linguaggi di programmazione poliglotti. Quando parte del sistema ha requisiti di performance duri che hanno bisogno di un linguaggio compilato e parte del sistema ha requisiti di iterazione rapida che hanno bisogno di un linguaggio di scripting, dividere lascia che ogni team faccia la scelta locale senza forzare la stessa scelta su tutti gli altri.
Isolamento dei guasti attraverso critical path. Quando un fallimento nel servizio di ricerca non deve abbattere il servizio di checkout, il confine di rete diventa un confine di guasto. Un bug in un servizio non fa crashare l’altro.
Il pattern attraverso questi casi è che riguardano la scala: scala di team, scala di carico, scala di complessità. Sotto la scala, i guadagni sono piccoli e i costi sono reali.
Quando i microservices perdono
La lista complementare, attinta dai modi di fallire che hanno guidato il pushback dal 2021 in poi:
Team piccolo, molti servizi. Quando cinque ingegneri possiedono dodici servizi, ogni cambiamento cross-cutting è un rollout multi-servizio, e l’attenzione del team è frammentata su servizi che nessuno comprende fino in fondo.
La tassa dei sistemi distribuiti. Ogni chiamata cross-service introduce modi di fallire della rete. Le otto fallacies della lezione 9 (la rete è affidabile, la latenza è zero, la banda è infinita, e così via) tornano tutte come incident in produzione attorno ai quali il team deve fare engineering. Timeout, retry, circuit breaker, idempotenza, dead-letter queue. Nulla di tutto questo è necessario in un monolith perché la chiamata di funzione dentro un singolo processo non fallisce in quei modi.
Debugging tra servizi. Un utente segnala “la pagina è lenta”. In un monolith leggi il request log e lo slow query log. Nei microservices la request attraversa sei servizi, e ti serve un sistema di distributed tracing per vedere dov’è andato il tempo. Il sistema di tracing stesso è infrastruttura che devi costruire e far girare.
Complessità dello sviluppo locale. “Tira su trenta servizi per far girare l’app sul tuo laptop” è un modo di fallire reale. I team finiscono con elaborati file Docker Compose, layer di mocking, o setup tilt-and-skaffold, solo per rendere lo sviluppo possibile. I nuovi ingegneri passano la prima settimana sul setup dell’ambiente.
Versioning e drift dei contratti. Il servizio A e il servizio B condividono una API. Quando A cambia la API, B deve essere aggiornato. Moltiplica per N servizi e il costo di coordinazione cresce quadraticamente.
Costo operativo. Ogni servizio ha il proprio deployment, la propria dashboard di monitoring, la propria aggregazione di log, il proprio alerting, il proprio on-call. Il costo fisso per servizio non è banale.
La frase che ha catturato questo alla fine degli anni 2010 era “you must be this tall to ride the microservices ride”, attribuita in varie forme a Martin Fowler e altri. Il punto era che i microservices presuppongono un livello di maturità di piattaforma (CI/CD, observability, container orchestration, service discovery, gestione dei segreti, tooling per API interne) che i piccoli team non hanno e non possono costruire a basso costo.
La via di mezzo: modular monolith
L’architettura che è uscita dal pushback dal 2021 in poi come nuovo default per la maggior parte dei team è il modular monolith. Un deployable, un database (o un piccolo set), una deploy pipeline. I confini di modulo interni sono forti: ogni modulo possiede il proprio dominio, espone un’interfaccia definita, e non può raggiungere gli internals di un altro modulo. Il compilatore o il runtime fanno enforce dei confini.
Le implementazioni variano per linguaggio e framework. I component di Shopify usano confini di gem Ruby con tooling custom per fare enforce delle dipendenze. I Rails engine partizionano un’app Rails in sub-app montate. I package Java e i moduli Maven danno la stessa forma con un enforcement più forte a compile-time. I progetti .NET, gli internal package di Go, e i namespace package di Python giocano tutti lo stesso ruolo.
I benefici che il modular monolith preserva:
- Un deployable, una deploy pipeline, uno stream di log, un trace, una sessione di debugger.
- Il refactoring tra confini di modulo è un normale cambio di codice, non una migrazione multi-servizio.
- La performance è qualunque cosa una chiamata di funzione costi, non qualunque cosa un network round-trip costi.
- Il team può muovere tutto il codice in una volta sola quando il design ha bisogno di cambiare.
I benefici a cui il modular monolith rinuncia, rispetto a veri microservices:
- Deployabilità indipendente attraverso i team (ogni cambio spedisce nello stesso deploy).
- Scaling per modulo (l’intero monolith scala insieme).
- Polyglot persistence per servizio (puoi comunque usare data store multipli, ma sono accoppiati allo stesso deployable).
- Linguaggi di programmazione poliglotti.
La via di fuga è il path che il modular monolith rende economico: quando un modulo ha genuinamente bisogno di una cadenza di deploy indipendente o di scaling indipendente, lo estrai in un servizio. Non prima. La disciplina è tenere l’opzione aperta e non pagare il costo preventivamente.
Scegliere in base allo shape
L’albero di decisione che cade fuori da tutto questo:
flowchart TD
A[Are you a small team less than 20 engineers?] -->|Yes| B[Modular monolith]
A -->|No| C[Do teams need independent deploy cadence?]
C -->|No| B
C -->|Yes| D[Do components have very different scaling profiles?]
D -->|No| E[Modular monolith with selective extraction]
D -->|Yes| F[Microservices for the components that need it]
F --> G[Keep everything else in the modular monolith]
La stessa idea su un asse di team-size: da uno a cinque ingegneri, monolith. Da cinque a cinquanta, modular monolith. Da cinquanta a qualche centinaio, modular monolith con una manciata di servizi estratti per i componenti che lo giustificano. Qualche centinaio e oltre, i microservices diventano il default e la domanda si rovescia.
I cross-reference chiudono il cerchio. La lezione 8 ha trattato tre aziende (Stripe, Shopify, Basecamp) che sono rimaste più semplici di quanto l’industria si aspettasse e hanno spedito a scala su un monolith. La lezione 56 ha trattato la deployment pipeline di Stripe, in cui un singolo monorepo con servizi interni permette loro di spedire centinaia di volte al giorno senza pagare il costo pieno di coordinazione dei microservices. Entrambi i casi puntano alla stessa lezione: l’architettura che vince è di solito quella che matcha il team e il carico, non quella che vince la guerra dei blog di architettura.
Riferimenti
- “Deconstructing the Monolith”, Shopify Engineering, 2019,
https://shopify.engineering/deconstructing-monolith-designing-software-maximizes-developer-productivity, consultato 2026-05-01. - “Scaling up the Prime Video audio/video monitoring service and reducing costs by 90%”, Amazon Prime Video Tech, marzo 2023,
https://www.primevideotech.com/video-streaming/scaling-up-the-prime-video-audio-video-monitoring-service-and-reducing-costs-by-90, consultato 2026-05-01. - David Heinemeier Hansson, “The Majestic Monolith”, Signal v. Noise,
https://m.signalvnoise.com/the-majestic-monolith/, consultato 2026-05-01. - Martin Fowler, “Microservices”,
https://martinfowler.com/articles/microservices.html, consultato 2026-05-01. - Sam Newman, “Building Microservices, 2nd Edition”, O’Reilly, 2021. Riferimento standard per i trade-off.
- Conway, M. E. “How Do Committees Invent?”, Datamation, 1968. Il paper originale della legge di Conway.