DDD, microservizi e architetture evolutive: quali best-practice?
Questo articolo è il primo di una serie dedicata all’esplorazione delle architetture software evolutive già pubblicati nella rivista web MokaByte e scritti da me, Alberto Acerbis.
Partendo dalla consapevolezza che sviluppare software va oltre il codice, evidenzierò l’importanza di capire il dominio e pensare in ottica business. Analizzerò Domain-Driven Design (DDD) e microservizi per riflettere su architetture software e best-practice per sistemi evolutivi e allineati alle esigenze del business.
Oltre la scrittura di codice
Scrivere codice, di per sé, non è così complicato. Basta conoscere un linguaggio, padroneggiare le best-practice, leggere qualche buon libro su Clean Code ed Extreme Programming, ed ecco che il risultato sarà leggibile e ben strutturato. Ma siamo davvero sicuri che sviluppare software significhi solo questo?
Un mio docente sosteneva che scrivere codice è solo l’ultima fase nella costruzione di un sistema. Una visione che all’inizio faticavo a condividere, preso com’ero dall’entusiasmo di far funzionare ciò che scrivevo. Col tempo, però, ho compreso che non aveva tutti i torti.
Sviluppare software significa prima di tutto risolvere problemi di business. E per farlo, serve comprenderli a fondo. È un processo continuo di apprendimento condiviso, che coinvolge clienti, stakeholder, utenti e sviluppatori. Il codice, in questo scenario, è solo la parte visibile di un lavoro molto più ampio.
Il senso delle architetture
Sviluppare software non è mai stato semplice — ancor meno nell’era dei Distributed Systems (sistemi distribuiti), dove microservizi, cloud e affidabilità sono elementi progettuali fondamentali.
Quando si parla di architettura, si pensa spesso a quelle più adottate — come hexagonal architecture, onion o clean architecture. Questi approcci offrono rassicurazione e replicabilità. Ma mancano spesso risorse chiare e pragmatiche su ambienti software evolutivi, affidabili e sostenibili nel tempo. Costruire software solido senza sovraprogettare fin dal primo giorno è una sfida che richiede equilibrio, esperienza e scelte consapevoli.
Tra best-practice e compromessi
Nel contesto delle architetture software evolutive, le best-practice non sono dogmi assoluti, ma punti di partenza. La realtà quotidiana dello sviluppo impone continui compromessi: ciò che funziona oggi potrebbe rivelarsi inefficace domani. Ogni scelta architetturale è il risultato di un bilanciamento tra esigenze tecniche, vincoli di business e contesto operativo — ed è qui che l’esperienza fa davvero la differenza. A vent’anni dall’uscita, il libro “Domain-Driven Design” di Eric Evans resta un riferimento per chi affronta complessità con un approccio domain-driven, ma va reinterpretato nel contesto attuale.
Introdurre il Bounded Context
Tra i concetti chiave emersi nel tempo parlando di architetture distribuite, il Bounded Context è sicuramente uno dei più citati — e forse, uno dei più fraintesi. Nato nel contesto del Domain-Driven Design di Eric Evans, questo pattern suggerisce di suddividere il dominio applicativo in confini ben definiti, all’interno dei quali ogni team può operare in modo indipendente, con pieno controllo sul proprio modello. Un’idea potente, soprattutto se accostata alla progettazione di microservizi, che permette di costruire soluzioni realmente modulari e scalabili. Tuttavia, come ricorda l’autore, il dominio resta “ignorante” rispetto alla persistenza: una distinzione che va compresa e interiorizzata, soprattutto quando si decide di affiancare il pattern del Bounded Context alla progettazione di servizi distribuiti.
La pallottola d’argento… non esiste
Separare le sfide legate al dominio di business da quelle infrastrutturali è un principio sano e condivisibile. Tuttavia, nella pratica quotidiana, questa distinzione è meno netta di quanto sembri. Fred Brooks, nel suo oramai celebre articolo “No Silver Bullet. Essence and Accident in Software Engineering“, distingueva tra complessità essenziale — intrinseca al problema di business — e complessità accidentale, legata agli strumenti, ai linguaggi e agli ambienti di deployment. Brooks sottolineava come la complessità accidentale sia destinata a ridursi nel tempo, consentendo agli sviluppatori di concentrarsi su ciò che conta davvero. Eppure, nel contesto attuale, ciò che un tempo era “accidentale” è spesso diventato parte integrante dell’essenziale: basti pensare alla gestione del cloud, delle reti, della scalabilità. Non esiste una cosiddetta “silver bullet” in grado di risolvere tutto, ma una maggiore consapevolezza dei tipi di complessità con cui abbiamo a che fare è il primo passo per progettare software che crei valore reale.
Qualche esempio con le architetture
Uno dei compiti principali di un software architect è garantire che la codebase, al pari dell’architettura, resti scalabile nel tempo. Curiosamente, non è necessario che questa figura conosca nel dettaglio il dominio di business, ma è invece fondamentale che sappia riconoscere — e gestire — i compromessi architetturali. Negli ultimi anni, questo compito si è fatto più arduo: l’affermazione dei microservizi ha introdotto un nuovo livello di complessità che, se mal gestito, porta spesso alla nascita del famigerato monolite distribuito.

