The aggregate design pattern is an essential and valuable tool in your domain-driven design (DDD) toolkit. This technique is used when modeling your code entities (not storage entities).
You use aggregates to model the relationships between related code entities, especially when there are multiple entities within a logical group.
There are different ways you can implement this pattern, most of which rely on composition over inheritance.
This blog post will explain what the aggregate pattern is and how you can use it to improve your DDD implementation.
An aggregate is a set of related objects bound together by a common abstraction. The term is often used to describe the relationship between a parent object and a child object, with the parent being the “aggregate root’ and its child objects being the “members” of the aggregate.
Sometimes the term “composite” is used instead of “aggregate” to describe this relationship.
In DDD, an aggregate is a model-level concept. It describes relationships between two or more entities in your domain.
You use the aggregate pattern to model relationships between two or more entities that make up a logical group, significantly reducing the mental overhead when working with or rationalizing about your system.
Your software model entities (classes) rarely exist in a vacuum, and if you chunk related concepts together as a single cohesive unit, your system is easier to understand, manage, and change.
Using an aggregate is the difference between working with a loose heap of Lego parts scattered across your floor or working with pre-assembled Lego models lined up neatly in a row.
Working with a pre-constructed model is more straightforward because.
As an example, consider an online store that sells books.
This system may have a logical group of Book entities and another logical group of Author entities. The Book entities and Author entities are likely related to each other. If so, you can use the aggregate design pattern to model this relationship. The Book entities and the Author entities are the members of their respective aggregates.
The Book aggregate root may have a list of Author entities related to that Book. Likewise, the Author’s aggregate root may have a list of Book entities that are related to that Author.
In this situation, the aggregate pattern is helpful because it allows you to model this relationship without creating a one-to-many relationship between the Book and Author entities.
It is also helpful to deal with every aspect of a Book entity (including the authors) without traversing relationships between desperate Book and Author entities. For example, everything you need to work with a Book entity is found in one place.
There are several ways to implement the aggregate pattern. The following examples show two of the most common implementations: embedding or externalization.
In the embedding model, the aggregate is implemented by having the members (the other entities in the group) become part of the core entity.
The Book aggregate from the example above can be implemented as follows: The Book entity contains a list of Author entities. This list is the “members” of the Book aggregate, and the Book entity is the “aggregate root”.
Embedding is preferable when the Book and Author entities are closely related, and there would never be an Author without a Book (or a Book without an Author).
The externalization model has the members (the other entities in the group) be their own individual entities that are separate from the core entity, but each can form its own aggregate root.
For example, the Book entity references a list of Author entities, and each Author entity references a Book entity. This implementation is preferable when you have higher decoupling between your Book and Author entities and need to deal with them independently.
You can use the aggregate pattern to model the relationship between two or more entities that make up a logical group.
This pattern can be used when multiple entities comprise a cohesive logical group.
The aggregate pattern can be implemented differently, such as in the embedding or externalization model.
The choice of implementation depends on how closely related the members are to the core entity, as well as how decoupled the members are from the core entity in your business.