Modelling Aggregate Roots Relationships

By Mike on 18 October 2013

 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.

Comments (5) -

Moon
Moon
17 April 2014 #

Best explanation I ever read on this topic. It might sound stupid, but this post is better than the blue book's explanation. Thank you so much for the insightful write up.

Reply

Andrew
Andrew
13 August 2014 #

So in your example with Post and Comments, how could they be used together to be displayed on the page? Each comment has PostID and then some Service 'joins them' (Post and CommentsbyPostID) to be sent to the output? Or what would be other - better- way to solve this problem?

Quote: "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."  

But we do care at some other point. So it's not enough to know <what not to do>, but much more important to know <what to do>

P.S. Your 'need to know latin' captcha is so terrible, what probably most of comments aren't posted because of it... Frown

Reply

Admin
Admin
13 August 2014 #

Displaying on a page is part of a UI and it uses a view model which can be the result of a query handler/service . The Domain has nothing to so with it. Each layer has its own model , which resembles but isn't identical to the others. They serve different needs and they should be kept separated. It's about respecting Separation of Concerns.

P.S: You mean you haven't played Starcraft?

Reply

Andrew
Andrew
13 August 2014 #

So reading this post i made conclusion that instead of building Post object which has Comments (as array/list/collection) inside it, one should build Post object and then build Comments Collection and glue them together in the View. Because using the former way, you could immediately access Post in the view and render it, while later way would require some 'joining' and then rendering in the View. Is this what you ment to say?

P.S. No, ofcourse not. Why should I? There were much better RTS games at the time and now [*hint* TA /SupCom *hint*] Smile But the issue is that here it's case sensitive and if you miss one letter <r> then it's no go as well. And then you look at google and there are another 5 versions and they all are wrong so finally you give up. Except Me.

Reply

Admin
Admin
13 August 2014 #

From a domain point of view the Post and comments are separated, but working together. In the UI they are part of the same view model. If using CQRS, the comment's read model can have post id or a post can contain all comments (when using a doc db for example)

Reply

Pingbacks and trackbacks (1)+

Add comment

biuquote
Loading