Dal monolite ad architetture Service-Based ed Event-Driven…
Eppure, architetture di tipo Service-Based possono rappresentare un primo passo strategico nel percorso di evoluzione da un sistema monolitico verso una struttura più modulare. Consentono agli architect di individuare aree del sistema che necessitano di ulteriore granularità, senza frammentare subito il database o coinvolgere i business expert. È un approccio tecnico, pragmatico, che prepara il terreno a scelte più radicali, come l’adozione di un orchestratore e successivamente di un message broker, preludio a un’architettura orientata agli eventi: Event-Driven Architecture.

Questo passaggio segna un vero cambio di paradigma: nei microservizi moderni, il database non è più un’infrastruttura condivisa, ma diventa una dipendenza interna al singolo servizio. Il Bounded Context, come definito da Evans, ingloba ora anche la persistenza, rendendo il servizio veramente autonomo. Tuttavia, questa indipendenza porta con sé nuove sfide: l’adozione della comunicazione asincrona e la necessità di rivedere anche il modo in cui si gestisce il frontend.
… alle Quantum Architecture
È in questo scenario che il concetto di Quantum Architecture inizia a prendere forma: non più solo Bounded Context, ma unità architetturali pienamente indipendenti, deployabili in modo autonomo, pensate per evolvere singolarmente senza compromettere il sistema nel suo insieme. Una prospettiva che ci obbliga a ripensare l’architettura in termini di continui compromessi tra esigenze di dominio e vincoli tecnici. Da un lato, i pattern del Domain-Driven Design aiutano ad affrontare la complessità essenziale; dall’altro, gli architect devono continuamente vigilare sulla coerenza strutturale e capire quando una complessità “accidentale” è diventata parte integrante del problema reale da risolvere.

Da qui
Fin qui abbiamo solo scalfito la superficie. Sul fronte del dominio, il prossimo passo sarà chiarire la distinzione tra problem space e solution space — due prospettive fondamentali per comprendere cosa stiamo davvero cercando di risolvere e come possiamo costruire la giusta soluzione. Sul piano architetturale affronteremo le static coupling tra componenti interni e le dynamic coupling che governano la comunicazione tra i “quanta” del sistema.
Il Domain-Driven Design continuerà a essere il nostro punto di riferimento, grazie alla sua capacità di fornire sia pattern strategici sia strumenti tattici. Ma non sarà l’unica risorsa a cui attingere: per progettare soluzioni software davvero efficaci, capaci di rispondere in modo concreto ai bisogni di business, sarà necessario ampliare il nostro bagaglio di competenze e approcci.