Busting some CQRS myths

CQRS, while a relatively simple concept, still brings a lot of assumptions about what CQRS is and should be. So what is CQRS? Simply put, CQRS is two objects where there was once one. We’re splitting code infrastructure down to the data layers between commands and queries.

But the assumptions around what a CQRS should be lead folks I’ve seen down paths of unnecessary complexity. Complexity around the architecture, and especially around the UI.

Myth #1 – CQRS = Event Sourcing and vice versa

Event sourcing often fits well with CQRS, as it makes building and updating read stores over time a bit more straightforward in eventually consistent models. Additionally, the aggregates living in the command side for behavior-heavier systems and task-based UIs more obvious.

However, event sourcing is a completely orthogonal concept to CQRS. While they fit well together, doing CQRS does not require event sourcing, and doing event sourcing does not automatically mean we’re doing CQRS.

For me, the bar for event sourcing is rather high and targeted (only inside a bounded context, for one), but that’s a story for another day.

Myth #2 – CQRS requires an eventual consistent read store

No, it does not. You can make your read store immediately consistent. That is, your read store can be updated when your command side succeeds (in the same transaction).

For many legacy/existing apps, transitioning to eventually consistent read stores will either force you to go through bogus hoops of mimicking synchronous calls. Users will bang down on your door with pitchforks and torches if you try and transition to an asynchronous model if you don’t change their business process first.

Instead, you can start with immediate consistency and transition where and when it’s needed. Unless a user expects a confirmation page, making every command page have a series of confirmations of “your request was received” is going to annoy the snot out of your users.

Myth #3 – CQRS requires a bus/queues/asynchronous messaging

See above myth. Nothing about CQRS says “thou shalt use NServiceBus”. It’s just not there. You’re merely separating infrastructure between handling commands and queries, but the how is quite varied. Don’t start with a bus until you prove you need eventual consistency.

Consistency models are a business decision because it directly impacts user experience. An eventually consistent model requires a different user experience than an immediate one, and this is not something you can just “slip in” to your users, or try to emulate. If you’re attempting to emulate immediate consistency in an eventually consistent model, you’re doing something wrong.

Myth #4 – Commands are fire-and-forget

How many business processes in your line of work are truly fire and forget? You typically need at least a synchronous acknowledgement that the command was received and accepted. If you’re doing an async send of the command, how do you notify the user? Email? Are they OK with this?

Instead, with commands that need heavy lifting to fulfill the request, we really have two things going on:

  • Accepting the request
  • Fulfilling the request

Accepting the request should be synchronous. Fulfilling need not be. But for the model of an asynchronous fulfillment, we still will likely need ways of correlating requests etc., and this is where you often see workflows/processes/sagas come into play.

Myth #5 – Read model needs to be built in an eventually consistent manner

Only when the business needs require eventual consistency does it need to be eventually consistent. How do we find this out? Probing and questioning. But not of the kind of “hey mr. business dood, can the read model be eventually consistent?”

Instead, we have to dig down on why we would need eventual consistency, and track those back to actual business needs. This is where imagining worlds without computers really helps. Human systems are inherently failure-prone, asynchronous and massively parallel. We just need to match our systems to how they actually work, not necessarily match human systems to how we built our applications.

Remember, as soon as you move to eventual consistency, your user experience must now deal with that fact that the operation the user just performed will not have its effects show up immediately. Additionally, you have to deal with failures in that area. What happens if your mechanism to build your read model fails or is slow? Does your user experience support those situations? If not, I don’t think you’re going to enjoy the support calls.

Myth #6 – CQRS lets you escape consistency problems and eliminate concurrency violations

Decidedly no on both counts. I’ve seen CQRS/ES systems scale horribly, mainly because in order to skip the problems of concurrency all commands and denormalization requests were flowed through a single-file line. Yes, forcing all commands to execute in single-file will eliminate concurrency problems. But now we’ve just forced ourselves into a serializable transaction isolation level.

On the read side, you can make your event handlers idempotent, but can they operate if items arrive out-of-order? Or arrive twice? De-duplicating events helps the latter, but I’ve seen teams miss out-of-order events again and again.

Denormalizing event handlers can be simple, but they are not the brain-dead code that I originally thought they would be. You just can’t escape concurrency.

Myth #7 – CQRS is easy

If it were easy, I wouldn’t see so many people with failed attempts to roll out a CQRS system. CQRS does not eliminate the need to understand what our business needs are. It might make it easier to realize those needs, but it’s just as easy to build the wrong system in a CQRS architecture as it is with n-tier.

Understanding business requirements are the hard part. Sure, we all have technical challenges. But for the CQRS sweet spot of task-based UIs and behavioral domains, that requires us to understand what the heck the business actually needs (versus wants).

Things get even more difficult with CQRS systems replacing legacy applications. In these situations, a wholesale rewrite is the most risky option you can take, and just having CQRS in your corner does not eliminate these risks.

The Silver Lining

