CQRS (разделение ответственности за выполнение команд и запросов) — это шаблон проектирования, который разделяет ваши операции READ и WRITE/UPDATE/DELETE в вашем коде.
На практике CQRS — очень простой паттерн, не требующий больших вложений. Его можно легко расширить с помощью более сложных методов, таких как архитектура, управляемая событиями, источник событий или многоязычное постоянство. Но они не всегда нужны. Даже без применения каких-либо дополнительных шаблонов CQRS может предложить лучшую развязку и более легкую для понимания структуру кода.
TLDR — вы можете получить общее представление, просто взглянув на это изображение
Вариант использования
Давайте рассмотрим базовую CRUD-модель для заказов в ресторане и ту же бизнес-модель — клиент размещает заказ, редко обновляет или удаляет его, но один и тот же заказ видят покупатель, кассир, повара и другие люди в между. Эта модель является моделью READ Heavy.
И эта система быстро растет с новыми функциями, мы хотели бы иметь меню, в котором каждое блюдо будет иметь свои ингредиенты, мы также хотим показать место, откуда эти ингредиенты получены, мы хотим включить количество калорий, которое содержит каждое блюдо. , так далее и так далее.
Это классический случай системы, управляемой данными, где у нас есть новые сущности, вложенные друг в друга, связанные друг с другом, и давайте добавим к этому миксу СОБЫТИЯ — такие как OrderTaken, OrderCooked, OrderDeliverd, BillPaid и другие.
Вдобавок к этому мы расширяемся за счет новых услуг, например, клиенты могут заказывать онлайн, они могут запрашивать небольшие изменения в ингредиентах — в основном мы добавляем массу новых вариантов использования в бизнесе по мере создания системы.
Что такое CQRS
Идея CQRS состоит в том, чтобы разделить приложение на два разных раздела, которые работают с разными моделями:
- КОМАНДА "Создать-обновить-удалить", которая отвечает за создание или изменение данных, и ЗАПРОС, который извлекает данные.
- У него также есть внутренняя модель, с которой он пишет, и одна или несколько моделей, с помощью которых мы можем читать (подробнее об этом позже).
Команды
Commands
это то, что пишет модель. Он используется для создания нового объекта или изменения состояния объекта.
Command
— это операция, основанная на задачах, а не на данных.Command
может быть вызовом функции с API.Command
можно поместить в очередь для асинхронной обработки (события, задачи).
В каком-то смысле Command
может изменить состояние, создать сущность, может вызвать изменения в системе прямо или косвенно. В терминологии API это определяется как Create/Update/Delete
: Entity
Command
ориентирован на поведение, а не на данные. Речь идет о намерении что-то изменить, оно не соответствует формату ресурса (например, DTO в API). Он может содержать данные, которые помогут обработать намерение, но не более того.
Мы также говорим о системах, основанных на задачах, а не о системах, основанных на ресурсах. Часть записи не принимает новые ресурсы или исправления существующих ресурсов: они принимают задачи, также известные как команды.
Запрос
Queries
— это методы, которые используются для чтения данных. Эти операции не изменяют данные, как вы можете себе представить, при этом у нас есть несколько моделей данных, которые мы можем комбинировать для ответа API. Например, UserModel и OrderModel для отображения всех заказов, сделанных указанным пользователем.
Преимущества этой системы проявляются, когда мы начинаем добавлять другие компоненты в нашу архитектуру.
- Добавление кеша
- Более быстрые запросы (у нас есть 3 БД для чтения и 1 БД для записи)
- Делайте много предварительных вычислений на серверной части — помогает поддерживать легкость на стороне клиента.
- Высокая задержка — есть разница между быстрыми запросами и этим ;)
Течение
Поток команд, здесь модель API, используемая клиентом, может делать две вещи:
- Он может создать объект, используя, отображая и проверяя внутреннюю модель.
- Он может вызвать событие, которое отвечает за изменение состояния объекта.
Поток запросов довольно прямолинеен, у вас есть потребность на стороне клиента, то есть либо —
- Является частью единой внутренней модели, где извлекается напрямую.
- Или это комбинация внутренних моделей, и есть некоторая агрегация моделей.
Преимущества CQRS
- Непротиворечивость. Гораздо проще обрабатывать транзакции с непротиворечивыми данными, чем обрабатывать все крайние случаи, которые могут возникнуть в результате непротиворечивости. Большинство систем в конечном итоге могут быть непротиворечивыми на стороне запросов.
- Хранение данных. Командная сторона, являющаяся обработчиком транзакций в реляционной структуре, хотела бы хранить данные в нормализованном виде, вероятно, близком к 3-й нормальной форме (3NF). Стороне запроса нужны данные денормализованным способом, чтобы минимизировать количество соединений, необходимых для получения заданного набора данных. В реляционной структуре, вероятно, в 1-й нормальной форме (1NF).
- Независимое масштабирование. CQRS позволяет независимо масштабировать рабочие нагрузки чтения и записи и может привести к меньшему количеству конфликтов за блокировку.
- Оптимизированные схемы данных. Сторона чтения может использовать схему, оптимизированную для запросов, а сторона записи — схему, оптимизированную для обновлений.
- Безопасность. Легче обеспечить, чтобы записи данных выполнялись только правильными объектами домена.
- Разделение ответственности. Разделение сторон чтения и записи может привести к созданию более удобных и гибких моделей. Большая часть сложной бизнес-логики входит в модель записи. Модель чтения может быть относительно простой.
- Простые запросы. Сохраняя материализованное представление в базе данных для чтения, приложение может избежать сложных объединений при выполнении запросов.
Когда использовать CQRS
Рассмотрите CQRS для следующих сценариев:
- Совместные домены, в которых множество пользователей получают доступ к одним и тем же данным параллельно. CQRS позволяет вам определять команды с достаточной степенью детализации, чтобы свести к минимуму конфликты слияния на уровне домена, а возникающие конфликты могут быть объединены командой.
- Пользовательские интерфейсы на основе задач, в которых пользователи проходят сложный процесс в виде последовательности шагов или сложных моделей предметной области. Модель записи имеет полный стек обработки команд с бизнес-логикой, проверкой ввода и бизнес-проверкой. Модель записи может рассматривать набор связанных объектов как единую единицу для изменения данных (агрегат в терминологии DDD) и гарантировать, что эти объекты всегда находятся в согласованном состоянии. Модель чтения не имеет бизнес-логики или стека проверки и просто возвращает DTO для использования в модели представления. Модель чтения в конечном итоге согласуется с моделью записи.
- Сценарии, в которых производительность операций чтения данных необходимо настраивать отдельно от производительности операций записи данных, особенно когда количество операций чтения значительно превышает количество операций записи. В этом сценарии вы можете масштабировать модель чтения, но запускать модель записи только на нескольких экземплярах. Небольшое количество экземпляров модели записи также помогает свести к минимуму возникновение конфликтов слияния.
- Сценарии, в которых одна группа разработчиков может сосредоточиться на сложной модели предметной области, являющейся частью модели записи, а другая команда может сосредоточиться на модели чтения и пользовательском интерфейсе.
- Сценарии, в которых ожидается, что система будет развиваться с течением времени и может содержать несколько версий модели, или где бизнес-правила регулярно меняются.
- Интеграция с другими системами, особенно в сочетании с источниками событий, когда временный сбой одной подсистемы не должен влиять на доступность других.
Этот шаблон не рекомендуется использовать, когда:
- Домен или бизнес-правила просты.
- Достаточно простого пользовательского интерфейса в стиле CRUD и операций доступа к данным.
Рассмотрите возможность применения CQRS к ограниченным разделам вашей системы, где это будет наиболее ценно.
Посмотрим, как это выглядит в коде
В этой части будет не «Код», а общий низкоуровневый дизайн, который помог мне понять CQRS и реализовать его в моих личных проектах, а также в некоторых проектах, над которыми я работал — CQRS действительно изменил мой способ написания микросервисов, которые являются ДДД.
Controller Orders - GET/Orders?id - GET/Orders - POST/Orders - PUT/Orders - DELTE/Orders?id Controller Restaurant - GET/Restaurant - GET/Restaurant?id - POST/Restaurant - PUT/Restaurant - DELTE/Restaurant?id Controller Dish - GET/Dish - GET/Dish?id - POST/Dish - PUT/Dish - DELTE/Dish?id User - GET/User?id
Давайте определим модели запросов
Здесь мы видим, что мы определяем абстракцию всех запросов, которые будут обслуживаться Клиенту.
Давайте определим модели команд
Теперь самое интересное, обработчик — давайте посмотрим
Интеграция в существующее приложение.
CQRS довольно гибок, вот несколько моих советов по добавлению CQRS и использованию его преимуществ.
- Начните с одного сервиса или API — это, хотя и не добавит прироста производительности, но сделает код более читабельным и упростит добавление новых функций и возможностей.
- Разделите свои базы данных — один набор (я сказал набор, потому что в масштабе вы бы разделили свою БД), который в основном используется для записи, и один набор для чтения. Вы можете сказать, что это что-то вроде инфрауровня CQRS?
- Разделите свои сервисы — Набор сервисов, которые используются только для записи в базу данных, которые связаны только с «базой набора записей», а другие только для чтения, явно связанные с «базой набора чтения», с этим вы добились очень высокий уровень разделения. Эта структура очень полезна, когда вы используете REST для записи, обновления, удаления и GraphQL для ПОЛУЧЕНИЯ данных.
Что хорошо сочетается с CQRS
- Кэширование — это хорошо, потому что у вас есть модели для написания, которые связаны с сервисами — поэтому легко выполнить инвалидацию кеша. Да, я бы сказал, что его легко аннулировать как больший профи, чем производительность.
- Event Sourcing — я скоро напишу об этом
Сноски
- Хороший документ от Microsoft — Шаблон CQRS — Azure Architecture Center | Документы Майкрософт
- 6-часовое видео о CQRS, супер крутое и супер длинное GregYoung 8 CQRS Class — YouTube
- Отличная статья о CQRS с демонстрацией C# Руководство разработчика по CQRS с использованием .NET Core и MediatR — DZone Web Dev
- Отличная статья о CQRS с Golang Введение в базовый CQRS путем рефакторинга проекта Go (threedots.tech)