Query Responsibility Segregation pattern is an architectural pattern that allows to represent system’s data in multiple persistent models. It is similar to Ports & Adapters pattern but it differs in a way the data is managed. It was initially defined to address limitations of Event Sourcing Pattern where it is only possible to query event of one aggregate instance at the time.
graph TD
Client[Client]
subgraph "Command Side"
CmdAPI[Command API]
CmdHandler[Command Handler]
WriteRepo[Write Repository]
end
subgraph "Query Side"
QueryAPI[Query API]
QueryHandler[Query Handler]
ReadRepo[Read Repository]
end
Client -->|Write Request| CmdAPI
Client -->|Read Request| QueryAPI
CmdAPI -->|Create/Update User| CmdHandler
CmdHandler -->|Persist Changes| WriteRepo
WriteRepo -->|Sync| ReadRepo
QueryAPI -->|Get User Data| QueryHandler
QueryHandler -->|Fetch Data| ReadRepo
style Client fill:#f9f,stroke:#333,stroke-width:2px
style CmdAPI fill:#bbf,stroke:#333,stroke-width:2px
style QueryAPI fill:#bfb,stroke:#333,stroke-width:2px
style CmdHandler fill:#bbf,stroke:#333,stroke-width:2px
style QueryHandler fill:#bfb,stroke:#333,stroke-width:2px
style WriteRepo fill:#fbb,stroke:#333,stroke-width:2px
style ReadRepo fill:#bfb,stroke:#333,stroke-width:2px
Command
Command is a write model that implements a business logic, validates rules and enforces invariants. This model represents strongly consistent data (source of truth). It should always let the caller know whether they succeed or failed, and it should provide a clear information why it did fail and if it’s caller’s fault, it should let them know how to fix that command.
Query
It is a read model, a pre-cached projection that lives in a database, flat file or in-memory cache. Read models can create projections synchronously and asynchronously
Synchronous Projection
Whenever the source tables are updated, changes are being reflected in the pre-cached views straight away by subscribing to the table. This requires a creation of projection model that is responsible for regenerationg an updating system’s read models. When write model is updated, the procetion engine uses last processed record to add and modify records.
Asynchronous Projections
They are similar to synchronous projections, but the main difference is that they are triggered asynchronously. The main challenge with using those is that they can be crmblesome in distributed computing. When messages are duplicated or out of order, projections may be inconsistent. Because of that, synchronous projection is a better option.
When to use it
Because this pattern supports Domain Driven Design core values of working with the most effective models for a task at hand, it should be used when using DDD. Also, it it works well with Event Sourcing Pattern. Also, this pattern is very useful when different technologies need to be used for different task (REST, Search Engines etc.).