While I was trying to apply DDD in combination with CQRS, I learned some good lessons.
I was trying to apply this in an agile approach, using the project method SCRUM. I started the project by translating all use-cases to smaller user stories. Based on these user stories, I defined a first sprint.
In the first sprint, I didn’t have or make a design for the complete domain. So I wasn’t completely sure if I made the right decision for the ‘aggregate root / bounded contexts’ needed for the first sprint. In the second sprint, I figured out it wasn’t the right choice so the second sprint took a lot of refactoring work. So I didn’t make it to the new userstories / functionality.
- So the first lesson I learned was... Before you start applying DDD, you have to identify at least the bounded contexts of your domain and define your aggregate roots. This will save you a lot of refactoring work. Last but not least, it gives you a good overview of the complete project.
When I defined by bounded context, I figured out I put some responsibilities on the wrong AR when I started to implement my designs. The lessons I learned here are.
- Just tell, don’t ask. This will lower the complexity and dependencies in your design. So use a domain service to tell one AR what he needs to know about another AR to make his decisions.
- In these domain services, you can use your readmodels to validate. This helps you to keep complexity low. So don’t hesitate to give up some consistency when the consistency isn’t a big deal.
To keep complexity low, I forced myself to keep properties out of my implementation. So the first question that came up to me was... How can I check if something has the right conditions when I can’t access them through properties. The solution was simple.
- Just use a
Guard method on the object who can make decisions and pass the dependencies to the method. When all conditions are ok, just do nothing, when they don’t, just throw an exception.
- Avoiding properties will help you in placing the logic in the right place, and prevents you from making some kind of ‘
God’ object / class.
Last but not least, I figured out dependency injection is the key to keeping dependencies as low as possible. In order to unit-test you domain scenarios. Because I write my unit-tests on commands and testing the resulting events, I rarely have to rewrite test when refactoring things in my domain. The only component that could be dependent on this are my ‘
CommandExecutors’. These ‘
CommandExecutors’ are injected into the framework as well as in my production environment as in my test environment.
So after a few weeks of applying DDD and CQRS, I already became a better architect, just by changing my mindset. I’m very impressed with the results I made to keep the code so simple for solving the, in first place, complex issues I was encountering.
By the way, I’m using the ncqrs framework. You can get a stable enough version from my fork at Github. However, the framework is still far from perfect. It saves you a lot of work. Everything that doesn’t fit can however be changed because the source code is opensource and it is really fun to participate and share thoughts about how it should be improved. So don’t hesitate to use this kind of framework, because the real issues you can only encounter when applying it in a real project. I think this is the only way to trace the points of pain and improve these kind of frameworks.
Hope you enjoyed this post. All feedback and additions are welcome, because learning never ends. Last but not least, I would like to thank the people who helped me to change my mindset.