In the first post in this series I outlined a typical C# implmentation of event sourced aggregates. In this post we add a second feature to the example from the first post. In doing so I wish to illustrate how that typical implmentation leads to violation of Open/Closed principle and ever growing aggregates.
The second feature
Once we have the code from the first post in place - that is: The infrastructure for sending commands to aggregates, raising events from aggregates, saving events and replaying events - and need to add a second feature, the way to do it is (to some extent) as outline in the foirst post:
Send a new type of command
Implement a command handler for the new command
Implement a new method on the aggregate with the new domain logic
Emit any new events needed
Implement new When methods for any new event types
Let's say we want to be able change a users username.
The command and the sending of of that command looks like this:
That's pretty straight forward and not too interesting, so let's move on to the command handler:
That also pretty straight forward, but a little more interesting: Most of the the command handler code is something that will be repeated in all commands handlers. We will deal with this in the next post, where that repetition is pulled out into a helper class. The next step is changes to the aggregate, where this is added:
This is still pretty straight forward. In fact everything needed to add this new feature was straight forward, so that is a good thing. The problem lies in the last two methods, the ones added to the aggregate.
Problem: An Open/Closed Principle violation
The aggregate just grew. In order to support changing the username we added 2 methods to the aggregate. That violates the Open/Closed principle, which indicates that it is a potential problem. In my experience, it quickly becomes a real problem because the aggregate grows relatively quickly and eventually becomes big and complicated, just like any other class that grows monotonically.
That's it for now. The next posts will:
Make the command handlers smarter and clean up some repetitiveness
Make the aggregate anemic in a naive way, leaving a stable aggregate, but introducing a new Open/Closed violation
Make the aggregate anemic, events (a little) smart, and solve the Open/Closed violation