Шаблон CQRS
CQRS, что означает разделение ответственности за запросы команд , происходит от CQS ( разделение запросов команд ), введенного Бертраном Мейером в статье «Конструирование объектно-ориентированного программного обеспечения» . Мейер утверждает, что каждый метод должен быть запросом или командой .
Разница между CQS и CQRS заключается в том, что каждый объект CQRS делится на два объекта: один для запроса и один для команды.
Команда определяется как метод, изменяющий состояние. Напротив, запрос возвращает только значение.
Следующая схема показывает базовую реализацию шаблона CQRS внутри приложения. Все сообщения отправляются через команды и события. Давайте рассмотрим это подробнее.

Пример реализации паттерна CQRS
Мы можем четко видеть разделение между записывающими частями и читающими: пользователь вносит изменения на своей странице, в результате чего выполняется команда. Как только эта команда полностью обработана, отправляется событие, сигнализирующее о модификации.
Команды
Команда говорит нашему приложению что-то сделать. В его названии всегда используется ориентировочное время, например TerminateBusiness или SendForgottenPasswordEmail . Очень важно не ограничивать эти имена созданием, изменением, удалением… и действительно сосредоточиться на вариантах использования (см. Документы CQRS в конце этого документа для получения дополнительной информации).
Команда фиксирует намерение пользователя. Сервер не возвращает никакого содержания в ответе, только запросы отвечают за получение данных.
Запросы
Использование разных хранилищ данных в нашем приложении для частей команд и запросов кажется очень интересной идеей. Как очень хорошо объясняет Уди Дахан в своей статье « Разъясненный CQRS» , мы могли бы создать базу данных, ориентированную на пользовательский интерфейс, которая бы отражала то, что нам нужно отображать для нашего пользователя. Мы бы выиграли как в производительности, так и в скорости.
Разделение наших хранилищ данных (одно для модификации данных, другое для чтения) не подразумевает, например, использования реляционных баз данных для них обоих. Поэтому было бы разумнее использовать базу данных, которая может быстро читать наши запросы.
Если мы разделим наши источники данных, как мы сможем их синхронизировать? В самом деле, наше хранилище «прочитанных» данных не должно знать, что команда была отправлена! Здесь в игру вступают события.
События
Событие является уведомление о то , что уже произошло. Как и команда, событие должно соответствовать правилу в отношении имен. В самом деле, имя события всегда должно быть в прошедшем времени, потому что нам нужно уведомить другие стороны, слушающие наше событие, о том, что команда была выполнена. Например, UserRegistered - допустимое имя события.
События обрабатываются одним или несколькими потребителями. Эти потребители несут ответственность за синхронизацию данных в нашем хранилище запросов.
Как и команды, события - это сообщения. Разница с командой суммируется здесь: команда характеризуется действием , которое должно произойти, и событие чем - то , что уже произошло.
За и против
Эта сегрегация дает множество различных преимуществ. Вот несколько:
- Масштабируемость: количество чтений намного превышает количество модификаций внутри приложения, применение шаблона CQRS позволяет независимо сосредоточиться на обеих проблемах. Одним из основных преимуществ этого разделения является масштабируемость: мы можем масштабировать нашу читающую часть иначе, чем записывающую (выделять больше ресурсов, разные типы баз данных).
- Гибкость : легко обновлять или добавлять на стороне чтения, ничего не меняя на стороне записи. Таким образом, согласованность данных не изменяется.
Применение
Шаблон CQRS должен использоваться в ограниченном контексте (ключевое понятие разработки, управляемой доменом ) или в бизнес-компоненте вашего приложения. В самом деле, хотя этот шаблон влияет на ваш код в нескольких местах, он не должен быть на более высоком уровне вашего приложения.
Поиск событий
Что интересно в CQRS, так это поиск событий . Его можно использовать без применения шаблона CQRS, но если мы используем CQRS, поиск событий кажется обязательным.
Электронный поиск заключается в сохранении каждого происходящего события в базе данных и, следовательно, в резервной копии фактов. В схеме источника событий вы не можете удалять или изменять события, вы можете только добавлять новые. Это выгодно для нашего бизнеса и нашей информационной системы, потому что мы можем знать в определенное время, каков статус команды, пользователя или чего-то еще. Кроме того, сохранение событий позволяет нам перестроить серию событий и сэкономить время на анализе.
Один из примеров, приведенных Грегом Янгом на конференции « Кодекс на пляже» , - это остаток на банковском счете. Его можно рассматривать как столбец в таблице, который мы обновляем каждый раз, когда деньги списываются или зачисляются на счет. Еще один подход - хранить в нашей базе данных все транзакции, которые позволили нам достичь этого баланса. Тогда становится легче быть уверенным, что указанная сумма верна, потому что мы отслеживаем произошедшие события, не имея возможности их изменить.
Мы не будем вдаваться в подробности этого принципа в этой статье. Очень интересное подробное исследование доступно в статье CQRS Journey (см. Ниже).
Резюме
CQRS - это простой шаблон, который открывает фантастические возможности. Он состоит в отделении части чтения от части записи с запросами и командами.
Его использование дает множество преимуществ, особенно с точки зрения гибкости и масштабирования.
Источники событий завершают шаблон CQRS, сохраняя историю, которая определяет текущее состояние нашего приложения. Это очень полезно в таких областях, как бухгалтерский учет, потому что вы получаете в свою базу данных серию событий (например, финансовые транзакции), которые нельзя изменить или удалить.
Идти дальше
Документы CQRS , Грег Янг
CQRS Journey , Доминик Беттс, Хулиан Домингес, Григорий Мельник, Фернандо Симонацци, Мани Субраманиан
Уточненный CQRS , Уди Дахан
CQRS и Event Sourcing - Code on the Beach 2014 , Грег Янг