Reputation: 31
I have a design problem in my project.
To simplify things, I'll take as an example Vaughn Vernon's forum project, which advocates the use of small aggregates rather than large ones. Because that is my problem.
Projet de Vaughn Vernon : https://github.com/VaughnVernon/IDDD_Samples/tree/master/iddd_collaboration/src/main/java/com/saasovation/collaboration
Vaughn Vernon forum model :
So to create a Discussion on a Forum, Vaughn does that :
Forum {
startDiscussion(title) {
return new Discussion(this.id, title)
}
}
Then, to post into discussion, he does that :
Discussion {
post(message) {
return new Post(this.forumId, this.id, message)
}
}
I think that's really cool, it makes sense from a business point of view.
According to its code, Forum can be closed, however, you can still create discussions and post. I also find that strange...
If I want to avoid starting discussions in a closed forum, it would be easy :
Forum {
startDiscussion(title) {
if (this.isClosed) {
throw new Exception("Cannot start discussion: forum closed")
}
return new Discussion(this.id, title)
}
}
Now, if I want to avoid posting in a discussion whose forum is closed, how can I do ?
Apart from using a large aggregate, I don't see how to do..
I had thought of using a service :
Service {
Post = postToDiscussion(forumId, discussionId, messageToPost) {
forum = forumRepo.get(forumId)
if (forum.closed) {
// throw Exception
}
discussion = discussionRepo.get(discussionId)
return discussion.post(messageToPost)
}
}
As there is a business rule, this service cannot be an Application Service, right?. A Domain Service then?
I am very surprised that such basic problems can become so complicated to implement in DDD..
Thanks for enlightening me :)
Upvotes: 0
Views: 181
Reputation: 79
Instead of passing just forumId
to postToDiscussion
method, pass the whole Forum
aggregate. It is ok to fetch and additional aggregate in the application service in order to fulfill the domain logic and check some business rules.
Upvotes: 0
Reputation: 2857
You can use events. When a forum is closed, publish ForumClosedEvent. Then handle that event anywhere you need to react to it. You can identify this type of requirements because they are usually worded like "When X happens, then Y should happen", where X is a business operation that will be represented as an event. For example, "When a forum is closed then all related discussions should be closed".
Note that Forum and Discussions will be eventually consistent, as there'll be a length of time when the Forum is closed but the related Discussions are still open. Make sure that you handle this situation accordingly. Many times, you don't have to do anything, in other cases, you have to execute some compensating actions. Don't assume that everything has to always be strictly consistent, real life is not transactional anyway.
Upvotes: 1