Saturday, October 18, 2008

Are Aggregates Practical?

My coworker Jörg Jenni from GARAIO reflects in his recent post on how his team is implementing aggregates. I worked with him and his team for a few months so I know how their current implementation looks like. To be honest I was one of the developers that had problems to follow the rules that come with aggregates.

From Evans, the rules we need to enforce include:
  • The root Entity has global identity and is 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.
  • 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.
Especially the "do not hold a reference from the outside to an object inside the aggregate" rule is very strict. Jörg suggests in his post to implement aggregate internals as private classes in the root class. With this approach sure you will not violate the rule anymore as the compiler enforces it. The problem is that at some point you will need access to these objects even if they are identified as conceptually internal. For example as a client I need a reference to these internals to show some information on a screen, to test the logic of the internal object or to execute some business logic that needs knowledge of data and behavior of objects in the aggregate.

Don't understand me wrong, I really would love to apply this pattern. The essence of aggregates to identify a cluster of objects that can be conceptually thought of as one unit is very important for managing complexity. But is it practical in our today's programming model? On the domain driven design discussion board I found an interesting discussion about aggregate boundaries between DDD adopters and Eric Evans. From the discussion I see that we're not the only ones that have problems with the implementation of aggregates. And what's interesting is that in the same discussion Mr. Evans wrote that he'll try to add a concrete example and that he we'll come up with some useful new insight - he didn't return to the discussion.

Does anybody has a real world example of aggregates? One that enforces all the rules?

2 comments:

Anonymous said...

I wanted to reflect more about the code-metrics of our project than about the aggregates itself in my last post. However I would like to give you an example of what I like and what I don’t like in how we implement the aggregate pattern:

What I like for example: repositories and aggregates build together a single concept. It’s clear that when I need an aggregate (e.g. person) I get it from the repository (e.g. person-repository). Query-logic is pretty good encapsulated in the repositories and we have found a good place to do some more advanced mapping (e.g. enrich the user-object with information from the active directory).

I don’t like that we are too tight coupled to the database model. We don’t take advantage of more advanced mappings; therefore our database model is always present. Why I need to instantiate a new address-object and than add it to address-collection of the person? Why I can’t just write person.SetNewAddress(“Cathedrale Square”, new DateTime(2009,1,1))? In my trial, which I mentioned in my post, I found out that I had less code at the end.

I was just watching at the ‘Muenzliste’-implementation that I liked very much because things like that is what we need. But we could go ahead and separate the database-model from the domain-model and make out of the ‘Muenzliste’ two classes. One represents the database-model the other class is a value-object returned by the aggregate root. We still would access it via get;set on the aggregate root, but the design would clearly indicate what functionality is important on the presentation layer.

The discussion about DDD shows in my opinion that there is no general rule :-(. There is always more than one solution to solve a problem, but I think the design should clearly state what solution was chosen. I think the aggregate pattern is at least a valuable guidline that helps us to structure our domain-logic.

Marco Studer said...

Yes, you're right, it's a valuable guideline. I would even say it's not a design pattern, as it lacks of implementations