This is the 3rd part of my series about event sourced aggregates. In the first post I outlined a typical implementation of event sourced aggregates, and in the second post I showed how that implementation leads to aggregates that grow bigger and bigger as features are added to the system. In this post I will clean up the command handlers from the previous post by moving some repeated code out them to a new abstraction. In the coming posts I will refactor between the command handlers, aggregates and event handlers to arrive at a design where the aggregate does not grow.
Repeated code in command handlers
In the last post we looked briefly at this implementation of a command handler:
Looking at the above the code at line 20 is - in a sense - where the ChangeUsernameCommand the is handled, because that is the only line that is about changing a username. All the other code in the command handler is about infrastructure; loading the aggregate, saving the aggregate and dispatching events. Moreover the code for loading and saving aggregates as well as the code for dispatching will be repeated in every command handler
Introducing a helper
To get past that repetitiveness and to cut back on the amount of infrastructure code in the command handler, we introduce this helper, where the loading of the aggregate, the saving of the aggregate and the dispatching of events is done:
The idea behind the CommandHandlerHelper is that the concrete command handler calls the Handle method with a handlerFunc, that does the business logic bit of the command handler. The handlerFunc is called at line 18, so the helper makes sure the infrastructure code is done in right order in relation to the business logic.
Cleaner command handlers
With the CommandHandlerHelper in place the ChangeUsernameCommand can be rewritten to use it like this:
This is a good deal simpler than the command handler code at the start of the post.
That's it for now. With this clean up in place we set for the next steps:
Make the command handlers smarter
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