|A better word for Aggregate Root|
The core activity of DDD is building a model, in a team together with developers and domain experts. Good communication between those two groups is essential. Modeling implies defining a common vocabulary. A very specific DDD jargon is not very helpful in that communication and should be avoided. Words like “ubiqitous language”, “bounded context” or “aggregate root” are not inviting non-insiders to share their domain knowledge; I've seen people being scared off by the use of those strange words. In part 1 of this series I investigated the concept of "bounded context". In this second part I propose an alternative for “aggregate root (AR)”.
In the DDD literature the words “aggregate” and “aggregate root” (often abbreviated to AR) are used very frequently. They are core concepts. For developers they sound familiar and are the logical consequence of working with groups of objects, respecting the Law of Demeter and Tell, Don't Ask, while guarding invariants. We have used those terms for decades, from the times we mainly worked with ERDs and ORMs. But for non-technical team members those words are strange jargon.
Learned from DCI
In DCI (Data-Context-Interaction, see http://fulloo.info/Documents/) the behaviour of objects is specific within the context of a use case: the objects are said to play a “role” in that context. Just like a person has different behaviour playing different “roles” in daily life (for instance as a developer, as a customer, as a mother, as a lover). In a DCI context all the behaviour is gathered that is needed to enact a use case. The roles form invariants in the use case. A context in DCI is comparable to an aggregate in “our” DDD. The behaviour of the roles is comparable to the interface of the aggregate root. Of course there are differences, for in class-oriented programming you cannot easily add behaviour to objects at runtime. But broadly speaking, looking at the similarities instead of at the differences, a DCI context is comparable to a DDD aggregate. An interesting aspect is that the origin of an aggregate is structural (some coherent objects), coming from a data-centric era of development, while a DCI context is mainly based on behavioural coherence, like the concept of invariants is.
One of the good things of DCI contexts is that they correspond one-on-one to use cases. In the 2010 book “Lean Architecture for Agile Software Development”James Coplien and Gertrud Bjørnvig show how well use cases support Agile development. They are good tools for incremental delivery of business value. And they are also familiar concepts for the persons with domain knowledge: we can easily communicate about a succes scenario and alternative scenarios that form a full blown use case. And the focus is immediately where it should be: on the behaviour.
That's why I prefer “use case” above “agregate root”.
It is nothing new that an aggregate root as used in DDD corresponds to a use case. Here are for instance some quotes from Scott Millett's book “Patterns, Principles and Practices of Domain-Driven Design” (2015): “When defining aggregates, you need to identify objects that work together and must be consistent with each other to fulfill business use cases” (page 444), “strive to modify a single aggregate per use case” (page 446), “justify each grouping and ensure that each object is required to define the behaviour of the aggregate instead of just being related to the aggregate”(page 449) and “Focus on modeling aggregates from the perspective of your business use cases” (page 449). However, in “Implementing Domain-Driven Design” (2013) Vaughn Vernon warns us for blindly trusting every use case (page 358-359), but apparently he sees use cases mostly as the product of business analysts, where I see the use cases as emergent from the modeling process, by the joint efforts of the team of developers and domain experts. So be careful with the word “use case” as it has a slightly different meaning for different people. For me a use case is the space between some blue and orange stickies of commands and events in a model storming session; what usually is called an aggregate.
I have a slightly different naming convention for use cases in comparison with aggregate roots, reflecting its behavioural nature: I often use the present participle. It is the place where things happen. The name also mostly fits with the name of commands and events. I get a sequence of command → use case → event: register → registering → registered, pay → paying → payed, etc. (mostly more verbose, including the name of the main object in the name of the command, use case and event, like registerMember etc., but you get the idea). This naming convention shows what is being done in a use case as opposed to the more static name of an object when naming an aggregate root. A use case is more about what the system does (behaviour) than what the system is (structure).
Domain object in multiple use cases
So in my models I treat use cases as first class citizens. Technically seen the use case still is the root of an aggregate, containing all objects involved in the use case. Its methods are not part of one of the domain objects in the aggregate, but of the use case itself. Unfortunately in class-oriented programming we cannot easily add methods to objects at run time, like in “pure” DCI. But we do have all methods belonging to the use case together in one (use case) object. That prevents adding methods to classes for objects that are used in multiple use cases. For instance if a Member would be an object in a registeringMember use case, and that member object would also be used in another use case in the same model (in DDD jargon: within the same Bounded Context) then we can now use that member object in the other use case without the registering methods. The registering methods are only applicable to the member object within the registering use case. I'm aware that this is opposite to the goal of giving domain objects “rich behaviour”, but it has the advantage of having all use case specific behaviour together in one place. It is more in the direction of functional programming (composing behaviour) than object oriented programming (emphasising structure, like relations between objects).
In his 1965 essay “A City is Not a Tree” Christopher Alexander shows the “real world” is too complex to divide it in mutually exclusive concepts. There is a lot of overlap and interference. In DDD we experience that when using multiple models (in DDD jargon: multiple Bounded Contexts) that use the same word for a concept in a different context. For instance a product in the context of a sales model, an inventory model, a fulfillment model etc. Within one model we have a consistent meaning for the name of a domain object, but it can still be used in different use cases, each with different invariants and behaviour. Explicitly naming the use case as such takes away the problem that object behaviour from another use case is part of some aggregate root. I'm still looking for concrete cases, but I guess that in current DDD practice such cases are sometimes solved by adding an extra Bounded Context (although the meaning of the used domain objects is in fact the same and so they should belong to the same model).
I don't have to use technical terms like “aggregate” and “aggregate root” in modeling sessions. We model use cases, consisting of scenarios handling success, failure or edge cases, being invoked by commands and resulting in events. Clear and immediately understandable, also for non-insiders of the DDD jargon.
(last edited: September 1, 2016)