All this being said, CQRS is a lovely architecture for separating two wildly different concerns. But don’t just throw every related CQRS concept at your application – defer these decisions until you’ve proven their need. You might just end up with something that actually fits the business needs!

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in CQRS, DomainDrivenDesign. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Khalid Abuhakmeh

    I’ve heard Andreas Ohlund mention the problem of out of order events on a podcast but haven’t heard anyone talk about how to address the issue. Any chance you can write a blog post describing what steps and thinking you can take to handle such situations?


    Thanks for this post. Every time I need some info about CQRS I get a post talking about event sourcing, aynchronous command … CQRS is just one principle that enable SRP.

  • Ali

    Everything is possible but not everything is beneficial. I can understand that I “can” use CQRS without any of above, but would I “benefit” from choosing this pattern but go the classic way in implementation?

    Design is all about compromise. I pay the complexity price for choosing CQRS but for me it only make sense to go all the way to benefit from such design – unless you correct me with an example.

    Having said that, I think this is a great post promoting understanding related but different concepts.

    • Anonymous

      What does it mean to “go all the way”?

      • Ali

        Items 1, 2 and 3. Why would you want to separate your command and read models and then put them on the same transaction? Why would you not use Bus. Sure, you may design CQRS and delay the decision to use all above so that you may switch anytime you want, but I do not think this is a real-world example.

        • Anonymous

          I should probably elaborate more on these models. But “real world”? Are apps in production not real world?

          And nothing in CQRS says “asynchronous”. It’s just an orthogonal concern. I could do async + n-tier, or sync + CQRS, I’m just trying to point out that it’s a separate decision.

          • Ali

            I do not want to drag on the discussion here, but would you ever do one without the other)? Yes, you can but would you choose to (use CQRS+Sync)? And if so an example is helpful.

            It is like lemon grass. Yes, I can use it in any dish but the only dish I would use is Thai dish, it goes well with chilli, coconut oil and coriander.

          • Anonymous

            Would I choose? Yes, it’s in fact my first choice, but it’s worth elaborating on. It really comes back to user experience where this sort of stuff shows its real differences.

  • Bob D.

    Myth #8 – CQRS is just the latest trendy cargo-cult architecture on the block.
    …. Not a myth.

    • Anonymous

      lol well CQRS has only named an architecture that has been around for decades. You’ve probably built a CQRS system but didn’t have a name for it!

      • Christopher

        Also it’s a pattern rather than an architecture

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1174()

  • Pingback: Distributed Weekly 169 — Scott Banwart's Blog()

  • Pingback: Какими бывают репозитории? | Гулин Сергей()

  • >> If it were easy, I wouldn’t see so many people with failed attempts to roll out a CQRS system.

    Are you aware of any case studies or post mortems of failed attempts?

    • jbogard

      Not that I know of – these are clients that I’ve talked to personally.
      Of course, nobody calls for help if everything is unicorns and rainbows, so there definitely could be some confirmation bias on my end.

  • Rafi

    Finally, clearly summarized. Thanks!

  • Eric Davis

    Regarding CQRS using an immediately consistent approach, you mentioned the option of including the updates to both your command and read-only data stores in the same transaction. In that case, does it even make sense to have separate command vs read data stores? Could you just use a single data store but still implement separate command and read stacks? If so, what are the possible drawbacks?

    • jbogard

      There might be, in case they’re drastically different. Event sourcing for example.

      • Eric Davis

        Not sure I follow. Can you clarify? In case what are drastically different?

        • jbogard

          They being the read/write data stores.

  • DmitrySemenov

    Myth number 2, where you say “your request has been received” seems not really correct for me. For instance taking servlet 3 API you may have asynchronous response emitted in different thread other then request. So you keep building asynchronous system and response to user when you are ready. Of course system might be elastic in terms of load and and scale according to the load

  • Liero

    What about systems with many reads and relatively few commands. In such case, making the command stack synchronous just makes sense, doesn’t it? e.g. response to the command is synchronously returned when event is saved in the event store.

    • jbogard

      I think regardless, commands should be synchronous. There are very, very few true “fire and forget” interactions.

      • Scenario – I have a service client, or should I call it a “emissary” if we get the fiefdom/emissaries model, that prepares a valid command based on the data sent by the client and performs all necessary validation. Why then the completely valid command should be synchronous? It will only fail if something happens on the infrastructure level. In this case it will most probably be retried and succeed. No, I am not saying anything about “fire and forget” but I split the “command” thing in two steps – prepare a valid command (synchronous, can fail or throw) and send it (asynchronous, should normally not fail).

        • jbogard

          Technically, it’s all async I/O. The presentation to the user is the most important thing here – you can assume success, and even further, perform state changes locally (especially if you are able to share denormalizers client-side like I’ve seen in some node.js implementations). But what does the user expect? Probably changes to “show up” immediately.

          • Yes, changes will be shown immediately if you use client-side data store like Redux (or any other Flux implementation) does.

  • Hm. #1 “and vice versa” does not sound convincing. How would you query events? If you have event sourcing, you have two sides unless your model does not require any queries, which is very, very rare.

    • jbogard

      Like a doc db or CDRT, I could query an entity and its final state is the sum of its events, like an account ledger.

      • Well, in terms of document db, I would separate retrieving an object by its identity, the operation you do when reconstructing an object from series of events, and querying across multiple object, which would require an index. I would argue that most of the applications that are being developed, require the second one. This is why people usually say that event sourcing requires CQRS to have a read side they can query.

  • Sven Bardos

    Myth #3 – CQRS requires a bus/queues/asynchronous messaging

    If I do CQRS with immediate consistency, which would mean, I guess, synchronous writes/reads how is then with scaling? Scaling of a CQRS system depends on async write/read, no? Thx.

    • jbogard

      Scaling and CQRS are orthogonal, it’s highly contextual and certainly doesn’t require async.

  • Federico Gosman

    Excelent post!

    Would you agree that the following statement is perpetuating some of the myths?

    “A Command Bus should never return a value because that would break the separation between the read and write models. A write action should never return a result. So the answer to the predicament of not being able to redirect on success is usually simpler than you would expect. If you really need that kind of functionality, you probably shouldn’t be using Command Query Responsibility Segregation for that part of your application. In fact, you probably shouldn’t be using CQRS for your entire application anyway.”