Aggregate Root | Domain Model | Domain Layer | Domain Driven Design
Aggregate is a pattern in Domain-Driven Design.
A DDD aggregate is a cluster of domain objects that can be treated as a single unit.
An example may be an order and its line-items, these will be separate objects, but it's useful to treat the order (together with its line items) as a single aggregate.
An aggregate will have one of its component objects be the aggregate root.
Any references from outside the aggregate should only go to the aggregate root.
The root can thus ensure the integrity of the aggregate as a whole.
Aggregates are the basic element of transfer of data storage - you request to load or save whole aggregates.
Load the Whole Aggregates
Save the Whole Aggregate in Transaction
Transnational and Consistency Boundary
Transactions should not cross aggregate boundaries.
DDD Aggregates are sometimes confused with collection classes (lists, maps, etc).
DDD aggregates are domain concepts (order, clinic visit, playlist), while collections are generic.
An aggregate will often contain multiple collections, together with simple fields.
The term "aggregate" is a common one, and is used in various different contexts (e.g. UML), in which case it does not refer to the same concept as a DDD aggregate.
It is difficult to guarantee the consistency of changes to a cluster related of objects in a model with complex associations.
Transactions/Concurrency Locks are used to ensure the Consistency.
In-variants are needed to implemented to the closely related groups of objects.
Due to cautious locking schemes cause multiple users to interfere pointlessly with each other and make a system unusable.
Therefore:
Cluster the ENTITIES and VALUE OBJECTS into AGGREGATES and define boundaries around each. Choose one ENTITY to be the root of each AGGREGATE, and control all access to the objects inside the boundary through the root. Allow external objects to hold references to the root only. Transient references to internal members can be passed out for use within a single operation only. Because the root controls access, it cannot be blindsided by changes to the internals. This arrangement makes it practical to enforce all invariants for objects in the AGGREGATE and for the AGGREGATE as a whole in any state change.
Aggregates and Roots
In real life, many concepts have relationships to each other. I have a set of credit cards, and each credit card has an owner (me). Each credit card has a billing institution, and each banking institution has a set of credit accounts, each of which may or may not be a credit card. If I were to represent all of these concepts as classes, what would the relationships be?
Should I represent every conceivable relationship possible in my object model? Where do I draw the line between whether or not to create a reference? If I have a reference between two entities, how should I handle persistence? Do updates cascade? Suppose an Employer has reference to their Manager directly. If I change the Employee.Manager.Name, and save the Employee, does the Manager’s Name get changed?
Object modeling is complex as it is. Invariants need to be enforced not only in an Entity, but in all the Entities that are referenced as well. That gets tough to maintain, and quick!
Aggregates draw a boundary around one or more Entities. An Aggregate enforces invariants for all its Entities for any operation it supports. Each Aggregate has a Root Entity, which is the only member of the Aggregate that any object outside the Aggregate is allowed to hold a reference to. From Evans, the rules we need to enforce include:
- The root Entity has global identity and is ultimately responsible for checking invariants
- Root Entities have global identity. Entities inside the boundary have local identity, unique only within the Aggregate.
- Nothing outside the Aggregate boundary can hold a reference to anything inside, except to the root Entity. The root Entity can hand references to the internal Entities to other objects, but they can only use them transiently (within a single method or block).
- Only Aggregate Roots can be obtained directly with database queries. Everything else must be done through traversal.
- Objects within the Aggregate can hold references to other Aggregate roots.
- A delete operation must remove everything within the Aggregate boundary all at once
- When a change to any object within the Aggregate boundary is committed, all invariants of the whole Aggregate must be satisfied.
That’s a lot of rules! All of them just come from the idea of creating a boundary around our Aggregates. The boundary simplifies our model, as it forces us to consider each relationship very carefully, and within a well-defined set of rules. Maintaining bi-directional associations is difficult enough without persistence thrown into the mix, so by modeling our relationships around real-world use cases, we can greatly simplify our model.
Not all relationships need to be represented through associations. In the Employee/Manager relationship, I can have a Manager directly off the Employee, but to get a Manager’s DirectReports, I’ll ask the EmployeeRepository. Since Employee is an Aggregate Root, it’s fine to have an Employee reference its Manager.
Modeling and simplification
One of my favorite quotes from Evans’ book is:
Translation blunts communication and makes knowledge crunching anemic.
To avoid translation, we’ll represent real-world concepts in our conceptual model, and our conceptual model expressed as code through Entities and Value Objects (and Services). To simplify our model, we’ll use Aggregates and Roots, enforcing invariants at each operation. In all cases, I should be able to represent our conceptual model in our code, and it should make sense to our domain expert, as they’ll see the Ubiquitous Language represented.
When the conceptual model we create with the domain expert is realized effectively in code, we’ll find that not only to technical refactorings become easier, but enhancements to our model as well. Entities and Value Objects are but a slice in the DDD world, but a core concept which many other ideas are built upon.
No comments:
Post a Comment