This is part 2 of 5. The entire series is here:
This is post #2 in the series. I very much recommend you to read them in order, otherwise I’m pretty sure confusion will arise.. All the code for this step is found on the commands branch:
Commands and Command Handlers
Anyway, this is when we actually do something useful. Let’s introduce Commands!
A Command is simply a DTO-type of object that contains the data necessary for the service to make one specific change to the state of the system. As an example, the AddHotelCommand looks like this:
[github file=”/andlju/hotel-admin/blob/commands/src/HotelAdmin.Messages/Commands/AddHotelCommand.cs” start_line=”4″ end_line=”15″]
The commands are pushed to a simple Dispatcher who passes them on to an appropriate Command Handler:
[github file=”/andlju/hotel-admin/blob/commands/src/HotelAdmin.Service/CommandHandlers/AddHotelCommandHandler.cs” start_line=”7″ end_line=”38″]
No we need to make sure that the old Transaction Script methods are updated to publish commands instead of using repositories themselves. This is when we run into the first issue.
Have a look at the signature of the Remote Façade:
[github file=”/andlju/hotel-admin/blob/commands/src/HotelAdmin.Service/IHotelService.cs” start_line=”20″ end_line=”22″]
Spot the problem? Yes, it is supposed to return the id of the newly created Hotel, otherwise the UI will be in trouble. But we have already stated that Commands are not allowed to return stuff, so what to do?
The common answer to that problem when it arises in a CQRS system is to use Guids as identifiers. That way the client (or whoever sends the Command) can be the one creating the identifier and does not have to wait for the server to respond before continuing to work on the object.
We pretty much have two options here. Remodel the database to use Guids instead of auto-incremented Ids, or introduce some kind of mapping between the two. Since we’ve said from the start that the DB should remain as intact as possible, mapping had to be the solution of choice for us.
If you look at the end of the AddHotelCommandHandler above, you’ll see that the last thing that happens is a call to _identityMapper.Map. This will insert the mapping in a simple lookup table. The AddHotel method in the service can now use this map in order to return the Id:
[github file=”/andlju/hotel-admin/blob/commands/src/HotelAdmin.Service/HotelService.cs” start_line=”95″ end_line=”111″]
If you’re paying attention, this will be the place where you say something like: “But, but. This means that all Command Handlers must be synchronous. And maybe even inside a.. a.. a Transaction??”. And you’ll be completely correct. But notice how “improved performance/scalability” was never one of the goals for this refactoring. I may revisit this though, so hang tight through the next couple of posts..
Testing the Commands are pretty similar to testing the old Service. We can put a little bit more thought into the base fixture though, since we know that the “When” will always be a Command, and the “Given” will be a Command Handler:
[github file=”/andlju/hotel-admin/blob/commands/src/HotelAdmin.Service.Tests/CommandHandlers/AddHotel/When_Handling_AddHotelCommand.cs” start_line=”9″ end_line=”75″]
Now I did promise that we would gain at least something in each step, didn’t I? Well, this may be a bit of a long-shot, but at least we have introduced a bit of Single Responsibility/Separation of Concerns to our architecture. The Command Handlers only have to inject the dependencies they actually need (as opposed to the old Service which is likely to become quite bloated). On the other hand, things did get a little more complex by introducing the Dispatcher, not to mention the Identity Map thingy…
You’d better keep reading the next post. Things may make a little bit more sense after that one.
Leave a Reply