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 first 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's 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.
That's pretty straight forward and not too interesting, so let's move on to the command handler:
That's 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:
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
No comments:
Post a Comment