Core DDD Concepts
To build an event-sourced system, you must understand three foundational pillars of Domain-Driven Design:1. Ubiquitous Language
The Ubiquitous Language is a shared, structured language used consistently by both software developers and non-technical business stakeholders (domain experts).- The names of your Rust structs, methods, commands, and events must map exactly to real business concepts.
- For example, instead of naming a function
update_balance_with_negative_delta, usewithdraw_moneyorcharge_fee. - This reduces translation errors and makes the code immediately understandable to anyone familiar with the business.
2. Entities & Value Objects
Within your domain model, data is separated into two categories:- Entities: Objects that have a unique, stable identity over time, even if their internal attributes change. For example, a
BankAccountis an entity identified by an account number. Even if the balance changes or the owner’s name is updated, it remains the same bank account. - Value Objects: Immutable objects that are defined solely by their attributes and have no identity of their own. For example, an
Addressor aMoneyAmountis a value object. If twoMoneyAmountobjects both contain$100, they are completely interchangeable.
3. The Aggregate Root & Transactional Consistency
An Aggregate is a cluster of associated entities and value objects that are treated as a single transaction unit for data changes.- The Aggregate Root is the sole entry point into this cluster. External objects are only allowed to hold references to the aggregate root, never to any entities inside the aggregate.
- The root serves as a strict transactional consistency boundary. Any modifications to any state inside the aggregate must go through the root. This guarantees that all business rules (domain invariants) are verified and enforced at all times.
- In our framework, this consistency boundary is represented by implementing the
Aggregatetrait.
How It Maps to Our Code
In our framework (ddd_cqrs_es), your aggregate root is represented by a plain Rust struct that implements the Aggregate trait.