Help, everything is an Aggregate Root!

2,018 views
Skip to first unread message

Dawid Ciecierski

unread,
Jul 31, 2012, 5:27:14 PM7/31/12
to ddd...@googlegroups.com
I know this sounds a little crazy just after you were all very helpful in another thread on this group, but as I'm going down the "split your Legos into different piles = subsystems", I'm also reshuffling stuff in my domain. And the more I do that, and the more I read on DDD, I'm feeling an urge to make almost everything an aggregate root. The Rules of Aggregate-rootness, ie. finding good candidates, are (among I'm sure others):
  1. If two components share lifetime (eg. Order and OrderItem), then they are a good fit to be part of the same aggregate.
  2. If, on the contrary, they have a much different lifetime, they should most likely be in two different aggregates (or be two ARs).
  3. Because outside is not to query for entities directly but only via ARs, what follows is that if outside needs something badly, then perhaps this something should be an AR?
I'm finding pts. 2 & 3 to be of concern especially with one-to-many relationships. Take the classic example of User and UserGroup. On the one hand, without users a user group does not neccessarily make sense, and so this might suggest that it's the user that is the AR. But then how do other systems that might need to fetch list of user groups on the system, obtain that information? After all, UserGroup is not an AR, and so not meant to be queried for from outside? Conversely, we definitely want to query for users direcly from an authentication and any user actions in the system (like assigning User to Customer). (I guess this could be overcome with some CQRS "trickery" and read views but I'm asking from a more general DDD standpoint.)

On a separate note: if it is the case that we only have 1-3 entities in our aggregates (so far), would you say that DDD is overdoing it, and perhaps we're looking at more of a CRUD app? On the other hand, there's one aggregate that is important from a business standpoint and whose consistency should be ensured at all times, and so DDD sounds like the way to go, also near-future-wise.

Will be interesed to hear your thoughs on that...

Regards,
Dawid Ciecierski

Kim Betti

unread,
Jul 31, 2012, 5:58:13 PM7/31/12
to ddd...@googlegroups.com
This was a very interesting and well phrased question. I'm trying to wrap my head around something similar so I hope you don't mind me adding something.

My gut feeling based on what I've read so far tells me that both User and UserGroup should be aggregate roots. The group aggregate probably won't contain any business logic requiring access to the actual user instances so it's probably enough to associate users by id from each group..? The read site can always be updated by a projection of user added / removed event. My concern is related to the user group life cycle (or lack of a one..). The relationship group => users is likely to grow without boundaries. It's not like a order that receives a limited number of events before it's shipped, billed and closed.

Perhaps the group shouldn't be an aggregate root after all? Or are there other ways of dealing with long lived entities like this?

Alistair Bush

unread,
Jul 31, 2012, 7:40:04 PM7/31/12
to ddd...@googlegroups.com
On Wednesday, 1 August 2012 09:27:14 UTC+12, Dawid Ciecierski wrote:
I know this sounds a little crazy just after you were all very helpful in another thread on this group, but as I'm going down the "split your Legos into different piles = subsystems", I'm also reshuffling stuff in my domain. And the more I do that, and the more I read on DDD, I'm feeling an urge to make almost everything an aggregate root. The Rules of Aggregate-rootness, ie. finding good candidates, are (among I'm sure others):
  1. If two components share lifetime (eg. Order and OrderItem), then they are a good fit to be part of the same aggregate.
  2. If, on the contrary, they have a much different lifetime, they should most likely be in two different aggregates (or be two ARs).
  3. Because outside is not to query for entities directly but only via ARs, what follows is that if outside needs something badly, then perhaps this something should be an AR?
