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.
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.
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.
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.
// 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));
}
}