Command Query Responsibility Segregation (CQRS)

Hexagonal Architecture is a good foundational architecture, but it has some limitations. For example, complex UIs can require Aggregate information displayed in diverse forms (Chapter 8, Aggregates), or they can require data obtained from multiple Aggregates. And in this scenario, we could end up with a lot of finder methods inside the Repositories (maybe as many as the UI views which exist within the application). Or, maybe we can decide to move this complexity to the Application Services, using complex structures to accumulate data from multiple Aggregates. Here's an example:

interface PostRepository 
{
public function save(Post $post);
public function byId(PostId $id);
public function all();
public function byCategory(CategoryId $categoryId); 
public function byTag(TagId $tagId);
public function withComments(PostId $id);
public function groupedByMonth();
// ...
}

When these techniques are abused, the construction of the UI views can become really painful. We should evaluate the tradeoff between making Application Services return Domain Model instances and returning some kind of DTOs. With the latter option, we avoid tight coupling between the Domain Model and Infrastructure code (web controllers, CLI controllers, and so on).

Luckily, there's another approach. If the problem is having multiple and disparate views, we can exclude them from the Domain Model and start treating them as a purely infrastructural concern. This option is based on a design principle, the Command Query Separation (CQS). This principle was defined by Bertrand Meyer, and, in turn, it gave birth to a new architectural pattern named Command Query Responsibility Segregation (CQRS), as defined by Greg Young.

Command Query Separation (CQS)  
Asking a question should not change the answer - Bertrand Meyer
This design principle states that every method should be either a command that performs an action, or a query that returns data to the caller, but not both, Wikipedia

CQRS seeks an even more aggressive Separation of Concerns, splitting the Model in two:

  • The Write Model: Also known as the Command Model, it performs the writes and takes responsibility for the true Domain behavior.
  • The Read Model: It takes responsibility of the reads within the application and treats them as something that should be out of the Domain Model.

Every time someone triggers a command to the Write Model, this performs the write to the desired data store. Additionally, it triggers the Read Model update, in order to display the latest changes on the Read Model.

This strict separation causes another problem: Eventual Consistency. The consistency of the Read Model is now subject to the commands performed by the Write Model. In other words, the Read Model is eventually consistent. That is, every time the Write Model performs a command, it will pull up a process that will be responsible for updating the Read Model according to the last updates on the Write Model. There's a window of time where the UI may present stale information to the user. In the web scenario, this happens often, as we're somewhat limited by the current technologies.

Think about a caching system in front of a web application. Every time the database is updated with new information, the data on the cache layer may potentially be stale, so every time it gets updated, there should be a process that updates the cache system. Cache systems are eventually consistent.

These kinds of processes, speaking in CQRS terminology, are called Write Model Projections, or just Projections. We project the Write Model onto the Read Model. This process can be synchronous or asynchronous, depending on your needs, and it can be done thanks to another useful tactical design pattern — Chapter Domain Events — which will be explained in detail later on in the book. The basis of the Write Model projections is to gather all the published Domain Events and update the Read Model with all the information coming from the events.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset