CQRS, UI, основаный на заданиях, Источники событий… ах

Original author: Greg Young
  • Translation
Ремарка от меня. Подобрать терминологию было непросто, поэтому готов в процессе редактировать перевод, чтобы улучшить понимание текста.

Многие заблуждаются в отношении того, что собой представляет CQRS. Они рассматривают CQRS как архитектуру, хотя он таковым не является. CQRS – это простой шаблон, имеющий много архитектурных возможностей. CQRS не является конечной согласованностью, событийностью, или обменом сообщениями, это не модель для чтения и записи, и не использование источников событий. Я попробую несколькими абзацами описать, что такое CQRS, а потом рассмотрю, какое отношение он имеет к другим шаблонам.

CQRS Разделение ответственности команд и запросов (Command and Query Responsibility Segregation)

Начиная работу с CQRS, необходимо понимать, что CQRS – это создание двух объектов, которые ранее были одним. Разделение основано на том, что методы — это команды или запросы (Мейер использовал то же определение в Command and Query Separation, команда — это любой метод, который меняет состояние, а запрос — это метод, который возвращает значение).

Когда большинство говорят о CQRS, они имеют в виду применение подхода к объекту, который представляет собой сервисную службу приложения. Рассмотрим следующий псевдо-код сервиса.

CustomerService

void MakeCustomerPreferred(CustomerId)
Customer GetCustomer(CustomerId)
CustomerSet GetCustomersWithName(Name)
CustomerSet GetPreferredCustomers()
void ChangeCustomerLocale(CustomerId, NewLocale)
void CreateCustomer(Customer)
void EditCustomerDetails(CustomerDetails)

Применение CQRS на этом приведет к двум сервисам

CustomerWriteService

void MakeCustomerPreferred(CustomerId)
void ChangeCustomerLocale(CustomerId, NewLocale)
void CreateCustomer(Customer)
void EditCustomerDetails(CustomerDetails)

CustomerReadService

Customer GetCustomer(CustomerId)
CustomerSet GetCustomersWithName(Name)
CustomerSet GetPreferredCustomers()

Вот и все. Это вся картина CQRS шаблона. Не более.… Это кажется занимательным, когда мы описываем его в таком виде, не так ли? Данное разделение дает возможность привнести нечто интересное в архитектурном плане. И что очень важно — он помогает остановить процесс ментальной ретардации, потому что двое используют те же данные, и кроме этого, они также должны использовать ту же модель данных.

Наибольшее преимущество – это то, что он распознает различные архитектурные свойства при работе с командами и запросами… Например, он позволяет нам разместить два сервиса по-разному: мы можем разместить сервис чтения на 25 серверах, а сервис записи — на двух. Обработка команд и запросов принципиально асимметричная, симметричное масштабирование этих сервисов не имеет большого смысла.

UI, основанный на заданиях (Task based UI)

Пользовательский интерфейс, основанный на заданиях, довольно сильно отличается от интерфейса, основанного на CRUD. В нем вы отслеживаете, что делает пользователь, и продвигаете команды, которые представляют его намерения. Хотелось бы подчеркнуть, что CQRS не требует интерфейса основанного на заданиях. Можно применить CQRS в CRUD приложении (хотя, например, создание отдельных моделей будет при этом гораздо сложнее).

Но есть одна вещь, которая действительно требует подобного интерфейса — это доменная модель.

Сервисный слой приложения в доменной модели представляет собой задачи, которые система может выполнять. Это не просто такие процессы, как копирование данных в доменный объект и их сохранение… Не стоит забывать о поведении с объектом. Прежде чем двигаться дальше, давайте посмотрим, что случится, если мы все-таки так сделаем.

В нашем повсеместном языке не было бы других глаголов кроме как «Создать», «Удалить» и «Изменить». И пока существует много доменов, в которых язык является именно таким, не стоит использовать принцип доменных моделей для построения системы.

Концепция такого интерфейса не предполагает быть частью CQRS, и у домена могут быть подобные команды, он должен следить за намерениями пользователя, что очень важно. Было ли это обновление принудительным или нет? Какая разница? Зависит от того, какой вопрос вы ставили перед собой.

Двигаемся к следующему шаблону, который вводит в заблуждение в CQRS

Источники событий

Хотелось бы внести ясность, что когда я использую этот термин, я не имею ввиду всё, что написано в bliki. Я ссылаюсь к хранению текущего состояния, как серии событий и возобновляю состояние системы, повторяя эти серии событий…

