[design-patterns] What's an Aggregate Root?

I'm trying to get my head around how to properly use the repository pattern. The central concept of an Aggregate Root keeps coming up. When searching both the web and Stack Overflow for help with what an aggregate root is, I keep finding discussions about them and dead links to pages that are supposed to contain base definitions.

In the context of the repository pattern, what is an aggregate root?

The answer is


From a broken link:

Within an Aggregate there is an Aggregate Root. The Aggregate Root is the parent Entity to all other Entities and Value Objects within the Aggregate.

A Repository operates upon an Aggregate Root.

More info can also be found here.


Aggregate means collection of something.
root is like top node of tree, from where we can access everything like <html> node in web page document.
Blog Analogy, A user can have many posts and each post can have many comments. so if we fetch any user then it can act as root to access all the related posts and further comments of those posts. These are all together said to be collection or Aggregated


The aggregate root is a complex name for a simple idea.


General idea

Well designed class diagram encapsulates its internals. Point through which you access this structure is called aggregate root.

enter image description here

Internals of your solution may be very complicated, but users of this hierarchy will just use root.doSomethingWhichHasBusinessMeaning().


Example

Check this simple class hierarchy enter image description here

How do you want to ride your car? Chose better API

Option A (it just somehow works):

car.ride();

Option B (user has access to class inernals):

if(car.getTires().getUsageLevel()< Car.ACCEPTABLE_TIRE_USAGE)
    for (Wheel w: car:getWheels()){
        w.spin();
    }
}

If you think that option A is better then congratulations. You get the main reason behind aggregate root.


Aggregate root encapsulates multiple classes. you can manipulate the whole hierarchy only through the main object.


In another world, in Event Sourcing, an Aggregate(Root) is a different concept. Event Sourcing might be encountered together with CQRS, DDD etc.

In Event Sourcing an Aggregate is an object for which the state (fields) is not mapped to a record in a database as we are used to think in SQL/JPA world.

Is not a group of related entities.

It is a group of related records like in a history table.

GiftCard.amount is one field in a GiftCard Aggregate, but this field is mapped to all the events, like card-redeemed (take money from the card) ever created.

So the source of data for your Aggregate is not a record in a database but the complete list of events ever created for that specific aggregate. We say we event sourced the aggregate.

Now we can ask ourselves how is it done? Who is aggregating these events so we are operating still with one field e.g GiftCard.amount? We might be expecting that amount to be a Collection and not a big-decimal type.

Is the event sourcing engine, doing the work, who might simply replay all the events in the creation order. But this is out of the scope for this thread.


Imagine you have a Computer entity, this entity also cannot live without its Software entity and Hardware entity. These form the Computer aggregate, the mini-ecosystem for the Computer portion of the domain.

Aggregate Root is the mothership entity inside the aggregate (in our case Computer), it is a common practice to have your repository only work with the entities that are Aggregate Roots, and this entity is responsible for initializing the other entities.

Consider Aggregate Root as an Entry-Point to an Aggregate.

In C# code:

public class Computer : IEntity, IAggregateRoot
{
    public Hardware Hardware { get; set; }
    public Software Software { get; set; }
}

public class Hardware : IEntity { }
public class Software : IValueObject { }

public class Repository<T> : IRepository<T> where T : IAggregateRoot {}

Keep in mind that Hardware would likely be a ValueObject too (do not have identity on its own), consider it as an example only.


In Erlang there is no need to differentiate between aggregates, once the aggregate is composed by data structures inside the state, instead of OO composition. See an example: https://github.com/bryanhunter/cqrs-with-erlang/tree/ndc-london


Dinah:

In the Context of a Repository the Aggregate Root is an Entity with no parent Entity. It contains zero, One or Many Child Entities whose existence is dependent upon the Parent for it's identity. That's a One To Many relationship in a Repository. Those Child Entities are plain Aggregates.

enter image description here


If you follow a database-first approach, you aggregate root is usually the table on the 1 side of a 1-many relationship.

The most common example being a Person. Each person has many addresses, one or more pay slips, invoices, CRM entries, etc. It's not always the case, but 9/10 times it is.

We're currently working on an e-commerce platform, and we basically have two aggregate roots:

  1. Customers
  2. Sellers

Customers supply contact info, we assign transactions to them, transactions get line items, etc.

Sellers sell products, have contact people, about us pages, special offers, etc.

These are taken care of by the Customer and Seller repository respectively.


From Evans DDD:

An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes. Each AGGREGATE has a root and a boundary. The boundary defines what is inside the AGGREGATE. The root is a single, specific ENTITY contained in the AGGREGATE.

And:

The root is the only member of the AGGREGATE that outside objects are allowed to hold references to[.]

This means that aggregate roots are the only objects that can be loaded from a repository.

An example is a model containing a Customer entity and an Address entity. We would never access an Address entity directly from the model as it does not make sense without the context of an associated Customer. So we could say that Customer and Address together form an aggregate and that Customer is an aggregate root.


Aggregate is where you protect your invariants and force consistency by limiting its access thought aggregate root. Do not forget, aggregate should design upon your project business rules and invariants, not database relationship. you should not inject any repository and no queries are not allowed.