Modelling Aggregate Roots Relationships
One of the most important things when doing DDD is to model the aggregates, entities, value objects and their relationships the right way. And this is also one of the most trickiest things. In this post I’ll try to show you some examples of both superficial and proper domain relationships modelling. But first let me say this loud and clear: Domain relationships have NOTHING to do with and they are totally unrelated to database (persistence) tables relationships. And remember that when modelling the database (any type) doesn’t exist.
Keep in mind that when defining a concept, we care about what an entity or value object IS. Regarding a HAS relationship, it’s important to understand that the ‘has’ is about a component(child) required by the concept or a component that changes the parent’s behaviour. There can be also ‘work with’ relationships, where two ore more aggregate roots (AR) have a partnership, thus working together to achieve a domain use case.
But let’s start with an all time favourite, Post and Comments. Everybody knows that a post has comments, so it appears to make sense that the Post AR holds (acts as a container for) Comments. Leaving aside the technical “I need to load 1000 comments in order to add another one”, this is an example of superficial domain understanding. A Post doesn’t need comments in order to be exist as a Post . The concept of a Post is totally unrelated to the concept of a Comment. A comment is an user submitted message. Wordpress, Youtube and Facebook are using comments and the comment definition is the same, regardless the subject users are commenting on. Considering comments part of a post AR is like considering an advert part of the post AR, just because they’re both on the same page and the ad content depends on the post content. But modelling domain is ONLY about the domain concepts and processes; at this point we don’t care how some things are shown in a page or how they will be used together outside the domain.
Consider a table and chairs. When you go in a restaurant, you’ll see tables with at least 1-2 chairs nears them. You can say that a table has 2 chairs. But can you use a table without chairs? Yes. Can you use a chair without a table? Of course! The fact is that the table and chairs are working together in order to provide business value. The table’s “has” relationship is not with the chairs, it’s with the table leg(s). A table has 4 legs, because without them, it’s not really a table, it’s just a surface.
One of the ‘real’ parent-children relationship is when the AR needs those concepts as part of its definition. A Post has a title (which is a value object), but never has comments. Posts and comments are working together because you want to involve your readers and you’re using the post to give them an incentive to comment. If you’re putting comments inside a post AR, you’re treating the AR just as a container, breaking the Single Responsibility Principle and improperly modelling the domain. It’s like saying that a restaurant table needs to hold chairs inside it in order to be and act as a table.
Let’s look a bit at a smartphone. I will focus on 2 components of it: the SIM card and the battery. We can safely say that you can have a phone without a SIM card and a battery. SIM cards and batteries can exist without a phone. However, a phone without SIM card has some restrictions. A phone without a battery has A LOT of restrictions i.e it’s useless. A phone can work without a SIM card but it requires one in order to enable all its functionality. Of course, the lack of battery removes all the phone’s functionality.
These 2 components change the phone behaviour. A phone HAS a SIM card, because a SIM card is required in order to access the carrier’s network. A phone HAS a battery because, it needs a power source. The phone is a great example for an AR. Not only it has a lot of components, but it also acts as a facade for them. For example, if you’re like anyone else, you’ll tell the phone to dial up a number and the phone will use the SimCard to do that. If you’re a developer, you’ll ask the phone for the SIM Card and try to dial up the number yourself, somehow.. If you’re like everyone else, when the battery is depleted, you’ll plug the charger into the phone and the phone will take care of the details. If you’re a developer, you’ll remove the battery from the phone and try to charge it yourself, somehow…
Because the phone is the AR, it uses other domain concepts to do its work and exposes the relevant behaviour for that. Everything you need from that aggregate, you ask the AR (the phone). Some domain objects are hidden, while other are exposed (battery, simcard). The phone acts as a parent for all those objects and it requires them in order to be and behave like a phone.
However, the charger, the data transfer cable or the protective cover are not part of a phone. The phone works with a charger and it’s protected by a cover, although you will say that “the phone has a protective cover”. That “has” is not a domain “has” so it’s not a hint that the phone AR should have a property Cover.
In order for a domain object to be considered a ‘child’ of another object, the parent needs that child as part of definition or behaviour. If the objects represent domain concepts that only work together, they should be part of an use case.
If you find yourself treating an AR just a holder for other objects, then there’s 99% chance that you’re doing it wrong. AR are not containers, are ‘high level” concepts which encapsulate other, ‘lower level” concepts. ARs are collaborating with other ARs in order to provide business value. A Category concept can be defined as grouping posts according to a criteria. The Post AR and the Category AR are unrelated, but they have a collaborative relationship, where a Service can use a Category to group Posts. You can say that the Category concept defines an use case for Post.
In conclusion, don’t rush to code and don’t treat the Domain superficially. Even with a quite simple Domain like a post publishing engine, you can fall into traps. Make sure that you really understand the concepts and take you time to identify the the proper ‘has’ relationships.