Domain Driven Design — Cheat Sheet

Tag: ddd, architecture, microservices, bounded context, ubiquitous language, entities

Livello: avanzato

TL;DR: Approccio allo sviluppo incentrato sulle logiche di business complesse. Connette esperti di dominio e sviluppatori tramite un Ubiquitous Language all'interno di Bounded Context ben definiti.

Concetti chiave

Ubiquitous Language: Linguaggio condiviso e rigoroso tra sviluppatori ed esperti di business, usato ovunque (codice, conversazioni, documentazione).

Bounded Context: Confine logico esplicito in cui un particolare modello di dominio è valido, isolato da altre parti del sistema.

Entities: Oggetti di dominio definiti da un'identità univoca e continua nel tempo, non dai loro attributi.

Value Objects: Oggetti immutabili definiti unicamente dai loro attributi, privi di identità (es. Denaro, Indirizzo, Data).

Aggregates: Gruppi di Entities e Value Objects legati insieme, trattati come una singola unità di modifica dei dati.

Aggregate Root: L'unica Entity tramite cui l'esterno può interagire con l'Aggregate, responsabile della consistenza interna.

Repositories: Astrazioni che gestiscono il recupero e il salvataggio degli Aggregates dal database.

Domain Events: Notifiche che indicano che qualcosa di rilevante per il business è accaduto nel dominio.

Anti-Corruption Layer: Strato di traduzione usato per comunicare con sistemi esterni o legacy senza inquinare il proprio modello.

Domande tipiche e risposte pronte

Q: Qual è la differenza principale tra Entity e Value Object?R: Un'Entity è identificata in modo univoco (es. un ID utente) e il suo stato può cambiare. Un Value Object è immutabile e definito solo dai suoi dati; se i dati cambiano, sostituisco l'intero oggetto.

Q: Come si gestiscono le transazioni nel DDD?R: La regola aurea è modificare un solo Aggregate per transazione. Se occorre aggiornare altri Aggregates in seguito, pubblico dei Domain Events gestiti in modo asincrono.

Q: Come individui un Bounded Context?R: Analizzo l'Ubiquitous Language. Se lo stesso termine (es. "Prodotto") ha logiche o attributi diversi tra magazzino e vendite, identifico due Bounded Context separati.

Insidie e errori comuni

Progettare "Anemic Domain Models", dove le Entities sono solo contenitori di dati (getter/setter) e la logica risiede nei Services.

Creare Aggregates eccessivamente grandi, causando frequenti conflitti di concorrenza e cali di performance nel database.

Adottare il DDD tattico per applicazioni interamente CRUD, introducendo un overhead ingiustificato senza reale complessità di business.

Condividere lo stesso modello di database tra Bounded Context diversi, violando l'isolamento architetturale.

Snippet e comandiTypeScript

// Esempio base di Value Object e Aggregate Root

class Money {
  constructor(public readonly amount: number, public readonly currency: string) {
    if (amount < 0) throw new Error("Amount cannot be negative");
  }
}

class Order { // Aggregate Root
  private id: string;
  private status: string;
  private total: Money;

  constructor(id: string) {
    this.id = id;
    this.status = "CREATED";
    this.total = new Money(0, "EUR");
  }

  // Comportamento di dominio, non semplici setter
  public confirmPayment(amountPaid: Money): void {
    if (this.status !== "CREATED") throw new Error("Invalid state");
    if (amountPaid.amount < this.total.amount) throw new Error("Insufficient funds");

    this.status = "PAID";
    // this.addDomainEvent(new OrderPaidEvent(this.id));
  }
}
Jarvis Interviews
Jarvis