DDD Tutorial - Modelling Domain Relationship and Domain Service

Written on 02 September 2016

This tutorial is an excerpt of the actual DDD modelling process of Value++ (Agile project management software) using Domain Map.

Business functionality: Remove a user from an organization

A quite straight forward functionality, however there is a little catch: an organization should always have at least 1 admin left. Basically, if the user is the last admin, the operation should fail (with an error message).

Modelling

The bounded context

We’re dealing with users and organization so, the relevant context is Membership (switch to it).

Applying CQS

The functionality clearly changes the business state, so we are in a Command case. Let’s create it in Domain Map, Add -> Command Use Case -> enter “Remove user from organization”.

Identifying the business state change

Well, the resulting change is about a (site) member who got removed from an organization. Add-> Event -> enter MemberRemovedFromOrganization . That’s our event and we need to find out the relevant details. Obviously, we need to know the member id and organization id. However, we need one of them to be the entity id, basically the id of the concept that the change is associated with. But both Member and Organization concepts are entities, so who is in ‘charge’? What concept ‘cares’ more about the operation?

It turns out the operation makes most sense for the Organization concept, so, the entity id will be the organization id. Click on the Events tab, then click on the new event to enter the details we’ve found out.

event

Identifying the aggregate

We know the result, but we need to enforce the business rules. First, we need to identify the aggregate, but in this situation we’re dealing with a weak relationship, we are ‘destroying’ an instance of that relationship and the aggregate should reflect that relationship, not Member or Organization. At this point, we don’t have that relationship represented in Domain Map so let’s create it now.

Click on the Entities tab, and then click on Organization. Then click on the “+” icon from the Relationships box.

dialog

Click on “+” from With Concept box then select Member. Let’s name this relationship “Members can be part of an organization”.

dialog2

Click “Create” and the new relationship should appear

dialog3

This relationship will appear on both Member and Organization details and the whole point is to acknowledge that these 2 concepts can be (dis)associated. However, this is not an aggregate, we still have to identify it and we do that as part of the current business case.

Click on Command Use Cases tab then click on Remove user from organization. Click “+” from Uses command model of and select the newly created relationship. What this tell us is that the command case will change an instance of the relationship and in this case, we ‘destroy’ it. And this aggregate will be in charge of that. Click on it to go to the details.

Inside the aggregate, you’ll see both (implicit) concepts: Member and Organization, then in the default outcome, select MemberRemovedFromOrganization.

agg

We’re done with the aggregate.

Using a Domain Service

But that’s not all! Remember the business rule that the last admin of the group must not be removed. So we need to enforce that and the best place is a Domain Service (DS). Why not a part of the aggregate, you ask? Because this rule is unrelated to the consistency of the relationship. It is an ‘outside” (the aggregate) rule so, we make it part of a DS. Even more, it’s a ‘permission’ kinda of rule, basically it tells the application service if the business case can continue. If not, it doesn’t even get to the aggregate part.

Add -> Domain Service -> enter: Can user be removed from organization . Then, go to the command case, click on “+” from Involves box to link to the domain service. Then click on the service name link to go to its details. In the Business behaviour box, write all the details that we need.

service

Well, I’ve kinda included a bit of implementation details here but hey, it doesn’t hurt anyone, especially if only developers (a domain modeller is usually one) will see it. But if you want to go even deeper with coding details (like “we should use a couple of query objects etc”), I suggest to put that in a note (the note icon next to the name).

Conclusion

This was a more complex case, but in the end we have our command case which involves a domain service (with all required details), we’re aware of a relationship between concepts and we know the aggregate and the event. Best part? No specific code was written, but with all this information available, it’s easier now to write an implementation using your favourite stack.

You can check out the model from this tutorial here.