I'm finding pts. 2 & 3 to be of concern especially with one-to-many relationships. Take the classic example of User and UserGroup. On the one hand, without users a user group does not neccessarily make sense, and so this might suggest that it's the user that is the AR. But then how do other systems that might need to fetch list of user groups on the system, obtain that information? After all, UserGroup is not an AR, and so not meant to be queried for from outside? Conversely, we definitely want to query for users direcly from an authentication and any user actions in the system (like assigning User to Customer). (I guess this could be overcome with some CQRS "trickery" and read views but I'm asking from a more general DDD standpoint.)

I guess that real question is how do Users become to belong within a UserGroup?   Do users Subscribe?  Or are they Invited?   Or are they really just Added?   Also is Authentication something your domain is interested in?   Are UserGroups an authentication/authorisation concern or a domain concern.

I'm not sure whether User and UserGroup are classic examples (I've never heard of it).  But what is the behaviour of both?   Could it be that User and UserGroup are a classic example of when NOT to do DDD.  It sounds like you might have some type of Party in your system so that you can assign that Party via a PartyRole to a Customer.  ( Look im just making this up now,  but hopefully in a way that makes you think ).
 

On a separate note: if it is the case that we only have 1-3 entities in our aggregates (so far), would you say that DDD is overdoing it, and perhaps we're looking at more of a CRUD app? On the other hand, there's one aggregate that is important from a business standpoint and whose consistency should be ensured at all times, and so DDD sounds like the way to go, also near-future-wise.

No that sounds about right.  Keep them small.   How many value objects for you have?

Hopefully this email makes you think more than it did me.

Alistair.

Greg Young

unread,
Aug 1, 2012, 2:43:11 AM8/1/12
to ddd...@googlegroups.com
> I'm finding pts. 2 & 3 to be of concern especially with one-to-many
> relationships. Take the classic example of User and UserGroup. On the one
> hand, without users a user group does not neccessarily make sense, and so
> this might suggest that it's the user that is the AR. But then how do other
> systems that might need to fetch list of user groups on the system, obtain
> that information? After all, UserGroup is not an AR, and so not meant to be
> queried for from outside? Conversely, we definitely want to query for users
> direcly from an authentication and any user actions in the system (like
> assigning User to Customer). (I guess this could be overcome with some CQRS
> "trickery" and read views but I'm asking from a more general DDD
> standpoint.)

If I were to use the Order and Order Line example, an Order Line has
no meaning outside of an Order.

A User certainly has meaning outside of a user group.

A question that can help with life cycles is "If I deleted this thing
would I cascade the delete?".

In the case of Order OrderLines would be deleted. Would you delete all
the users in a group when you deleted it?

Greg
--
Le doute n'est pas une condition agréable, mais la certitude est absurde.

belitre

unread,
Aug 1, 2012, 3:09:37 PM8/1/12
to ddd...@googlegroups.com
Dawid, take a look to Effective Aggregate Design series by Vaughn Vernon:  http://dddcommunity.org/library/vernon_2011 
Also there exist more guidance in the last book by Vernon: http://my.safaribooksonline.com/book/-/9780133039900

I don't now about similar guidance for aggregates implemented with Event Sourcing. During my "couple of months" experience, I have experienced much more "freedom" and "power" modeling business when using Event Sourcing. In spite of I still haven't found an ellegant way to separating behaviour and state management into several objects within the same event sourced aggregate. We tend to model all state management (event handling) in the same object.

Good luck :-)

@yreynhout

unread,
Aug 1, 2012, 4:44:16 PM8/1/12
to ddd...@googlegroups.com
You might wanna checkout Ravi Sandhu's work on RBAC to better understand the why of user management (http://modelibra.googlecode.com/svn/trunk/Modelibra/doc/security/sandhu96.pdf). A bit outdated but very inspirational.

Dawid Ciecierski

unread,
Aug 2, 2012, 3:11:03 AM8/2/12
to ddd...@googlegroups.com
First just to answer some of the valid questions you raised:

@Kim: true, in this case UserGroup is a kind of long-lived entity. But then isn't it the case with Users, Customers and others? They rarely disable their accounts (if are allowed to at all) too. In this particular case thou, and after consulting our Domain Experts, we're aiming for a user to be able to be part of multiple user groups, which may be created and deleted at will (eg. users who deal with vip clients, users available over the weekend, etc). This seems to suggest that in our domain Users might be more imporant than UserGroups, but of different lifetime (= two ARs).

@Alistair: User and UserGroup being classic not in the DDD-sense, but most (if not all) of the systems we create over here tend to feature these two guys in one form or another. It's may not be the case in other domains, so perhaps I made a sweeping generalization too eagerly. Other than that: that was a lot of questions :-) Very valid ones too. In our case Users are assigned to UserGroups by admins, and UGs have no part in authentication / authorization. Only some algorithms in the system make use of them (like "if vip customer then assign it to one of the users from 'experienced users' group"). So it seems we're dealing with the simpler, manual case rather than Party-type relationships.

