Anton Sidorov homepage

Bookmark this to keep an eye on my project updates!

Follow me on GitHub

Command Query Responsibility Segregation (CQRS)

Зачем

  • это разделение ответственности за команды и запросы, шаблон, который разделяет операции чтения и обновления для хранилища данных.
  • Внедрив в приложение CQRS, можно максимально увеличить его производительность, масштабируемость и защиту.
  • Гибкость, достигнутая при переходе на CQRS, позволяет системе лучше развиваться с течением времени и не мешает командам обновления вызывать конфликты слияния на уровне домена
  • В основном используется с Event Sourcing

Плюсы и минусы

Плюсы

  • Независимое масштабирование. CQRS позволяет раздельно масштабировать рабочие нагрузки чтения и записи, снижая риск конфликтов блокировки.
  • Оптимизированные схемы данных. Для процессов чтения можно применить схему, оптимизированную для запросов, а для процессов записи — другую схему, оптимизированную для обновлений.
  • Безопасность. Так будет проще назначить для выполнения операций записи данных только допустимые сущности домена.
  • Разделение проблем. Разделение процессов чтения и записи позволяет получить более гибкие и простые в обслуживании. Большая часть сложной бизнес-логики переместится в модель записи. Это в некоторой степени упростит модель чтения.
  • Более простые запросы. Сохраняя в базе данных для чтения материализованное представление данных, вы предотвратите использование приложением сложных соединений в запросах.

Минусы

  • в любой системе с разделением хранилищ для записи и чтения, здесь возможна только итоговая согласованность. Между созданием события и обновлением данных в хранилище всегда будет некоторая задержка.
  • повышает сложность системы, так как в нем нужно создать код для запуска и обработки событий, а также постоянно собирать или обновлять все представления и объекты, необходимые для обработки запросов в модели чтения.
    • Применять когда read — подсистема не справляется с нагрузками

Команда

command cqrs

  • это запрос к системе на выполнение действия, которое изменяет состояние системы
  • Команды являются императивными и должны обрабатываться только один раз
  • Команды имеет смысл делать идемпотентными, если этого требуют бизнес-правила и инварианты предметной области
  • Команда — это объект передачи данных (DTO) особого типа, предназначенный специально для запроса изменений или транзакций.

Обработчик комманд

Обработчик комманд:

  • FAQ
  • Конвейер обработки команд может активировать обработчик команд способами:

Запрос

  • Чтение это просто «отфильтруй данные и преобразуй их в формат удобный для фронта». Уже фраза - формат удобный для фронта намекает что это не про домен.
  • Плюс чтение не оказывает влияние на целостность агрегатов, их инварианты
  • В противовес же (как техническое обоснование почему чтению нечего делать в домене) - операции чтения редко требуется вернуть модель в том виде в котором она представлена в домене. Куда чаще это какие-то более плоские ViewModel. Тогда зачем городить для всего этого лишний слой абстракции?
  • Представим ситуацию что мы сделали репозиторий и достаём из него пагинированные агрегаты чтобы потом представить их в плоскую модель для отображения таблички на фронте. Операция «достать агрегат» дорогостоящая (в силу того что агрегат почти всегда имеет достаточно сложную иерархическую структуру). Вместо этого мы могли бы сразу написать query которая достанет только необходимые данные и не создаст лишнего оверхеда
  • Чтение является бизнес-требованием, но вряд ли его можно назвать бизнес-правилом доменной области. Потребности чтения могут меняться в зависимости от смены фронта или дизайна приложения. Является ли это частью описания жизненного цикла бизнес сущностей в домене?

Паттерны

Технологии