CQRS - это...
Просто о NET | создано: 05.11.2020 | опубликовано: 05.11.2020 | обновлено: 13.01.2024 | просмотров: 6709 | всего комментариев: 2
Несколько фактов о CQRS
Что такое CQRS?
Для начала давайте определимся, что же всё-таки такое CQRS. Итак, CQRS - это способ написания программного кода. Аббревиатура расшифровывается как Command and Query Responsibility Segregation (CQRS). То есть это разделение ответственности на команды и запросы. Единственное, для чего он был придуман, так это для того, чтобы разделить операции записи в базу данных от операций чтения данных. И всё потому, что операции записи требуют больше ресурсов и времени чем операции чтения. Всё! И чего только не услышишь про этот CQRS, и "Task Based UIs", и даже "Event Sourcing"... Просто жесть! Давайте покажу на примере.
Пример применения паттерна CQRS на C#
Предположим, что у меня есть интерфейс репозитория для работы с сущностью User:
/// <summary>
/// User repository
/// </summary>
public interface IUserRepository{
/// <summary>
/// Returns user by identifer
/// </summary>
User GetById(Guid id);
/// <summary>
/// Returns user by identifer
/// </summary>
IPagedList<User> GetPaged(int pageIndex, int pageSize);
/// <summary>
/// Creates new user
/// </summary>
void CreateUser(string firstName, string lastName, DateTime dateOfBirth);
/// <summary>
/// Updates new user
/// </summary>
void UpdateUser(Guid id, string firstName, string lastName, DateTime dateOfBirth);
/// <summary>
/// Deletes user by identifier
/// </summary>
void DeleteUser(Guid id);
/// <summary>
/// Sets Salary for user with identity
/// </summary>
void SetSalary(Guid id, decimal value);
}
Обратите внимание, что в моём репозитории есть несколько методов на получение данные (другими словами Query) и несколько методов на запись (можно назвать Command).
После того как я применю паттерн (подход), который уже набил оскомину и назавается CQRS, то мой репозиторий разделится на две части. Первая - это набор запросов (Queries):
/// <summary>
/// User repository for read data
/// </summary>
public interface IUserReadRepository
{
/// <summary>
/// Returns user by identifer
/// </summary>
User GetById(Guid id);
/// <summary>
/// Returns user by identifer
/// </summary>
IPagedList<User> GetPaged(int pageIndex, int pageSize);
}
и вторая часть - это набор комманд (Commands):
/// <summary>
/// User repository for write
/// </summary>
public interface IUserWriteRepository
{
/// <summary>
/// Creates new user
/// </summary>
void CreateUser(string firstName, string lastName, DateTime dateOfBirth);
/// <summary>
/// Updates new user
/// </summary>
void UpdateUser(Guid id, string firstName, string lastName, DateTime dateOfBirth);
/// <summary>
/// Deletes user by identifier
/// </summary>
void DeleteUser(Guid id);
/// <summary>
/// Sets Salary for user with identity
/// </summary>
void SetSalary(Guid id, decimal value);
}
Всё. Больше ничего в этом CQRS нет.
Заключение
В качестве заключения позвольте привести список "НЕ..."
- CQRS НЕ потребует на изучение более 2 минут.
- CQRS - это НЕ панацея от всех проблем
- CQRS НЕ является Event Sourcing
- CQRS НЕ требует Message Queue (шины сообщений)
- CQRS внутренне НЕ связан с DDD
- CQRS НЕ является архитектурой верхнего уровня
- CQRS НЕ является основополагающим принципом
- CQRS - это НЕ новый подход.
- CQRS - это НЕ серебряная пуля, и он никак не улучшит ваш код
- CQRS НЕ сделает ваш прижок в высоту выше
Ссылки
- CQRS wiki
- Другой пример: ReadonlyController и WritableController из сборки Calabonga.UnitOfWork.Controllers (nuget)
Комментарии к статье (2)
В начале статьи когда описывали IUserRepository допущена грубая ошибка: надо было сразу сказать, что этот интерфейс УЖЕ написан по шаблону CQRS. Вон, даже по первой же ссылке написано что? "Принцип гласит, что метод должен быть либо командой, выполняющей какое-то действие, либо запросом, возвращающим данные, но не одновременно". Посмотрите на каждый метод и найдите в нём хоть один метод, объединяющий и действие и получение данных. Ответственности УЖЕ разделены. Точка.