Un monolite è una sola applicazione con un unico deployment; i microservizi la spezzano in servizi piccoli e indipendenti che dialogano via API. Il dibattito suona architetturale, ma è soprattutto organizzativo: la domanda vera è se struttura dei team, conoscenza del dominio e maturità operativa possano pagare la divisione – perché la divisione presenta sempre il conto.
Punti chiave
| Domanda | Risposta |
|---|---|
| Monolite | Un codebase, un deployment, chiamate in-process, un database |
| Microservizi | Molti servizi, deployment indipendenti, chiamate di rete, un database per servizio |
| La terza opzione nascosta | Il monolite modulare – una sola unità di deployment, confini interni applicati |
| L’impostazione predefinita condivisa | Partire monolitici; dividere quando il coordinamento dei deployment fa male, non prima |
| La trappola | Il monolite distribuito – costi da microservizi con l’accoppiamento del monolite |
La differenza in un esempio di codice
Dentro un monolite, chiamare un altro modulo è una chiamata di funzione: veloce, atomica, e non può fallire a metà:
// Monolite: chiamata in-process – una transazione, un solo dominio di guasto
const receipt = await billing.chargeOrder(order.id);
// Microservizi: la stessa chiamata attraversa la rete – e ora restano in carico
// timeout, ritentativi, guasti parziali ed eventual consistency
const res = await fetch('https://billing.internal/charge', {
method: 'POST',
body: JSON.stringify({ orderId: order.id }),
signal: AbortSignal.timeout(3000), // e se billing è lento?
});
if (!res.ok) await compensateOrder(order.id); // e se è riuscita a metà?
Ogni punto di dolore dei microservizi vive in quelle ultime tre righe. La via di mezzo gestita mantiene la logica su misura con deployment indipendente senza consegnare in mano la gestione dei guasti: una funzione si chiama come un servizio, ma gira su infrastruttura gestita dalla piattaforma:
// JavaScript / Node.js — Back4app JS SDK
// One deployable unit of business logic, no service mesh required
const receipt = await Parse.Cloud.run('chargeOrder', { orderId: 'ord_481' });
console.log(`Charged: ${receipt.status}`); // Flutter / Dart — Back4app Flutter SDK
final function = ParseCloudFunction('chargeOrder');
final response =
await function.execute(parameters: {'orderId': 'ord_481'});
if (response.success) {
print('Charged: ${response.result['status']}');
} // iOS / Swift — Back4app Swift SDK
ParseCloud.callFunction("chargeOrder",
parameters: ["orderId": "ord_481"]) { result in
if case .success(let receipt) = result {
print("Charged: \(receipt)")
}
} // Android / Kotlin — Back4app Android SDK
val params = hashMapOf("orderId" to "ord_481")
ParseCloud.callFunctionInBackground<Map<String, Any>>("chargeOrder", params) { receipt, e ->
if (e == null) Log.d("Billing", "Charged: ${receipt["status"]}")
} Tre forme, non due
L’articolo canonico sui microservizi descrive la destinazione; MonolithFirst descrive la strada: quasi tutti i sistemi a microservizi riusciti sono partiti da un monolite diventato troppo grande, e il monolite modulare è il modo di tenere aperta l’opzione – prima i confini, la rete dopo, e solo dove se l’è guadagnata.
Microservizi vs. monolite: le differenze pratiche
| Dimensione | Monolite | Microservizi |
|---|---|---|
| Deployment | Un’unica unità, un solo treno di release | Indipendente, per servizio |
| Scalabilità | L’app scala tutta insieme | Per servizio, dove il carico sta davvero |
| Chiamate tra le parti | In-process, nanosecondi | Rete, millisecondi + modi di guasto |
| Coerenza dei dati | Transazioni ACID | Saga ed eventual consistency |
| Isolamento dei guasti | Un bug può far cadere tutto | Guasti contenuti – se il progetto lo prevede |
| Dove vive la complessità | Nel codice | Nell’operatività |
| Team adatto | Un team, fino a ~10 sviluppatori | Più team autonomi |
| Debugging | Una sola stack trace | Tracing distribuito tra servizi |
| Profilo di costo | Un runtime, economico | Infra per servizio + osservabilità + team di piattaforma |
La riga più tagliente di quella tabella è dove vive la complessità: dividere un sistema non elimina la complessità – la sposta dal codebase alla rete, alla pipeline di deployment e alla dashboard delle 3 di notte.
I due sensi della storia delle migrazioni
Il senso famoso: una grande piattaforma di streaming video ha passato anni a dividere il proprio monolite in oltre mille servizi, risolvendo un problema di scalabilità che aveva davvero. Il senso opposto è più recente e altrettanto istruttivo: lo stesso settore ha prodotto un servizio di monitoring che ha rifuso i propri microservizi serverless in un unico processo e tagliato i costi di infrastruttura di circa il 90 % – spostare i dati tra i pezzi era la spesa dominante – e team di ingegneria che hanno consolidato più di cento servizi in uno solo, citando suite di test e gestione delle dipendenze diventate ingestibili. Entrambi i sensi erano razionali: la costante è che l’architettura ha seguito il problema misurato, non la tendenza.
Casi d’uso tipici
- Monolite: prodotti nuovi, team piccoli, domini ancora sfocati – dove la velocità di apprendimento batte la teoria della scalabilità.
- Monolite modulare: prodotti in crescita che vogliono opzioni future senza sovraccarico presente; l’impostazione predefinita che vale la pena difendere.
- Microservizi: molti team che rilasciano in autonomia, componenti con scalabilità divergente (feed vs. checkout), organizzazioni che già praticano provisioning rapido, monitoring e reperibilità.
- Ibrido con un backend gestito: le funzionalità standard (autenticazione, dati, archiviazione) consumate come servizio, la logica su misura come funzioni con deployment indipendente – autonomia da servizi al costo operativo di un monolite.
Conviene dividere? Matrice decisionale
| Restare monolitici quando… | Dividere quando… |
|---|---|
| Il team sta in una stanza (< ~10 sviluppatori) | 15–20+ sviluppatori su più team in coda su un’unica release |
| I confini del dominio si spostano ancora ogni mese | I confini sono stabili da trimestri |
| Le transazioni attraversano i workflow centrali | I componenti hanno dati davvero indipendenti |
| Maturità ops = “si rilascia di tanto in tanto” | Provisioning, tracing e reperibilità sono già solidi |
| Il dolore è la qualità del codice | Il dolore è il coordinamento dei deployment |
Se la colonna di sinistra descrive la situazione reale ma quella di destra attira, il monolite modulare è il compromesso onesto – e se dopo la divisione ogni modifica tocca tre servizi, quello che si è costruito è il monolite distribuito e conviene rifonderlo senza vergogna.
Limiti e trade-off
- Monolite: il treno di release rallenta mentre i team si moltiplicano; un memory leak diventa il disservizio di tutti; i grovigli di lunga data resistono all’estrazione se la disciplina dei moduli si allenta.
- Microservizi: il “MicroservicePremium” – transazioni distribuite, gestione dei guasti di rete, API versionate tra team della stessa azienda e uno stack di osservabilità che diventa una voce di bilancio a sé.
- Entrambi: nessuno dei due ripara un dominio modellato male. Confini dei servizi tracciati su un modello sbagliato producono una versione distribuita dello stesso disordine, con la latenza in più.
- Il vincolo organizzativo è reale: per la legge di Conway, si rilascia la propria struttura di comunicazione. Ristrutturare l’architettura senza ristrutturare i team produce l’anti-pattern con assoluta affidabilità.
Microservizi vs. monolite su Back4app
Back4app è una piattaforma open-source di Backend as a Service (BaaS) che combina database gestito, API REST e GraphQL generate automaticamente, autenticazione, archiviazione di file e funzioni serverless con Cloud Code. Cambia i termini del dibattito: l’80 % standard del backend non è nemmeno da progettare, e il 20 % su misura gira come funzioni Cloud Code – ciascuna con deployment indipendente come un microservizio, nessuna che si porti dietro un service mesh, un database per servizio o un turno di reperibilità. I team che superano anche questo conservano la via d’uscita: lo stack è open source, quindi estrarre un servizio vero più tardi parte da confini che funzionano, non da una riscrittura.
Domande frequenti
Microservizi o monolite: qual è la scelta migliore?
Nessuna delle due, in assoluto – ottimizzano cose diverse. Il monolite ottimizza la semplicità: un solo codebase, un solo deployment, chiamate in-process, transazioni di database reali. I microservizi ottimizzano l'autonomia dei team e la scalabilità indipendente – al prezzo della complessità dei sistemi distribuiti. I fattori decisivi sono la dimensione del team, la stabilità del dominio e la maturità operativa, non la moda architetturale.
Una startup dovrebbe adottare i microservizi?
Il consenso forte del settore è no: conviene partire da un monolite. L'argomento canonico, dal saggio MonolithFirst di Martin Fowler, osserva che quasi tutte le storie di successo con i microservizi sono partite da un monolite diventato troppo grande, mentre i sistemi nati come microservizi da zero fanno fatica: si finisce per tracciare i confini dei servizi prima di capire il dominio, che è esattamente il momento in cui li si traccia male.
Che cos'è un monolite modulare?
La terza opzione, deliberatamente noiosa: una sola unità di deployment con confini interni tra i moduli applicati in modo rigoroso. Conserva la semplicità operativa del monolite e costruisce intanto le linee di taglio che rendono possibile una divisione futura – ed è l'impostazione predefinita raccomandata dal consenso per la maggior parte dei team, perché i moduli tracciati bene si possono estrarre in servizi più tardi, mentre un monolite ingarbugliato no.
Che cos'è un monolite distribuito?
L'anti-pattern che combina il peggio dei due mondi: servizi fisicamente separati che però vanno modificati e rilasciati insieme – di solito perché i confini sono stati tracciati male o perché i servizi condividono un database. Si pagano i costi operativi dei microservizi (chiamate di rete, orchestrazione, osservabilità) conservando l'accoppiamento del monolite. È il modo di fallire più comune della divisione prematura.
Quando conviene dividere un monolite in microservizi?
Quando il collo di bottiglia diventa il coordinamento dei deployment, non la dimensione del codice: più team in coda su un solo treno di release, componenti con esigenze di scalabilità davvero divergenti e confini di dominio che hanno smesso di spostarsi. Soglie pratiche dall'esperienza del settore: sotto la decina di sviluppatori il monolite ha quasi sempre ragione; la divisione inizia a ripagarsi da quindici sviluppatori in su distribuiti su più team.
Come gestiscono i microservizi la coerenza dei dati?
Con difficoltà – è il costo meno pubblicizzato. Ogni servizio possiede il proprio database, quindi la transazione ACID che nel monolite stava in una riga diventa una saga: una sequenza di transazioni locali con rollback compensativi, che si assesta su una eventual consistency (coerenza finale). I workflow che hanno davvero bisogno di aggiornamenti atomici tra servizi sono il segnale che quei servizi non andavano separati.
Che cosa c'entra la legge di Conway con questa scelta?
Tutto: i sistemi finiscono per rispecchiare la struttura di comunicazione delle organizzazioni che li costruiscono. I microservizi funzionano quando piccoli team autonomi possiedono ciascuno un servizio da capo a fondo; l'architettura è un organigramma tanto quanto un diagramma. Un solo team piccolo che adotta i microservizi eredita il sovraccarico di coordinamento di molti team senza averli.
Ci sono aziende tornate dai microservizi al monolite?
Sì, e i casi di studio sono istruttivi. Il team di monitoring di una grande piattaforma video ha rifuso i propri microservizi serverless in un unico processo e tagliato i costi di infrastruttura di circa il 90 % – il passaggio dei dati tra i pezzi era la spesa dominante. Altri team di ingegneria hanno consolidato centinaia di microservizi in un solo servizio, citando un sovraccarico di test e di dipendenze. La lezione non è "i microservizi sono sbagliati", ma che la divisione deve pagare il proprio sovraccarico.