Big Blue Series — 16 — Aggregating Objects into Domain Organisms

John Connolly
Domain Intelligence Today
5 min readSep 27, 2022
Photo by The Lucky Neko on Unsplash

You knew there was going to be a kitten photo at some point! I’ll reference that idea in a moment.

The goal of software in most instances is not to have a fully detailed model of the real world. If time and money were not to be considered, then maybe that would just be pure fun. I am sure it is extreme fun for those who are working on virtual reality solutions.

In most corporate, government, and non-profit domains, we are looking to build enough of the model, well defined and easy to manage, to serve the needs and processes we are automating or at least semi-automating.

When we look at the elements of design we have explored so far, from the wide lens of Domains and Bounded Contexts to the microscope of Entities, Value Objects, Services, and Events we start to get a sense that we have almost enough basic power to model the real world well enough to make extremely useful, durable, yet flexible systems. But something is needed to make it feel less like herding kittens. We need a basket. Something that can group the things we need into some logical grouping I am calling an organism.

Now, each kitten has value on its own and in the world of software up until Blue, it almost seemed like these baskets may or may not happen. If we had good objects we were fine. The issue came to be that we did not understand where many of these kittens came from, how related are these kittens anyway? We often suspected a stray entered the family and now that we have fed it milk long enough, well we cannot just send it out the door. Software and litters get messy.

Fortunately, we started to focus on Object Graphs in software at some point, then in Blue, Evans (2004), helped us to take it a step further to include special rules on graphs. One of these rules is that one of the objects gets to be the leader and there is no accessing data and capability without going through that object leader. Enter…

Aggregates and Aggregate Roots

In Blue, and now in software out there in the real world in some places, these graphs with leaders and rules are called Aggregates. The leader object is called the Aggregate Root. The great thing about this is, it is a lot like many living things we can think of. Aggregates follow a general real-world pattern in an abstract sense. Many living things have a head and a body. When the head is born, so is the body. When the head is in New York, so is the body. In old software the head might be in San Francisco when the body is in Amsterdam.

So, to keep the software from getting detrimentally disjointed Aggregates are basically constructed similarly to living things. Not a perfect analogy, but you get it if you are seeing that we can make organized cohesive Aggregates from Entities, Value Objects, Services and Events where they truly belong together to make an existential whole of a main Domain being. And, one of those, often an obvious but sometimes not so obvious Entity, is the head of that being.

Remember, there is no one right way to do this, but the closer you align your Aggregates to the way the Domain considers the Customer, then you are deliberately applying Domain-Driven Design conceptually in a tactical manner. You will sense the peace in this process when saving your Aggregate to a datastore just works out well. But I am getting ahead of myself.

Let’s look at a couple of examples that we can easily understand for now. “Customer” as an Aggregate is simple conceptualize in it’s basic form. It can get complicated. If we make a Customer Entity and choose that as the Aggregate Root for now, there are quite enough elements that really are part of the customer being that come to mind that would fit in that Aggregate. Let’s look at pseudo code to see what we can come up with:

Customer { 
CustomerId int,
FirstName char,
MiddleInitial char,
LastName char,
MailingAddress MailingAddress,
DiscountPlan DiscountPlan,
}
MailingAddress {
AddressLineOne char,
AddressLineTwo char,
City char,
ProvinceOrState,
PostalCode,
Country
}
DiscountPlan{
PlanLevelId int
AdditionalPercentDiscount decimal
}

Hopefully you get the picture that we could continue to add many things about the customer and then even take things in a different direction to have an Addresses grouping with mailing and shipping as separate Value Objects in an address list.

The key here, is that the Customer Entity is the Aggregate Root and if you want to get the mailing address or update the discount plan, you must call up this whole Customer Aggregate and then make those requests through that Customer Aggregate Root.

The idea is that you would not, in the model or the code representing that model, put the CustomerId on the DiscountPlan and then just call up the DiscountPlan by CustomerId and work with it all on its own. You might see that CustomerId in the database on that DiscountPlan, but that is a different topic for Database designers.

Sidenote, DDD does not stand for Database-Driven Design. :)

No Room for Giant Aggregates — Generally

When making the Customer, it might be tempting to put an “Orders” list as a member of this Aggregate with the ability to hold all of the Orders for this Customer, but the Order Entity is likely an Aggregate Root in and of itself. Generally, it is a bad practice to put an Aggregate Root inside of another Root. If there somehow seems to be a good reason to do it, then the model probably needs more refinement.

So how do we connect them? Generally, the Order Aggregate Root will have the CustomerId in the Root itself. This way if you needed a list of Orders by Customer, other than getting the CustomerId from the Customer Aggregate, you only need to worry about the Order Aggregates that matter to this Customer.

Also, you want to try to avoid massive Aggregate graphs as a rule. They take longer to create, save, send and more. There is no mathematical rule here. Just look to make things relatively easy to work with, small as needed and cohesively aggregated.

Aggregate Life Cycle

Each Aggregate lives, moves, gets stored, is quarantined, travels and is heaped into a trash can as a unit. It is important to remember this when designing Aggregations in DDD. Creating representations of these Aggregates and Storing them are coming up in the next couple of articles, but the idea is that at every stage of the life of an Aggregate they are living the Three Musketeers moto, “All for one and one for all!”

Until then…

I hope I see you in the next installment of — the Big Blue Series.

And remember, your cats may likely control you, but at least you can fully control your Aggregates!

Photo by Alex Carter on Unsplash

References

Evans, E. (2004). Domain-Driven Design: Tackling Complexity in the heart of software. Addison-Wesley Professional

--

--

John Connolly
Domain Intelligence Today

Domain-Driven Design Consultant. Passionately helping domain experts, architects and developers understand domain models improving product delivery.