Home > Net >  Best practice on determining an aggregate root vs child entities (DDD Modelling)
Best practice on determining an aggregate root vs child entities (DDD Modelling)

Time:11-26

I am attempting to model a set of entities and am seeking best practices on determining if a domain object is a candidate for an aggregate root or as a list of child entities under another aggregate root.

I have a Game object that represents a played game of a generic sport. The Game aggregate currently has a list of child entities titled GamePlayers. These GamePlayer entities also have a list of child entities titled GamePlayerHits which record where a player was hit during a game of this generic sport.

Methods exist on the Game aggregate such as AddPlayer() and RemovePlayer(). The child entities under GamePlayer of type GamePlayerHit also have methods such as AddHit().

The problem I'm facing is whether GamePlayers should be an aggregate root of its own with a reference to the Game entity. A Game can technically exist without a list of GamePlayers initially, at some later stage it may get populated. The Game could also be deleted or cancelled without any players ever being registered. This leads me to believe that GamePlayers should be it's own aggregate based on examples I've see online.

This is the example where I began to question the best practices surrounding this subject:

https://github.com/kgrzybek/modular-monolith-with-ddd

Here, the Meetings aggregate has a list of child MeetingAttendee entities however the Meetings commenting feature MeetingComment is it's own aggregate with a reference back to the Meeting it belongs to. For ease of referencing:

The Meeting class with MeetingAttendee child entities

The MeetingComment class as it's own aggregrate

In this example why is MeetingComment not a list of child entities under the Meeting aggregate with a suitable AddComment() and DeleteComment() methods on the main aggregate? My assumption is either comments are optional and are not required to validate the aggregrate and/or these entities need referencing elsewhere via an identifier/key which wouldn't be possible as being a member of a child collection.

How does one determine taking in to account my example above regarding games which is the correct way to models these aggregates and entities? What determines if entities should exist as child entities or as a separate aggregate root?

CodePudding user response:

How does one determine taking in to account my example above regarding games which is the correct way to models these aggregates and entities? What determines if entities should exist as child entities or as a separate aggregate root?

The existence of a domain constraints connecting information.

If all we needed was to capture a bunch of information provided to us, we wouldn't need a domain model; a database is more than adequate for data capture.

We introduce the domain model because either (a) we need to ensure that new information is compatible with information that we have already captured and/or (b) there are derived values that we want to compute locally (ex: because computing them locally reduces the error rate).

Rule: If we have a constraint that must always hold, and that constraint spans multiple pieces of information, then that information must all be contained within a single "aggregate".

The justification for the rule: information subject to a constraint like this must be changed atomically. In other words, we want all of this information to be part of a single unit for the purpose of data changes. Therefore, the domain entities that manage this information must all be part of the same "aggregate".

In the cargo shipping example taken from the blue book (Evans, 2003), we have a constraint on the misdirected property of a shipment: it must be true if the most recently recorded handling event for a container is inconsistent with the most recently assigned itinerary. It follows that these three pieces of information must be stored atomically (otherwise we risk inconsistencies in our stored data), and therefore that the domain entities that manage this information must all be part of the same aggregate.

I tend to imagine a graph - the data are nodes, and each constraint implies edges connecting the data subject to that constraint. Our rule then becomes "every graph must be contained entirely within a single aggregate".

A single aggregate can contain more than one of these graphs, but in doing that you are also introducing contention that is not inherent to the domain -- this is one of the forms of "accidental complexity".

  • Related