Автор шаблона, Григорий Юнг (Gregory Young)[1], пишет в своем блоге[2] о названии, данном шаблону, следующее:
"Я отказался от короткого имени шаблона и назвал его Command and Query Responsibility Segregation или CQRS так как это название в точности соответствует тому, что мы делаем - мы фактически разбиваем один объект на два и разделяем его обязанности между этими двумя объектами."Шаблон очень похож на принцип разделения команд и запросов к данным Command-Query Segregation[3], предложенный Бертраном Майером, в котором говорится о том, что каждый метод должен обеспечивать либо изменение состояния объекта, либо получение данных, но не оба действия одновременно.
В шаблоне CQRS принцип CQR применяется ко всему приложению в целом. В приложение четко выделяют две части - одну, отвечающую за изменение состояния объектов предметной области и одну, отвечающую за представление данных клиенту.
![]() |
| Трансформация архитектуры приложения при использовании шаблона CQRS. |
- Что мы получаем от такого разделения? В чем проблема стандартного подхода?
- Проблема в лишних преобразованиях?
- В стандартном приложении данные передаются всегда по одному и тому же маршруту:
- Пользователь нажимает кнопку;
- Клиент трансформирует модель представления в DTO и передает его серверу;
- Сервер трансформирует объект DTO в объект предметной области;
- К объекту предметной области применяются бизнес-правила;
- Объект предметной области трансформируется в реляционную модель и сохраняется в базе данных.
- Запросы к данным происходят в обратном порядке:
- Из базы данных извлекаются реляционные данные и трансформируются в объект предметной области;
- объект предметной области трансформируется в DTO и передается клиенту;
- Клиент трансформирует DTO в модель представления и отображает данные пользователю;
Задайте себе простой вопрос - В чем объективная необходимость преобразования данных в модель предметной области и DTO? Клиенту они не нужны! Клиенту нужна модель представления, которую он отобразит пользователю.
- Данные дают ответ на вопрос "как?".
Как изменились данные контракта? Как изменился баланс клиента? Если вы хотя бы раз участвовали в "разборе полетов", то наверняка знаете, что это не тот вопрос, который интересует бизнес. Бизнес интересует вопрос "почему?" - Почему изменились данные контакта? Почему сумма на счете больше, чем прибыль? - Проблема в расширяемости?
Что мы делаем, когда нам требуется расширить наше оборудование для увеличения производительности? Мы покупаем новое оборудование и настраиваем репликацию. Репликацию двухстороннюю. Тяжелую. И в плане настройки и в плане потребления ресурсов.
- Что дает нам разделение команд и запросов?
- Отсутствие лишних преобразований данных.
В приложении, использующем шаблон CQRS данные кэшируются в денормализованном состоянии, в точности соответствующем логике клиентской модели представления. Нет необходимости делать какие-либо преобразования для передачи данных клиенту.
- Отсутствие ограничений, накладываемых реляционными базами данных.
Информация о событиях, происходящих в системе, хранится в виде одной "плоской" таблицы. Это может быть не обязательно таблица базы данных - это может быть файл или какой-нибудь движок, позволяющий выбирать данные по ключу. Данные хранятся в виде набора событий. Это позволяет в любой момент времени "вернуться в прошлое" и проиграть тот или иной набор событий в порядке их изменения.
- События дают ответ на вопрос "почему?"
События хранятся в виде... событий. Перед сохранением события десериализуются, что дает возможность восстановить событие в точности в том же виде, каким оно было создано. Это позволяет создать набор событий, отвечающих на вопросы бизнеса "почему?". Например, базовую команду клиента ChangeCustomerAddressCommand можно расширить до ChangeCustomerAddressWhileCustomerDeparturedCommand и в ответ на нее создать событие CustomerAddressWasChangedWhileCustomerIsDeparturedEvent, которое даст точный ответ на вопрос "почему?".
- Event-Driven подход позволяет легко наращивать мощность оборудования.
По статистике 90% запросов к серверу - запросы к данным. Даже если опустить тот факт, что при использовании CQRS мы избавляемся от ненужных преобразований, остается еще один очень важный момент: для расширения системы нам нужен просто еще один сервер. Вся настройка сводится к установке на него еще одной копии кэша и подписке на события. Это позволяет очень быстро нарастить пропускную способность оборудования, простым добавлением серверов, обслуживающих запросы на получение данных.
На сегодня пока все. Если Вас заинтересовала данная тема - этот сайт для Вас. Если у Вас есть свои мысли или переводные материалы по теме программирования с использованием DDD/CQRS, обращайтесь ко мне лично в почту grominc@cqrs.net.ru, я постараюсь по возможности более полно ответить на все ваши вопросы или предоставить возможность самостоятельно размещать статьи в этом блоге.
-----------------------------
Ссылки на материалы, использованные в тексте
1. Greg Young blog блог Грега Юнга;
2. Gerg Young about CQRS Грег Юнг о шаблоне проектирования CQRS;
3. Command-Query segregation principle принцип CQS Бертрана Майера;
4. Майер, Бертрант (wikipedia);
5. Пол Фосмо о CQRS