На командной стороне уравнения, с тех пор как «чтение» больше не является частью домена, сохранение событий может быть отличным способом поддержания текущего состояния. Значение возрастет, если вы решитесь на две отдельные модели (модель для чтения и модель для записи) и если вам необходимо их интегрировать, то вы вероятнее всего будете это делать через события. Так как событийность сохраняется, почему бы просто не использовать одну модель для управления состоянием?

Шаблон обмена сообщениями

Нет необходимости в использовании этого подхода с CQRS. Впрочем, если вы разделите ваши модели данных, скорее всего, будете использовать обмен сообщениями между ними, потому что в этом случае появляются новые возможности.

Наконец я подошел к последнему «подходу», правда, не люблю его так называть, потому что в действительности это концепция, которую люди кладут в свои определения CQRS, которая идет рука в руку с обменом сообщениями…

Конечная согласованность

Принцип конечной согласованности также довольно часто вводится между сервисами. Это делается ввиду многих архитектурных побуждений. Но наибольшее преимущество — это то, что он позволяет увеличить масштабируемость и доступность. Если вы помните CAP теорему, там сказано, что если нет согласованности — это усиливает другие два свойства. Это очень хорошо для моделей, если они разделены, но это ни в коем случае не является свойством конкретно CQRS.

Сейчас мы можем увидеть, что CQRS на самом деле довольно простой шаблон. Все, что крутится около CQRS, это не только CQRS, а также архитектурные свойства интеграции двух сервисов. Другими словами, самое интересное — это не шаблон CQRS, а те решения, которые принимаются по ходу. Есть много интересных решений, которые были задействованы в системе, где решили использовать CQRS… но это не только CQRS само по себе.
  • +10
  • 12.7k
  • 8
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 8

    +1
    Хотел написать что написали какую то херню. Потом посмотрел на автора. Этот чувак создал geteventstore.com
    Если мы рассмотрим CQRS как это написано в вики «метод должен быть либо командой, выполняющей какое-то действие, либо запросом, возвращающим данные, но не одновременно», то он прав. Но только ради этого естественно смысла нет использовать CQRS.
    В тех проектах где я сталкивался, всегда использовали:
    1. команды — которые создают события(и наоборот), но события важнее
    2. база для хранения событий, и вторая база, которую можно получить пробегаясь по всем событиям из первой базы.

    Без них лично я не вижу смысла использовать CQRS.
      0
      Этот чувак создал geteventstore.com

      … этот «чувак» первым озвучил термин CQRS, уж если на то пошло.

      Но только ради этого естественно смысла нет использовать CQRS.

      Почему?
        0
        Чувак этот крутой, я в курсе )) У меня 2 проекта используют его EventStore. А вот на другом проекте не смогли перейти, стрессовое тестирование не прошел.
        По поводу «почему». Какой смысл усложнять себе жизнь? Ведь клиент отправляя команду, как правило хочет знать, выполнилась она или нет, и если выполнилась то обновить у себя состояние. Проще тогда все делать «по старинке».
        А у вас есть другое мнение? Очень интересно послушать.

          0
          Очень часто либо обновленное состояние не нужно вообще (особенно, если говорить о программных клиентах, а не пользовательских), либо клиент и сам его знает (когда команда по суди имеет семантику «обновить сущность на сервере в соответствии с её состоянием на клиенте» или проще «сохранить изменения»).
            0
            Ну хорошо, поставим вопрос с другой стороны. Какой плюс в использование CQRS в чистом виде?
              +1
              Возможность последующего масштабирования, например.
                +1
                Более быстрые запросы которые просто отдают данные для отображения и при этом полнофункциональная доменная модель для команд. Очень, знаете ли неудобно, когда для отображения грида в котором 3-4 колонки со значениями, для каждой строки приходится загружать весь агрегат целиком.
                При этом query модель вообще не позволяет апдейтить сущности в хранилище, и поэтому нельзя испортить консистентность данных сохранив не прошедшие валидацию доменом значения.
              +1
              Во-первых, есть домены, где CQRS естественнен: всякое логгирование, аудит и так далее.
              Во-вторых, есть технические ситуации, когда клиенту, на самом деле, никто не гарантирует ответа об успешности команды (все удаленные подключения в условиях нестабильной связи).

        Only users with full accounts can post comments. Log in, please.