@Greg: Brief and to-the-point as usual :-) I liked your idea of considering if a delete should cascade when looking at lifetimes, it makes a lot of sense to my still-ORM-wired brain. In our case, no, as users groups can be created ad-hoc on an as-needed basis, and since users can be part of 0..n UGs, we definitely would not cascade a delete either way.

@Javier: I went through Vernon's series twice before, but for me it's only once I start practicing something that doubts and other thoughts begin to creep in. (Guess Vernon could be like poetry, read over and over again at different stages in your DDD life to deepen your understanding of the subject, much like the Blue Book!) Thanks for reminding me to read it again thou.

@Yves: It talks about the advantage of roles as opposed to groups, which is a very valid point. Hoever, in our case we're going to have both. Roles for authorization, and groups for... well, bunching users into groups like 'experienced users,' 'available over the weekend' etc.

To sum up some of the thoughts and our own revised understanding of the domain.:
  1. In our case, UserGroup is definitely a domain concept and external to Roles; one that will be used by some of the domain logic, eg. when round-robin distributing new clients to users from a particular group.
  2. After consulting with domain experts, we now have that UserGroups may be created on an ad-hoc way, and Users may be part of multiple UserGroups at the same time.
  3. What follows is that we would never cascade a delete either way. We therefore conclude they have different lifetimes.
  4. Because they share different lifetimes, they are two different Aggregate Roots.
  5. Implementation detail: as a consequence of U and UG being two ARs, and as suggested earlier by Eric Therond, we only keep List<Guid> UserIds on UserGroups.
It is all much clearer now, and the forest of Aggregate Roots we're surrounded by feels a lot less scary. Thank you for your hints and suggestions, as always they induce thinking, which leads to a deeper understanding of the domain. That in turn makes general rules applied to our domain look a lot more reasonable and exactly the strategies the problem called for.

And apologies for rather lengthy posts, I appreciate you taking the time to help me on my DDD ways all the more.

Regards,
Dawid

Philip Jander

unread,
Aug 2, 2012, 4:44:33 AM8/2/12
to ddd...@googlegroups.com

@Greg: Brief and to-the-point as usual :-) I liked your idea of considering if a delete should cascade when looking at lifetimes, it makes a lot of sense to my still-ORM-wired brain. In our case, no, as users groups can be created ad-hoc on an as-needed basis, and since users can be part of 0..n UGs, we definitely would not cascade a delete either way.


  1. Implementation detail: as a consequence of U and UG being two ARs, and as suggested earlier by Eric Therond, we only keep List<Guid> UserIds on UserGroups.


Depending on what business rules you have for users which are members of a group, there might be two additional entities involved:
For rules affecting the behavior of Usergroups to which users belong, the Usergroup might have Member entities,
and/or for rules affecting the behavior of Users belonging to a group, the User might have Membership entities.

Sometimes, you find that those entities are better container for the rules than the plain User or Usergroup entities with just a List<Guid>.

Again the standard DDD/CQRS disclaimer: it all depends on your requirements ;)

Cheers
Phil

Dawid Ciecierski

unread,
Aug 2, 2012, 6:38:39 AM8/2/12
to ddd...@googlegroups.com
Yes, I've come to love-hate this old DDD adage :-)

Good point you're making, somehow it did not occur to me that we could employ relationship objects in the mix! I'll need to think about whether it makes sense within our domain; on first sight we don't have a need for start/end dates or any other additional info, but perhaps it's best to put this question to the business owners + domain experts just in case.

Best,
Dawid

belitre

unread,
Aug 2, 2012, 12:47:06 PM8/2/12
to ddd...@googlegroups.com
Just trying to complicate things a bit more... UserGroup could be an Aggregate/Entity in the BoundedContext where UserGroups lifetimes are managed, but UserGroup can also be a Value Object in other BoundedContext where it is used to track points earned by a group through participation in a contest (just a simplistic example to illustrate the idea).
Reply all
Reply to author
Forward
0 new messages