(please read my
Introduction post in this series for an explanation of what I'm trying to do with this blog series)
In my
last post, I talked about separating your reads from your writes in your applications. Once you've done that - you've already applied CQRS... you've separated the responsibility of reading your data from writing your data. You're done and your app will b be better for it :)
But if you want to take things further, the next step in applying CQRS as you commonly read about it is to unify the way that data flows through the write side of your application.
Before that though, a quick note on the read side - it's done. Once you've separated it out, that's really all that needs to be done. It can now change indepdently of the write side and it should be very simple. All you're looking to do on the read side is get some data and display it. You can tweak queries and tweak code, but the code should be very simple. So once you've done step 1 as I outlined in my last post, you're pretty much done the "radical" changes on the read side.
On the write side, the way to unify the data flow through it is to issue commands from your client and have them handled by a command handler. In the command handler, you load the business object that the command relates to, call a method that performs the command on the business object and, if necessary, have the business object fire off events which can be handled by event handlers.
Whoa. That was a pretty dense amount of information wrapped up in one paragraph. There's a lot of interesting information about what commands and events are and how they should be named, but rather than re-hash it, I'll just share a few links.
For more on commands,
read this. For more on events,
look here. And if you want to see a sample application that shows the most simple implementation of commands, events and how they're both handled, check out
this project written by Greg Young.
If you don't feel like reading all that other stuff (shame on you), just understand that commands are telling the system to do something and should be named as such - i.e.
UpdateCustomerInfoCommand. Commands should be in the imperative to imply that they are telling the system to do something. Events are telling the system that something has occurred in the past. That's the distinction. So after you handled the
UpdateCustomerInfoCommand, you might issue a
CustomerInfoUpdatedEvent event to let other parts of the system know what happened in case they are interested. And handlers are just functions that handle the commands/events when they're raised.
If you start following these guidelines of having your client issue commands that are handled and then having your business objects, as part of that handling fire events, you'll see some benefits over your standard architecture, including:
Consolidation of business logic into the business objects
I can't count the number of times I've seen an application that touted their business object layer, only to see all of the actual business logic in code-behind files or in MVC actions or elsewhere. The business objects were really just DTOs with some data access methods and maybe a bit of validation logic. The actual changes to the object were occurring elsewhere, breaking encapsulation. When you begin issuing commands, it becomes very natural that all of your business logic is inside your business objects.
A more human way to understand the system
Telling a system what to do and then having the system notify other systems what happened is a very easy thing to understand in human terms, because it models how humans work.
This makes it easy on the developer's brain to understand how data flows through the system and even more important, it makes it easy on the non-developer's brain to understand how the system works as well. Instead of talking in terms of objects, you can talk in very real world terms which makes sense to non-developers that are part of building a system. Which brings me to my next point...
You head in the direction of domain-driven design
I'm not a DDD expert, but I've read
the big blue book and a lot of what it discusses is handled by moving into commands and events on the write side. Most CQRS proponents suggest a full blown domain model behind the command handlers and it does make sense. But you can almost get to a domain model just by consolidating your logic and issuing commands this way.
Your client apps become simpler and more focused
Your client apps, whether they be MVC apps, WebForms or desktop apps can go back to being more focused on what they're good at which is displaying data to a user and handling input from a user. No longer will they be burdened with also housing business logic as part of their job. You're getting better SRP and SOC. That's always a good thing.
This change is a little more involved than step 1. In a larger app, it can take considerable effort to pull your business logic together when its currently spread all over your current system. But you also get bigger bang for your buck with this step. Even though refactoring your app to issue commands and raise events make take more effort, you're actually simplifying your system and making it easier to understand for the future.
In the next post, I'll talk about going even further with CQRS by using event sourcing. This is probably where a lot of developers start to feel uneasy about CQRS. Not that they don't see the benefits, but it's quite a leap from how they're used to developing that we become unsure if its the right way to go.
As I mentioned in my introduction post, if something here sounds wrong, or if I'm missing something - please let me know in the comments. Feedback is very much appreciated.
- Introduction
- Step 1: Separating Your Reads From Your Writes
- Step 2: Commands, Events And Handlers