Friday, November 2, 2018

AGGREGATE Pattern | Domain Model | Domain Layer | Domain Driven Design

Aggregates | Domain Model | Domain Layer | Domain Driven Design


Aggregate: A collection of objects that are bound together by a root entity, otherwise known as an aggregate root. The aggregate root guarantees the consistency of changes being made within the aggregate by forbidding external objects from holding references to its members. Aggregates can also be seen as a kind of bounded context, giving the root entity and the whole object graph a context in which they are used.

Example: When you drive a car, you do not have to worry about moving the wheels forward, making the engine combust with spark and fuel, etc.; you are simply driving the car. In this context, the car is an aggregate of several other objects and serves as the aggregate root to all of the other systems. A steering wheel can be rotated, this is it’s context within the car aggregate. It can also be produced or recycled. This usually happens not within the driving car context, so this would be another aggregate, probably referencing the car as well.

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. 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 mutliple 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.

For more details see the Domain-Driven Design book and other links in the DDD Community website.

Aggregates
  • Aggregates decompose large object graphs into small clusters of domain objects to reduce the complexity of the technical implementation of the domain model.
  • Aggregates are a consistency boundary to ensure the domain model is kept in a reliable state.
  • Aim for smaller aggregates to reduce transnational locking and reduce consistency complexities.
  • An aggregate root is an entity of the aggregate that is chosen as the gateway into the aggregate.
  • The aggregate root ensures the aggregate is always consistent and invariants are enforced.
  • An aggregate root has global identity; the domain objects within the aggregate only have identity within the context of the aggregate root.
  • Domain objects outside the aggregate can only hold a reference to the aggregate root.
  • When an aggregate is deleted all the domain objects within it must be removed as well.
  • No domain objects outside the boundary of the aggregate can hold a reference to internal objects.
  • Aggregates, not individual domain objects, are persisted and hydrated from the database via the repository.
  • Relationships between aggregate roots should be implemented by keeping a reference to the ID of another aggregate root and not a reference to the object itself.
  • An aggregate’s internal domain objects can hold references to other aggregate roots.
  • Transactions should, ideally, not cross aggregate boundaries.
  • There can be inconsistencies between aggregates; use domain events to update aggregates in a separate transaction.

Aggregate

Aggregate is the most complex tactical design pattern in the domain-driven design.
Aggregate is a cluster of entities and values. Basically, these objects are viewed together as a unified whole from a data modification perspective. Every aggregate has a specific root and border; and, within this specific border all the possible invariants should be satisfied.
All requests to aggregate should be performed through its root. Root is a specific type of entity that has its own global, unique identifier. All inner objects of aggregate only have a so-called local identity but can refer to each other without limitations. External objects can store only a link to a specific root, not to inner objects.
Invariant is a business rule that always preserves its consistency. This consistency is often called an atomic transactional coherence. However, there is a so-called overall coherence as well. In case of invariants, transactional coherence is used. A transactional coherence border can also be named aggregate. This border stores all the invariant rules regardless of the performed operations. If you want to specify aggregates in bounded context, you need to analyze the actual invariants of the model in order to figure out which objects to bundle into aggregate.
When you need to design aggregates, pay attention that small-cluster aggregates are better than large-cluster aggregates in terms of performance and scalability. To upload a large aggregate, you need to have more memory. Meanwhile, smaller aggregates not only work much faster but also improve transaction performance. It is more desirable to use value objects, not entities within aggregate. Value objects are much easier to support and test (as I mentioned above).
Every aggregate can store links as roots of other aggregates. However, it doesn’t place this aggregate into the coherence borders of the first aggregate. A link doesn’t establish a comprehensive aggregate.
Within the context of transaction in bounded context, only a single aggregate should be modified. It is preferable to create links using global identifiers of aggregate root. You shouldn't store direct links as objects or locators. By this, you decrease object memory, allowing them to upload and scale faster.
If a user’s request has to do with several aggregates, rely on the overall coherence principle. You can achieve the overall coherence by publishing domain events. Basically, when aggregate is modified, it publishes an event that causes other aggregates to complete the action and maintain the system’s coherence.
To demonstrate that principle, look at the credit report below:
Every credit report needs to include a credit user’s ID data. Use customerId to save & store external linkage by identifier. Customer is an independent aggregate that preserves all the info about the credit user (name, address, contacts). Let’s say that credit rating estimation rule is used as invariant and is modified based on specific data stored in the credit history. It is not important how this credit rating is calculated or estimated; what matters is how transactional coherence within aggregate is achieved. For example, when the credit history is somehow modified, credit score should change too. This should be an atomic operation. If you use a database, it makes sense to create an independent transaction. As soon as any changes in the object's' data within aggregate are made, invariants should be activated and applied.
Inquiry is a specific credit score request from third-party organizations. Aggregate root is an entity and has a global identity. If you should link to this aggregate, you will be able to use only an identifier root. In case you delete a credit report’s aggregate, all values are deleted.

What are Aggregates in Domain Driven Design?
As an application begins to grow in complexity, the web of interconnected Entities and associations can begin to get overwhelming. What was once a simple set of Entities and relationships is suddenly a sprawling mess of objects and associations.

When the number of interconnected objects increases, so too does the surface area for interacting with those objects. Certain objects will have child objects, and those objects will have further related objects.

