The CQRS dilemma and related random thoughts


ANOOP MADHUSUDANAN

Vote on HN

imageI was very skeptical about CQRS (Command Query Responsibility Segregation) some time back, how ever after working on a CQRS implementation for the past few months for a customer in the telecom domain, I see better light. For some reason, there is a wide spread perception that CQRS is only for complex domains, how ever I think any true business system can benefit from CQRS principles. Here are few quick thoughts, mostly rants.

What is CQRS?

The basic idea of CQRS is pretty simple, this is from the CQRS summary post by Greg Young

Starting with CQRS, CQRS is simply the creation of two objects where there was previously only one. The separation occurs based upon whether the methods are a command or a query (the same definition that is used by Meyer in Command and Query Separation, a command is any method that mutates state and a query is any method that returns a value).

When most people talk about CQRS they are really speaking about applying the CQRS pattern to the object that represents the service boundary of the application.

As simple as that. I suggest you to read/bookmark the below posts.

Code samples to start with (.NET stuff)

So, most of the discussion happening these days is about the application possibilities and implementation details around CQRS, and these are just few random thoughts around the same, and these are not any pointers for anyone.

For a moment, let us forget what exactly is CQRS, let us see how your system or business normally works. The users or stake holders or external system interact with your system in two ways – basically they’ll ask the system to do something (commands), and they also need to view/visualize the state of the system in different ways (queries). In most businesses, the system will be queried not just for the current state, but also for historical changes – i.e, you need to track the history of changes (as in an audit log) and need special logic to capture intelligence about events happened in the past. Say, to answer like "how many users are removing product x from their cart after adding product y". 

You could argue any system that is just CRUD is a database, and yes we can put any decoration on top of it to build some editing features. But any meaningful Business Context involves capturing intent from user, to validate the intent at times, handle it, and provide some meaningful read models to query.

So, I think CQRS allows modeling the domain in a more natural way. You can pick commands directly from the use cases (if well written), and you can focus on what the domain does or what the domain should do when a state change happens, and use this information to construct how different stake holders view the system. In our scenario, we had multiple dimensions/read model snapshots.

Do I need CQRS?

It is all about the ROI, isn't it? Theoretically, you could argue any BC that models a set of business scenarios can be benefited leveraging the CQRS principles, because that means your system will be able to answer a lot of business related questions implicitly. Do you need that or not? That's a business call.

Here is my top three reasons based on my limited exposure towards CQRS based models.

  • The users or stake holders or external system interact with your system in two ways and if you are specifically focused on capturing the user intent– basically in any system, they’ll ask the system to do something (commands), and they also need to view/visualize the state of the system in different ways (queries).
  • In case your system will be queried not just for the current state, but also for historical changes – i.e, you need to track the history of changes (as in an audit log in a stereotypical system) and need special logic to capture intelligence about events happened in the past. Say, as I mentioned, to answer like "how many users are removing product x from their cart after adding product y".
  • Your management/customer thinks it'll add value to them on the long run, i.e, the system will help them have an edge over the competition. Oh yea, you have to sell this to them.

There is going to be a spike in the CapEx, may be because building Task Based/Inductive UIs are more costly than spread sheet like grids/CRUD focused forms where the user has to bring up the entire form to change the status from open to closed or what ever.  Other than that, I think the cost is totally dependent on the design and related details, and the way you implement CQRS along with other DDD patterns.

CQRS and Event Sourcing

CQRS can be a simple separation of commands and queries, but I think the real value is if you tie CQRS with Event sourcing - it allows you to capture the system as how it came to the current state, rather than what it is right now. So, you are adding a new dimension to the system, i.e, the time. And you can take snapshots of the system at different times, and then compare it, that is valuable business intelligence. I think we don't need to see the read model as just a static snapshot of the system at a given time - it can even be derived from the state of the system at two different times.

And you can build read models based on multiple dimensions - to answer questions related to the system's behavior as well. For example, a stereotypical system can't answer even simple questions like "how many users are removing product x from their cart after adding product y" with out explicit design to capture the scenario. In a CQRS system this is implicit.

You can plugin a new dimension that constructs a read model to answer the query. About the cost - I think the key is in bringing in the mindset and selling this idea to the stake holders - even if the initial investment is a bit high, that will significantly improve their ROI and place them ahead of the competition.

How ever, the problem is, the world may be too corrupted with people like us, who were trying hard to persist a single state snapshot of the system in a mismatching ER model and then trying to keep it up to date and worrying about all related issues, to further mess it up with audit logs and all other mining crap when business starts asking critical questions.

Related Reads:

CQRS and REST

Related Reads

Based on the recent experience, I’ve got a feeling that REST and CQRS goes well together, and there is a bit to explore there.   To start with, they way we implemented Commands in one of the recent system is over a REST API, where the URL scheme represents the commands.

Say, for example, if the user need to close and issue, the end point will be like http://server/issue/close   - The end points are used to identify the command handler and pass it to the same. Command handlers are registered in a container, in our case we used MEF to export the command handlers, something like

Message is essentially a key value store as in a dictionary, and this allows us to cope up with versioning.  We had a REST based Querying API too. And we were federating the commands to the results/DTOs as in Hypermedia

i.e, here is an example

[ExportCommandHandler("Issue","Close")]
public void CloseIssueCommandHandler(int id) {..}

I couldn't figure out a defined way for the Task Based UI to find out possible commands based on the current state. Probably this is more or less an implementation related aspect and all of us are free to choose. We could do the validation of the command after it is issued, but in some scenarios, it is better to prevent the user from issuing the command in first place.

I.e, let us consider a DTO,
<issue>
  <id>1</id>
  <description>A bug is trying to hug me</description>
  <otherfields/>
  <link rel="rc:closeissue" url="/issue/close/1">
</issue>

Now, when a user closed an issue, a CloseIssue command has gone in and if the operation succeeds, an IssueClosed event has been logged to our event store - Now, as the issue is already closed, you don't need to (or you should not) provide the CloseIssue action to another user again, because the Issue is already closed by some one.

So, in our scenario, we had some decorators on top of the Query builder to evaluate the current state, so that only the required commands are federated to a returned result. So, the Task Based UI can be more intelligent (and the TB UI is anyway issuing commands based on the DTO information it has).

Related Reads:

Alright, I warned you early enough that these were some random thoughts.  Happy coding!!

© 2012. All Rights Reserved. Amazedsaint.com