I know that I'm not the only person who has said this and I'm probably not going to be the last, but after discussing this very thing with a few people I think it is worth emphasizing. When I talk to other developers about what images the four words "Command Query Responsibility Separation" conjure, it is interesting. Often times I hear elaborate stories about event sourcing, eventual consistency, and a lot of crazy technology stacks.
It is a shame that this idea seems to be so prevalent, causing a lot of developer to discard it as overly complicated. If we look at the words that comprise the acronym, it seems silly that we attribute so much to it. In my mind, we have wrapped up so many ideas into this simple concept that it is almost like freaking out because somebody is attempting to use SOLID development practices. (Watch out for all of those crazy classes and interfaces!) At its core, CQRS is simple. Very simple. The idea is that we recognize that a call from an outside entity to mutate the state of our application and a call to get state information are two totally separate things. And, as such, should be modeled differently.
Real world pain
I worked on a project that interfaced with a COBOL "backend" for the government. One of the things that we had to face on that project was how the COBOL programmers viewed the world. When we needed to query anything or send in a "command" it would use, in their terms, the same screen. Basically, they had an old green screen AS-400 set of screens (over 200) that we just pushed data into and pulled it out of over a WSDL endpoint. It made it absolutely impossible for us to gain any context on the web side of the world because the same "screen" was used to ask for data and to mutate it. We also had to serialize a hundreds of empty fields back to the COBOL application with maybe one or two filled in just to get some data back. Needless to say this was a painful and error-prone process.
Once the web world had kind of taken over my team thought (foolishly) that we would start writing the logic on our side and deprecate the COBOL world. Unfortunately, development continued in the COBOL application. What we were able to do, though, was talk to the COBOL developers and get them to change the way we requested information. We found out that the "screens" we were sending back and forth did not, in fact, have to have identical fields. It was just how they had always done it when interfacing with the green screen.
After some discussion, we actually got a few of the new programs to utilize different fields for input and output. This even went so far as to breaking apart a few of the monolithic monsters that that gave us huge headaches and were pretty much impossible to test. (I'm talking QA testing, too. Unit/Integration tests were impossible.) This really helped speed up the development process and allowed a cleaner definition of what was required for input versus output. This was especially helpful for screens that returned collections. Before the change, we would have to send a request with (hundreds) of empty rows just so the COBOL program would have the correct data.
Oh, and this application is still being developed as of today. This isn't some horror story from the 90s.
CQRS versus the Command Pattern
Another thing to watch out for is mixing up ideas from the Command Pattern and CQRS. The commands in CQRS are not the same thing. Usually, in the command pattern, the command has an execute method on it that does the actual work. That is not how the commands work for CQRS. The commands should be built as Plain Old (Insert your development framework/language here) Objects. For us in the .NET world those are POCOs and, for Java devs, POJOs. (As was kindly pointed out in the comments: just a data structure.) They are just property bags that carry the intent of the user (a human or another system) to the domain.
Eventual Consistency
This is another thing that constantly gets tied to CQRS. Unfortunately, there is absolutely no reason that we have to have eventual consistency with CQRS. It is perfectly fine to inject a command handler into your web endpoint and pass in the command directly. We don't need a command bus to enjoy the magic of CQRS. And along with this, we also get:
Event Systems
And, for that matter, we don't have to have event systems in place to make use of CQRS. These are things that we can add to our system as we need to scale out and get a better feel for our domain. If these things are a requirement for your domain, obviously plan ahead and make extension points where you can plug these things in.
Why the confusion and over complication?
When I was able to make the shift over and try it out, plainly, without the overhead and complications I could see why. It is liberating. Once I broke everything apart and started practicing CQRS I could see how I could really empower my systems and make them even more decoupled by taking the next step. Adding in a command bus and event sourcing is a natural progression. Even so, we can implement a cheaper version of the two without a bunch of crazy overhead. This is made even more possible with (you guessed it!) F#. This will be the topic of my next post, so stay tuned!
No comments:
Post a Comment