В DDD / CQRS, должен ли ReadModel действовать как ViewModel, если нет, то где ответственность за отображение? - PullRequest
0 голосов
/ 18 октября 2019

Предположим, что модель чтения ProductCatalogueItem построена из агрегатов / моделей записи, хранится отдельно от моделей записи и содержит каждый продукт, доступный для продажи, и имеет следующие свойства:

  • основы: product_code, name, price, number_of_available_stock,
  • Документация: short_description, description, ...
  • Характеристики продукта: weight, length, depth, width, color, ...

И существует два вида:

  • список продуктов, содержащий список / таблицу / сетку издоступны предложения продукта, и для просмотра требуются только следующие основные свойства: product_code, name, price, number_of_available_stock,
  • сведения о продукте, показывающие все свойства - основы, документация, характеристики продукта.

Естественно, имеются в виду две модели ViewMode:

  • ProductCatalogueListItem, содержащая только основные свойства,
  • ProductCatalogueItemDetails, содержащая все свойства.

Теперь ... есть два варианта (я вижу).


  1. ViewModels представляют 1: 1 представление ReadModels

Поэтому есть две модели чтения, а не одна, ProductCatalogueListItem и ProductCatalogueItemDetails. И служба чтения будет иметь два метода:

  • List<ProductCatalogueListItem> searchProducts(FilteringOptions),
  • ProductCatalogueItemDetails getProductDetails(product_code).

И контроллеры возвращают эти модели напрямую (или, сопоставленный с dto для транспортного уровня).

Здесь возникает проблема фильтрации , .. должен ли сервис чтения выполнять поиск по другой модели чтения, чем возвращается из вызова метода? Потому что ProductCatalogueListItem не имеет достаточно информации для выполнения фильтрации.


ViewModels - это еще один проект ReadModels

Служба чтения будет иметь два метода:

  • List<ProductCatalogueItem> searchProducts(FilteringOptions),
  • ProductCatalogueItem getProduct(product_code).

И отображение из ReadModels в ViewModels выполняется верхним уровнем (вероятно, контроллером).

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


Какой подход к организации ответственности является правильным в соответствии с DDD / CQRS или полностью чем-то еще?

Дело в том:

  • Стоит ли строить две модели чтения и выполнять поиск по одной, а затем возвращать другую?
  • Должен ли я строить модель с одним чтением, которая используетсяи затем сопоставлен с ограниченным представлением, чтобы содержать только базовую информацию для представления?

Ответы [ 2 ]

2 голосов
/ 19 октября 2019

Прежде всего, вы делаете неправильное утверждение:

"... читать модель ProductCatalogueItem построен из агрегатов / моделей записи ..."

Читать модель не знаетагрегатов или чего-либо другого в модели записи, вы строите модель чтения непосредственно из базы данных, возвращая данные, необходимые для пользовательского интерфейса.

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

ОБНОВЛЕНИЕ:

Я попытаюсь объяснить себя лучше:

CQRS просто разбивает один объект на два, основываясь на типах методов. Существует два типа методов: команда (любой метод, который изменяет состояние) и запрос (любой метод, который возвращает значение). Вот и все.

Когда вы применяете этот шаблон к границе службы приложения, у вас есть служба записи и служба чтения, и вы можете по-разному масштабировать обработку команд и запросов, а также можете иметь двамодели.

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

При этом дизайн модели чтения выполняется в соответствии с информацией, которую пользователь хочет видеть в пользовательском интерфейсе, т. Е. Модель чтениямодель представления, у вас нет сопоставления между ними, они обе - одна и та же модель. Вы можете прочитать об этом в ссылках (3) и (6) ниже. Я думаю, что это ответ на весь ваш вопрос. Что я не понимаю, так это проблема фильтрации.

Несколько хороших ссылок:

(1) http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/

(2) http://www.cqrs.nu/Faq/command-query-responsibility-segregation

(3) книга Vaugn Vernon «Внедрение доменного дизайна». Глава 4: Архитектура, раздел «Разделение ответственности по запросам команд или CQRS»

(4) https://kalele.io/really-simple-cqrs/

(5) https://martinfowler.com/bliki/CQRS.html

(6) http://udidahan.com/2009/12/09/clarified-cqrs/

1 голос
/ 19 октября 2019

Поскольку вы уже создали свою модель чтения с использованием данных, поступивших из одного или нескольких сервисов, ваша проблема теперь находится в другом пространстве (возможно, MVC), а не в CQRS.

Теперь предположим, что ваша модель чтения является объектом dbи ProductCatalogueListItem и ProductCatalogueItemDetails являются двумя моделями представления. Когда у вас есть запрос на обслуживание списка продуктов, вы сделаете запрос в вашей базе данных read from read model (таблица ProductCatalog). Может быть, вы делаете запросы на дополнительные фильтры, используя дополнительные предложения where. Теперь, куда вы помещаете свои действия по отображению в ваш код после получения объектов db? Это личный выбор. Вы не должны делать это на верхнем уровне. Когда я использую dapper, я выбираю объекты db, используя модели представлений внутри generic. Поэтому я могу напрямую вернуть результат из моего метода сервиса, тип возвращаемого значения которого был бы IEnumerable.

Для подробного просмотра я бы использовал тот же объект БД. Я знаю, что CQRS предлагает разные модели чтения для разных представлений. Но спросите себя - вам действительно нужен еще один объект БД для подробного просмотра? Вам понадобится только идентификатор, чтобы получить все столбцы, где в первом случае вам нужно было выбрать несколько столбцов. Таким образом, я бы разработал ваш случай, используя смесь из 2 вышеупомянутых методов - у вас есть 2 метода обслуживания, возвращающие 2 разных объекта, но вместо того, чтобы иметь модель чтения 1: 1 для просмотра модели, используйте один объект db чтения и строите 2 разные модели представления изэто.

...