(please read my
Introduction post in this series for an explanation of what I'm trying to do)
The first "phase" in Command-Query Responsibility Segregation (CQRS) is probably the most straightforward and obvious - separating your reads (queries) from your writes (commands). In a typical application (sorry, no samples), this basically means separating the queries that display data on the screen from the ones that perform inserts, updates and deletes on your database.
I should probably take a minute to explain the type of architecture I'm envisioning for this blog post, although benefits of the steps can be seen no matter your architecture. For the phases, I'm imagining you have a domain model or at least a business logic layer which has business objects for each of the main entities in your system. In all likelihood, these business objects are being hydated from the database and also save their state back to the database. Again, this isn't the only type of system that can benefit from some of the concepts of CQRS, but its what I have in mind mostly because it's what I deal with at work that I'm trying to improve :)
What do I mean by separate the reads from the writes? Most them into different objects. That's it. If you use business objects, move the functions that read data from the database out of them and into another read-specific object. If you just use a straight object for data access like a repository, break it up into two repositories - one for reading methods and one for writing methods. Just separate the methods in your app that read data from the ones that write data.
With even just this simple step, you will see some benefits, including:
Your code, especially if you have business objects, will become simpler.
This may not be as applicable if you're not using business objects, but if you are - you have removed an entire responsibility from them. The responsibility of hydrating themselves to display on the screen.
This means your business objects become more focused on what they're intended to do - validate things before they get created, updated, deleted, etc.
Increased ability to optimize your read query performance.
There are a few reasons for this. The big one is that in most cases, your business object represents a row in a database table. Even if you're using an ORM, you're mapping objects to database table rows. As such, you're usually querying entire rows, using lazy loading to get related child objects and other techniques in order to get the data you need to show a screen.
Once you've removed the concern of reading from business objects and put it into its own class, you're now able to use any techniques in order to get the performance you want. You can write custom SQL queries to bring back just the data you need because you're not beholden to the business object definition. If a stored procedure makes more sense here, use that. If you only need two columns from a row instead of the entire row, just write a query that only returns those two values. You have much more wiggle room this way.
So with just this simple change you've cleaned up your business objects and given yourself some leeway when it comes to optimizing your queries. Not bad.
In the next post, I'll talk about the 2nd step as I see it - unifying the way data flows through the write side via the use of commands, events and handlers.
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