CQRS and Human Intent

Command Query Segregation Responsibility (CQRS) is one of those ideas that has been floating around my career for so long that I honestly can’t pinpoint the exact moment I first heard it. I think it may have been through the older formulation called CQS — Command Query Separation, from Kent Beck’s Implementation Patterns. That early framing was simple: if a method is a query, it should not mutate state; if it’s a command, it should not return data. Clean separation at the method level.

That alone already saves us from a ton of surprises. If you call a GetBalance() method, you shouldn’t worry that it’s also withdrawing money behind your back. If you call a Deposit(amount), it shouldn’t try to tell you the current balance — especially in a world where hundreds or thousands of deposits may be happening at the same time (not to my banking account, unfortunately). Whatever number it returns will likely be misleading. Queries provide information; commands express intent to change state. Keep them separate.

When I first encountered CQRS as a broader architectural pattern, sometime in the early 2000s, it was often paired with event sourcing. I remember Greg Young presenting in Montreal and asking the room: “You all have backups… but how confident are you that you could restore your system to a fully consistent operational state within an hour?” (That’s how I remember it…) Not many hands went up. Event sourcing enabled replaying events and reconstructing the state reliably. That idea stuck with me—but that’s a story for another post.

It wasn’t until around 2011 that I worked on a system that embraced CQRS. By then, what most people talked about was the tooling—mediator libraries, read/write models, separate read and write databases, SQL projections, and so on. Those things matter, but they’re not the heart of CQRS for me.

I think the heart of CQRS is intent.

Before touching any architecture diagrams, I prefer to think like a person acting within a system. A part of that system is likely automated. What is their intent? What do they believe will happen when they click something? What would surprise them? That framing often gives you better guidance than any technical explanation.

Take a simple e‑commerce example. A customer arrives with a question: “What can I buy?” That’s a query. If the store has hundreds of thousands of items, we shouldn’t dump everything on them. Instead, we guide them: “We sell products for extreme sports,” followed by a list of categories. Then they refine the query: “Show me snowboarding gear.” Another query. Then: “Add this snowboard to my shopping cart.” That’s a command — an expression of intent to change something.

Eventually, they say, “Place my order.” But placing an order isn’t the same as creating a sales order record in a database (it’s a sales order from the business perspective and a purchase order from the customer’s perspective). The customer expresses intent to buy. The system receives that intention; instead of structuring the command as fields to be stored in a database, we structure it as an intention to be interpreted by the system. The business decides what needs to happen next—taking payment, checking inventory, capturing marketing data (e.g., “How did you hear about us?”), and recording their experience.

Seen this way, the command isn’t “CreateOrder.” The command is: A customer wants to place an order. A more elaborate solution may guide the customer through a process to identify what they need, capture that, and then give them what they want.

That mindset also applies to queries. Think about requesting a financial statement. The user’s intent might be: “Give me year‑to‑date.” Internally, we calculate the date range. When they request that same statement in the future, do they mean “year‑to‑date again” or “the same period as last time”? Understanding intent shapes the design. See the following examples of an accountant’s intent when working with financial statements:

The user requests Calendar YTD (Year-to-date):

The system produces the statement and retains information about the user’s intent (the accounting period, and what begin and end dates it meant in that moment):

Or maybe the user wants a statement that goes from period to period:

The system retain that information. Should the dates for those fiscal periods change in the future, the statement can still be either recreated for the same dates or for the same periods, depending on what the person needs:

Or maybe the need is to select specific dates:

The user’s intent is preserved:

When we start at this level—human intent, behavioral separation, and clear mental models—the technical structure of CQRS becomes much simpler. The tooling becomes an implementation detail rather than the centerpiece.

And that’s what keeps the system predictable, maintainable, and more aligned with how real people think.

, , , ,

  1. Leave a comment

Leave a Reply

Discover more from Claudio Lassala's Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading