Picking Aggregate Roots - Domain Driven Design

I’m steadily thinking more and more in terms of Domain Driven Design.

I had often found it tricky to pick the domain object that should become the Aggregate Root.

I always try to bear in mind that Eric Evans says “Provide REPOSITORIES only for AGGREGATE roots that actually need direct access”.

So, if I am deliberating between two objects - I often find it handy to write down, by hand, a few example method calls that I might want to use on the repository.

It can be surprising to discover that the object most suitable to become a root is not the one you first think of.

Another thing that I am discovering is -  where I used to have a shallow class that describes the ”type” of something, it can often end up becoming an aggregate root.

E.g I found recently that I was planning to pull a collection of ”classifications” from a classification repository. But always had to pass a TypeOfClassification object to do so (because it was difficult to lump “every type of thing that there is” into the one, single, taxonomical scheme - hard though I tried). Furthermore I foresaw that the planned repository would have to constantly delegate implementation to a strategy based on the TypeOfClassification I was trying to pull. Upon re-thinking i made ”ClassificationScheme” into the aggregate root and plan to build a ClassificationSchemeRepository that returns a ClassificationScheme that can be queried for individual classifications as VALUE OBJECTS. I feel a lot more comfortable with that.

I worked it out by comparing the two kinds of repositories that i would need. Basically if i wanted to get hold of a classification object (or taxon as i call it) here were the potential method calls that depended on my choice of Agg Root:

Looking at my choices

If  Taxon was an aggregate root:

$taxon =  $taxonRepository->findTaxon($taxonomicalScheme, $taxonId);

OR - If TaxonomicalScheme was Agg Root:

$taxonomicalScheme = $taxonomicalSchemeRepository->findTaxonomicalScheme($taxonomicalSchemeId);
$taxon = $taxonomicalScheme->getTaxon($TaxonId);

—–

I prefer the second option because:

  • If I delete a taxonical scheme - do the taxons go with it? YES. (I was finding that hard to grasp considering that so many other objects hold references to a taxon - they classify things after-all). Everything that references them would have to observe the occasion, but YES the taxons would go or move somewhere else (remember: move = copy, then delete original). Also, if i think of taxons as VALUE OBJECTS then any references are just held values and not actual object references.
  • The chances of getting a NULL taxon are much higher than getting a NULL taxonomicalscheme. This seemed fishy for some reason.
  • I was wanting to get more information out of a repository than the object itself. If i had a NULL taxon I would wonder why. So, I was tempted to return a collection of taxons, every time. Just so I could interogate the collection if it contained no taxons. Then I extrapolated that to think - “a taxonomical scheme IS, in many senses, a collection of taxons, So hey. Why not get one of those out instead?”
  • I also envisage things like:

$taxon1 = $taxonFactory->createNewTaxon($criteria1) ;
$taxonomicalScheme->addTaxon($parentTaxon, $taxon1);

$taxon2 = $taxonFactory->createNewTaxon($criteria2) ;
$taxonomicalScheme->addTaxon($parentTaxon, $taxon2);

$taxonomicalSchemeRepository->commit($taxonomicalScheme);

Anyway - just saying “if you are agonising over a choice of aggregate root. Work out what the potential access methods would look like for each choice and see which feels better.” Its kind of obvious, but i was overlooking that procedure whilst my brain was frazzled by the infinite web of possibilities that were under consideration.

Leave a Reply