Wrapping your heads around CQRS(Command Query Responsibility Segregation) pattern is a bit tricky & implementing it is all the more difficult. I have seen over the years that engineers straightaway go for implementing it with the help of some tutorials over the internet(I also did so) which, I realized later, is a pretty wrong way to start with. Without understanding it conceptually, implementing it may be a hard nut to crack! Let's do it the right way then. Let's understand it's basics & the need behind it!
As usual, let's take a practical example.
Consider there is an in-house web application which is used to store employee information like employee name, address, post, role, permanent address, leaves taken, leaves balance etc. This application has been developed in n-layered architecture i.e. it's having presentation layer, business layer & data access layer. For simplicity, let's suppose this is a monolithic application & it uses a single MS SQL database. Below is an overly simple diagram of the flow -
Now let's modify this diagram for getting & saving the employee information. It should look like as below -
As you can see, for both get & save calls EmployeeDTO is being used. The EmployeeDTO consists of all the properties pertaining to all the information required for an employee like employeeid, name, location, leaves taken etc.
Here is a good link to refresh your memory on DTOs.
In case of get call, the EmployeeDTO can have only EmployeeID & the rest of the properties can be empty as input & then DataAccessLayer populates all the other properties & returns it to top layers.
In case of save call, the EmployeeDTO will have all the properties populated as input & they are all saved in DB, and then DataAccessLayer returns the newly created Employee object as an EmployeeDomainModel to top layer where it is mapped to the EmployeeDTO object.
You would think that the flow is fine. What is the issue in this? There is no issue. At least for now. But you can see here that for both the calls we are using the same DTO i.e. EmployeeDTO. Both the get & save calls have different requirement of properties i.e. in case of get only EmployeeID is needed and in save call all properties are needed but we are using the same DTO for both the calls.
What if the requirements start coming where we want some fields from Employee table which should be populated only in get call but not needed in save call? For e.g. CreatedOn, UpdatedOn info is also needed but only in get call because these are inserted from database only as default values so they are not needed in save call. What you will do? You will add 2 more properties in EmployeeDTO which will be populated only during get call & will never be used in save call. What if there are some properties which are required only in save calls & not in get calls, like EmployeeSecretKey? You will do the same thing i.e. add one property for this in EmployeeDTO which will be used only in save call but never in get call!
Do you see what we are doing here? We keep adding more properties to the same EmployeeDTO for two separate purposes which will soon turn into a maintenance nightmare if these type of requirements keep coming. So what we can do to avoid it? Can't we simply use separate DTOs for get & save calls? Yes! We can! And that's exactly what CQRS pattern is all about. Segregate the Query(get calls) & Command(save calls) processes.
The example we have discussed is of the most simplistic nature. We are touching only DTOs here but CQRS can be extended to any part of the application or any component of the whole system for that matter. To put it in simple words, we can apply CQRS in following ways as well -
- Create separate DTOs
- Create separate layers i.e. sub-layers within business/dal layers
- Create separate DBs for get & save calls. Yes. This is also a CQRS variation & very popular and the most tricky one to implement.
I hope the article has helped in clearing the basics of a CQRS pattern. I have intentionally kept this article short as compared to my other articles so that you can grasp it's very basic core concept without getting confused. In the next article, I will show you how we can implement a CQRS pattern & that will remove the remaining doubts from your mind.