Pubblicato il 22 maggio 2026
Best PracticeSoftware DevelopmentArchitecture

Domain-Driven Design (DDD)

Una guida approfondita al Domain-Driven Design: concetti chiave, design strategico e tattico, e come modellare il software partendo dal cuore del business.

Cos'è il Domain-Driven Design?

Il Domain-Driven Design (DDD) è un approccio alla progettazione del software teorizzato da Eric Evans nel suo celebre libro del 2003: "Domain-Driven Design: Tackling Complexity in the Heart of Software".

A differenza degli approcci tradizionali incentrati sui database o sui framework tecnologici, il DDD sposta il focus interamente sul dominio: l'area di business, le regole e i problemi che il software è chiamato a risolvere. Il principio cardine è semplice ma rivoluzionario: la struttura del codice deve rispecchiare fedelmente il modello di business reale.


I Due Pilastri del DDD: Strategico e Tattico

Il Domain-Driven Design si divide in due macro-aree di progettazione, entrambe fondamentali per il successo di un progetto complesso.

graph TD
    DDD[Domain-Driven Design]-->DS["Design Strategico (Cosa e Dove)"]
    DDD-->DT["Design Tattico (Come)"]
    DS-->UL[Ubiquitous Language]
    DS-->BS[Bounded Contexts]
    DS-->CM[Context Mapping]
    DT-->EVO[Entities & Value Objects]
    DT-->AR[Aggregates & Root]
    DT-->R[Repositories]
    DT-->DE[Domain Events]

1. Design Strategico: Definire i Confini

Il design strategico si concentra sulla scomposizione di un grande dominio di business in parti più piccole e gestibili, definendo le relazioni tra di esse.

Ubiquitous Language (Linguaggio Ubiquo)

È un linguaggio condiviso e rigoroso, utilizzato indistintamente da sviluppatori, esperti di dominio (domain experts) e stakeholder. Non deve esserci alcuna traduzione tra il modo in cui il business parla di un problema e il modo in cui quel problema è codificato. Se il business parla di "Carrello Spedito", nel codice non dovremmo trovare OrderStatus = 3 o updateDeliveryStatus(), ma concetti espliciti come ShipOrder().

Bounded Context (Contesto Delimitato)

Un grande sistema software non può avere un singolo modello unificato senza creare ambiguità. Il Bounded Context definisce un confine logico all'interno del quale un modello specifico ha un significato preciso e univoco. Esempio: In un e-commerce, la parola Prodotto ha significati diversi a seconda del contesto. Nel contesto delle Vendite rappresenta una descrizione con un prezzo; nel contesto della Logistica rappresenta un oggetto fisico con peso e dimensioni. Il DDD consiglia di creare modelli separati in Bounded Context differenti anziché un unico modello Product gigantesco.


2. Design Tattico: Modellare il Codice

Il design tattico fornisce i mattoncini di codice per implementare i modelli all'interno di un Bounded Context.

Entities vs Value Objects

La distinzione tra queste due tipologie di oggetti è cruciale in DDD:

Concetto Entity (Entità) Value Object (Oggetto Valore)
Identità Definita da un ID univoco che non cambia nel tempo. Non ha identità. È definito esclusivamente dalle sue proprietà.
Mutabilità Mutabile (le sue proprietà possono cambiare, ma l'identità resta). Immutabile (per modificarlo se ne crea uno nuovo).
Eguaglianza Due entità sono uguali se hanno lo stesso ID. Due Value Object sono uguali se tutti i loro campi sono uguali.

Esempio in pseudo-codice:

// VALUE OBJECT: Immutabile, senza ID
class Soldi {
    constructor(readonly importo: number, readonly valuta: string) {}
    
    somma(altri: Soldi): Soldi {
        if (this.valuta !== altri.valuta) throw new Error("Valute diverse");
        return new Soldi(this.importo + altri.importo, this.valuta);
    }
}

// ENTITY: Ha un ID, le sue proprietà cambiano nel tempo
class Cliente {
    constructor(readonly id: string, public nome: string, public saldo: Soldi) {}
    
    riceviBonifico(somma: Soldi) {
        this.saldo = this.saldo.somma(somma);
    }
}

Aggregates (Aggregati)

Un Aggregato è un cluster di entità e Value Object associati che vengono trattati come un'unica unità per le modifiche dei dati. Ogni aggregato ha un confine ben definito e un Aggregate Root (la radice dell'aggregato), che è l'unica entità a cui il codice esterno può fare riferimento direttamente. L'Aggregate Root garantisce che tutte le regole di business (invarianti) all'interno dell'aggregato siano sempre rispettate. Esempio: Un Ordine (Aggregate Root) e le sue RigheOrdine (entità interne). Nessuno può modificare una riga d'ordine direttamente; si deve sempre passare attraverso l'oggetto Ordine per garantire che il calcolo del totale o gli sconti rimangano consistenti.

Repositories (Repository)

Forniscono un'interfaccia simile a una collezione in memoria per accedere agli aggregati. Nascondono i dettagli del database (SQL, NoSQL, ORM) dietro contratti chiari. I repository si occupano esclusivamente del salvataggio e del recupero degli Aggregate Roots.

Domain Events (Eventi di Dominio)

Un evento di dominio rappresenta qualcosa di rilevante accaduto nel passato all'interno del dominio di business. Gli eventi consentono di disaccoppiare diverse parti dell'applicazione o diversi contesti. Esempio: OrdineSpedito, UtenteRegistrato. Quando l'aggregato Ordine viene spedito, emette un evento OrdineSpedito che farà partire in modo asincrono l'invio dell'email di notifica o l'aggiornamento dell'inventario.


La Sinergia tra DDD e Clean Architecture

Il Domain-Driven Design si sposa splendidamente con la Clean Architecture. In un'applicazione progettata con entrambi i pattern:

  1. Il cerchio delle Entities della Clean Architecture conterrà gli Aggregati, le Entità e i Value Objects del DDD.
  2. Il cerchio degli Use Cases implementerà l'orchestrazione dei casi d'uso sfruttando le Domain Services e le interfacce dei Repositories.
  3. L'infrastruttura esterna implementerà le classi concrete dei Repositories per interfacciarsi con il database reale.

Questa combinazione crea codice disaccoppiato, altamente manutenibile e focalizzato al 100% sul valore di business.


Conclusione

Adottare il DDD non è immediato: richiede un cambio di mentalità per focalizzarsi sui processi di business invece che sulle tabelle dei database, e presuppone una collaborazione attiva con gli esperti di dominio (spesso agevolata da sessioni di Event Storming).

Tuttavia, per sistemi complessi ed enterprise, il Domain-Driven Design rappresenta lo standard di riferimento per evitare il debito tecnico e garantire che il software continui a supportare la crescita e l'evoluzione dell'azienda per molti anni.

Condividi questo articolo