Domain Driven Design is all about allowing the model to drive the direction of development. When the complexity of the object graph inevitably becomes overwhelming, it’s time to take a closer look at the model to understand how to resolve the issues.

Aggregates are a way to calm this complexity by reducing the web of connected objects into a single unit. In today’s article we’re going to be looking at Aggregates, how they work and why you would want to use them in a Domain Driven Design project.

The problem of complexity
When code becomes too complex, bugs can creep in through ambiguity.

In a simple application, all objects will have equal precedence within the application. For example, if we were creating a forum application, we would probably have Thread, Post and Reply objects. Each Thread would have child Post objects and certain Post objects would have Reply objects.

When all objects have equal precedence, we could very easily select any of these objects straight from the database using their unique id:

$reply = Reply::find(4526);  
However, what about the rules of our application? If only certain users can post in a Thread how do we prevent them from adding a Reply object to a Post? What about when a Thread is deleted? How do we deal with all of the child Post objects and their Reply objects?

Looking to the model for answers
In any non-trivial application, there is likely going to be a lot of rules around how the objects should interact and coexist together. In reality, these objects should not have equal precedence in the application.

A Post object only really make sense in the context of a Thread because we can’t have a Post without a Thread, and we definitely can’t have a Reply without a Post.

When all objects have equal precedence we have created a massive interface for interacting with those objects. However, when we actually take a closer look at the model we are building, it does not make sense for those objects to be globally accessible. If an object shouldn’t appear outside of the context of it’s parent, we have no business having access to it in isolation.

Aggregates are the answer
An Aggregate is a cluster of associated object that we treat as a single unit. Each Aggregate has a single root Entity and a boundary that marks what is inside and what is outside of the Aggregate.

The root Entity is the only Entity that is globally accessible in the application. In the example from above, Thread would be the root Entity.

Inside the boundary we would have all of the associated objects of this Aggregate. For example, we would have the Post and Reply Entities as well as any other Entities or Value Objects that make up the Aggregate.

The Post and Reply objects can hold references to each other internally to the Aggregate, but no other external object can hold a reference to any object internally to the Aggregate that is not the root Entity.

The only way to access the Post and Reply Entities is to retrieve the Thread root Entity and traverse it’s associated objects.

The benefits of using Aggregates
To fully appreciate why you would want to structure your application around Aggregates, I think its important to first understand the benefits of using them. Without understanding the benefits, Aggregates can seem a bit like a needless artificial constraint in your code.

I think there are basically 3 benefits to using Aggregates.

A simple interface
The first big benefit of Aggregates is that it greatly reduces the interface you have to a certain segment of your application.

Imagine it’s your first day on the job of our imaginary forum development project and you’ve been tasked with making a change to some existing functionality.

Having unrestricted power to manipulate any object in the application is only going to lead to bad things happening. Without the constraints of an Aggregate a developer without the understanding of the business rules of the application will likely break those rules or expose an object that should not be exposed.

By having a single point of entry to the Aggregate, we can constrain access to the internal objects and maintain the harmony inside of the boundary. Having a single point of entry also makes it much easier to work with the code for the first time because there is no ambiguity of how you are supposed to access the child objects of a parent object.

Maintaining the invariants
The real beauty of Domain Driven applications is the ability to model the business rules of the application through invariants. An invariant is a rule that must remain consistent.

For example, if there was a business rule that stated only users who had posted in a thread could reply to other posts, we would be able to maintain this rule through the constraint of the Aggregate.

Maintaining the invariants of a unit of objects would be difficult without the constraint of the Aggregate boundary. If we didn’t have the boundary it would be very easy to simply create a new Reply and associate it with a Post.

Instead, the Thread can be in charge of deciding whether a Reply is valid or not, and so any attempt to circumvent this rule would be stopped.

Removing Objects
A common problem when building web applications is how to safely remove objects. When we don’t have constraints around what objects can be associated with other objects, this can start to become scary.

For example, if we didn’t restrict the associations of the application and we wanted to delete a Thread, how could we be certain that we wouldn’t be breaking other associations by cascading through the relationships of the Thread?

If we were to delete just the Thread we would be leaving lots of Post and Reply garbage objects in the database that no longer had context within the application.

Using Aggregates removes this problem because all objects within the boundary of the Aggregate are forbidden from being associated with any object outside of the boundary. This means we can delete the Thread and all of it’s internal associated objects without being scared of breaking associations across the application.

Conclusion
Thinking about your application as a set of main Aggregates can really clarify your thought process when designing what you need to build. Aggregates attract responsibility and capture a lot of the nuances of an association between two objects so it is not lost in complexity.

Now of course, there will always be ways to circumvent the constraints that an Aggregate puts in place. But I think the process of identifying and modelling your application in terms of Aggregates can really help distill the problem you are trying to tackle.

Using Aggregates also makes it a lot easier to make certain decisions. For example, it can be difficult to decide who has responsibility for creating and maintaining the relationship between Entities. When you identify and implement Aggregates you don’t have to ponder this decision because the model should have already guided you to the right answer.

So even if your next project isn’t a fully blown Domain Driven Design application, I would encourage you to start thinking about your code in terms of Aggregates and where the lines of responsibility between objects fall.

No comments:

Post a Comment