Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.
I recently got a really great comment from my post on using Query Objects instead of Repositories. Although that blog post is now 2 years old, I still use the same concepts today in my applications. What I thought may be relevant is to elaborate more on why and when I use the mediator and command pattern for the query side. It may seem obvious on the command side, but not really needed on the query side. Here a portion of the comment from Chris:I’m struggling a bit to see the killer reason for using Query objects over repository. I can see the benefits of CQS but it’s this command pattern type implementation of the Q part I struggle with. I can see for Commands (mutators) the benefits of having separate handlers as you can use decorator pattern to wrap them with additional functionality e.g. Transaction, Audit etc. However for queries I’m struggling to see why you wouldn’t just use a normal repository. Essentially your IQuery object defined what would be a method signature in the repository and the handler defines the implementation of the method. However at some point you have to compose the IQuery class to it’s handler either using a dependency injection framework or Mediator pattern as in your following blog.
Query Objects
The primary place I use query objects (mediator + command pattern) is when I want to be decoupled from an integration boundary. Often times this is between my application and the web framework I’m using. I view my query objects as my public API. Which means I usually want to create a pipeline for those queries. I will use a request pipeline for handling things such as authorization, validation and logging in the query pipeline. Since this is the same implementation I use on the command side, it’s easy to use with library like MediatR which handles both commands and queries as a “Request”.Repositories
I still use repositories, but just very differently than I did before. Since my query objects are my public API, my repositories are generally only used internally within a the core of a given application (or bounded context). My repositories are usually pretty narrow and also handle things like caching.CQRS
There are many ways to implement the separation between reads and rights. I’ve failed at making this point clear in many of my prior posts. I’ve had a few encounters recently that make me feel like there’s still a lot of misconceptions about what people think CQRS is. I’ll keep posting quote from Greg Young.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).That’s all it is folks. Not really that interesting. What’s interesting are all the possibilities because of this simple idea. How you implement that is up to you. One of the ways I’ve been implementing this is with the Mediator + Command Patterns. It’s not the only way!
I find it offers some flexibility in how I do my reads. I can reference the ORM directly and create a query that is not so tightly bound to my aggregate/domain boundaries if the view model relates to a consolidated view. Or just simply when I don’t want to go through multiple mappings…from data entity -> domain object -> view model.