Tag: ddd, architecture, microservices, aggregates, bounded-context, ubiquitous-language
Livello: advanced
TL;DR: Domain-Driven Design focuses on mapping complex business logic to software models through a Ubiquitous Language and bounded contexts. It separates domain logic from infrastructure, ensuring the software reflects the real-world business accurately.
Ubiquitous Language: A shared vocabulary between domain experts and developers to ensure accurate modeling without translation layers.
Bounded Context: A logical boundary within which a particular domain model is defined, valid, and strictly applicable.
Entities: Objects defined by a consistent thread of continuity and identity, not merely by their current data attributes.
Value Objects: Immutable objects that describe characteristics or attributes but have no unique identity (e.g., Money, DateRange).
Aggregates: Clusters of domain objects treated as a single transactional unit, encapsulating business rules and maintaining consistency.
Aggregate Root: The single entry-point entity for an aggregate, controlling all access to its internal objects to protect invariants.
Domain Events: Records of significant business occurrences that have happened in the past, used to decouple side effects.
Repositories: Abstractions that handle the retrieval and persistence of aggregates, mimicking an in-memory collection.
Anti-Corruption Layer (ACL): An isolation layer that translates between different subsystems to prevent pollution of the internal domain model.
Q: What is the difference between an Entity and a Value Object?R: I always explain that an Entity has a distinct identity that persists over time, while a Value Object is immutable and defined entirely by its structural attributes.
Q: Why is the Aggregate Root so important?R: I use the Aggregate Root to enforce transactional consistency and business invariants. External objects can only hold references to the root, preventing the internal state from being bypassed or corrupted.
Q: How do Bounded Contexts relate to Microservices architecture?R: A Bounded Context is a logical boundary for a domain model. I typically map one Bounded Context to one microservice, which provides a natural architectural boundary and prevents tight coupling.
Anemic Domain Model: Designing entities as mere data holders with public getters/setters, scattering the actual business logic across stateless services.
God Classes: Creating massive Aggregate Roots that handle too many responsibilities, leading to severe concurrency conflicts and unmaintainable code.
Ignoring the Ubiquitous Language: Translating business terms into generic technical jargon, causing friction and misunderstandings with domain experts.
Over-engineering: Applying complex DDD patterns to simple CRUD applications where a basic layered architecture would be far more efficient.
// Value Object: Immutable, no identity
class Money {
constructor(public readonly amount: number, public readonly currency: string) {}
equals(other: Money): boolean {
return this.amount === other.amount && this.currency === other.currency;
}
}
// Aggregate Root: Protects invariants and internal state
class Order {
private status: 'Pending' | 'Confirmed' | 'Shipped';
constructor(public readonly id: string, private total: Money) {
this.status = 'Pending';
}
confirm(): void {
if (this.status !== 'Pending') {
throw new Error("Order must be in Pending state to be confirmed.");
}
this.status = 'Confirmed';
// Domain Event dispatching would typically happen here
}
}
[ ] Event Sourcing integration with DDD aggregates.
[x] CQRS (Command Query Responsibility Segregation) to separate complex reads from domain writes.