DDD: Как правильно работать с контекстами ?

Gutsy

Новичок
Есть 3 поддомена: Заказная часть, Контрактная и Словари.
У Заказной части есть контекст для Поиска предложений. В Словарях хранятся Страны и Города, есть контекст для CRUD по ним. В Контрактной части есть контекст для работы с отелями и ценами номеров отелей по датам.
Внимание, вопрос - как нужно организовать работу поиска ? Я же получается потеряю возможность делать выборку с join'ами, или я всё же могу дергать в каких-то случаях модели из других контекстов ?

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

Типичный UseCase - Клиент запрашивает на какой-то период предложения по номерам в конкретном городе.

Алгоритм примерно следующий:
  1. Сперва нужно по городу отфильтровать отели.
  2. Затем получить активные цены на номера в этих отелях.

Благодрю заранее за любые ответы !
 

Sufir

Я не волшебник, я только учусь
Поиск - это вообще по идее read model. Там простые DTOшки или даже массивы могут быть, выбирай и наполняй как удобнее, как того требует представление. Join'ы это вообще про инфраструктуру, домену как и presentation должно быть пофиг что там в запросах, более того, там, весьма вероятно, будут какие-то кеши/предагрегации и т.п. если туров много. Короче CQRS отличный вариант.

А в domain могут быть в разных контекстах отдельные модели пересекающихся сущностей или даже то что представлено в одном контексте как сущность в другом может быть реализовано вообще в виде ValueObject.
upload_2017-4-3_18-35-11.png

 
Последнее редактирование:

Gutsy

Новичок
Ага, хорошо, это всё понятно. А есть какие-то примеры с реализованными контекстами и как они друг с другом работают ? Пока все примеры, которые я видел, это что-то непонятное было.
Где в коде хранятся интерфейсы взаимодействия контекстов друг с другом ?
Где происходит преобразование из объектов одного контекста в объекты другого контекста ? Вот допустим Контекст продаж запрашивает у Техподдержки список клиентов. На каком этапе объекты Клиентов контекста техподдержки трансформируются в объекты Клиентов продаж ?
И самое главное, как это всё выглядит в коде ? В теории всё понятно и красиво, но как в коде это отразить - не ясно и примеров не видел до сих пор, сколько не ищу.
 
Последнее редактирование:

Gutsy

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

fixxxer

К.О.
Партнер клуба
Я не совсем понял, что ты называешь сущностью, а что моделью.
Сущность = domain model entity, модель = persistence models?

Со связанными - может, проблема в том, что где-то между контекстами идет обмен самими сущностями (а не их id)?

Вообще в каждом контексте должна быть своя транзакция, да, получится eventual consistency, но с этим можно жить. Представь себе, что каждый контекст - это микросервис и они общаются друг с другом по http. Одна большая транзакция на все контексты это в общем случае проблемно и почти гарантированные дедлоки :)
 

Вурдалак

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

По поводу остального я не ничего не понял.
 

Gutsy

Новичок
Модель - это доменная модель, сущность - это entity, которая мапится в доктрине. Это разные классы: модель прописана в домене и некоторые в инфраструктуре; сущности и их мапинги для доктрины хранятся в отдельном месте.

Вот рассмотрим простейший пример. Есть 2 модели страна и город, и есть 2 похожие сущности для доктрины . Город должен быть в некой стране, страна имеет столицу(город).
Модель страны хранит в поле столицы - айдишник города. Модель города хранит в поле страны - айдишник страны.
Теперь реализуем их репозитории, которые должны возвращать доменные модели, разумеется, не сущности доктрины. Для этого им нужны методы для конвертации моделей в сущности и наоборот.
Рассмотрим запрос к репозиторию стран для поиска страны по айди.
  1. В методе репы страны мы переадресуем запрос к доктрине, она возвращает сущность страны
  2. Создаем модель страны с айдишником города в поле столицы. Тут нет проблем.
Теперь мы сохраняем страну, изменив столицу.
  1. Передаем репе в метод save модель страны с новый айдишником столицы.
  2. Чтобы доктрина сохранила это дело, нам нужно конвертнуть модель страны в сущность доктрины.
  3. Конвертируем простые поля без проблем и доходим до поля столицы.
  4. Оказывается, что нам нужно в поле столицы у сущности вставить не просто айдишник, а доктриновскую сущность города. Чтобы его получить, нам нужно сделать запрос к репозиторию городов. Окей, делаем.
  5. Но репы же возвращают нам не доктриновские сущности, а доменные модели ... Окей, конвертируем полученную модель города в сущность.
  6. Доходим до поля страны, а там опять у модели только айдишник и требуется как-то получить из айдишника страны сущность доктриновскую.
  7. Возвращаемся на шаг 3 и всё, приплыли.

Простите, не знаю, как это проще объяснить :)
 

Gutsy

Новичок
Я рекомендую так не делать, а заводить новую таблицу под каждую сущность из разных контекстов.

По поводу остального я не ничего не понял.
Извиняюсь, что непонятно излагаюсь, но тема не простая сама по себе.

Рассмотрим пример Цен. Цена в базе хранится простой строкой с небольшой мета-инфой и конечно айдишником. В контексте заказов для нас цена в таком виде вполне приемлема, но в другом контексте(назовем его "договорным") цена - это агрегат, который имеет разные связи.
Для каждого контекста заводить свои таблицы - не вижу возможным. Тогда будет слишком много дублирования и консистентность данных будет никакая.
Как вариант решения этой проблемы было решено создать отдельный слой, который бы обеспечивал отображения БД в коде, то есть ОРМ. Мы используем доктрину, поэтому этот слой у нас хранит просто все мапинги и entity(сущности) таблиц. В слое инфраструктуры прописаны реализации репозиториев, интерфейсы которых прописаны в слое домена. Эти репозитории, разумеется, как и многие места в коде, должны оперировать доменными моделями, не сущностями доктрины.
Проблема возникает в сохранении модели через репозиторий, когда пытаемся разобрать нашу доменную модель обратно в сущности доктрины(entity), чтобы доктрина всё сохранила в БД. Юз кейс примерный описан сообщением выше.

Спасибо еще раз всем за попытки помочь :)
 

fixxxer

К.О.
Партнер клуба
Если доктриновские entities использовать как persistence models, то надо уж мапить сразу весь aggregate root целиком. А с таким подходом, по-моему, проще оставить от доктрины один только квери билдер и делать "ручной датамаппер".
 

Вурдалак

Продвинутый новичок
Модель - это доменная модель, сущность - это entity, которая мапится в доктрине. Это разные классы: модель прописана в домене и некоторые в инфраструктуре; сущности и их мапинги для доктрины хранятся в отдельном месте.
Зачем тебе делать разделение на domain и persistence models (то, что ты называешь «моделью» и «сущностью» соответственно)? Doctrine тоже без проблем может оперировать id-шниками.

Цена в базе хранится простой строкой с небольшой мета-инфой и конечно айдишником.
Для меня это звучит бессмысленно. Это значит, что цены $42 и $42 — это разные цены, если у них разные id-шники. Что это значит?
 

WMix

герр M:)ller
Партнер клуба
оптовая цена от 20 шт., 42 EUR/St,
скидочная цена до 10.10.2010, 42 EUR/St
 

Gutsy

Новичок
Примеров, когда доменная модель не может быть напрямую замапина в доктрину просто масса. Цена - простейшая сущность. В одном контексте нас удовлетворяет только поле айди и сама цифра, в другом нам нужны связи, которые будут браться из какой-нибудь монги, а не только джоином из другой таблицы. Есть модель Отель, которая намного сложнее и просто кардинально отличается между контекстами. Тем более и собирается из разных БД.

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

Неужели у всех просто доменная модель мапится в доктрину и всё ?!?!
 

WMix

герр M:)ller
Партнер клуба
Цена одинаковая, условия при которых они действуют — разные.
у нас на каждого клиента на товар действует цена по которой он договорился с поставщиком, оптовая цена (на товар на клиента на количество) которую поставщик может установить чтоб сбагрить товар и еще возможно групповая цена для всех клиентов одной группы клиентов по которой договорился картель (бюргер кинг договорился для всех филиалов по германии). в итоге будет наименьшая удовлетворяющая всем условиям.
 

Вурдалак

Продвинутый новичок
В одном контексте нас удовлетворяет только поле айди и сама цифра
Это должно быть просто value object'ом. Нет никакого смысла в такой сущности.

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

Вурдалак

Продвинутый новичок
у нас на каждого клиента на товар действует цена по которой он договорился с поставщиком
У каждого клиента свой договор, но при этом могут быть прописаны одинаковые цены в них. Цена не станет «другой», если она совпадает, но находится в другом договоре.
 

WMix

герр M:)ller
Партнер клуба
одинаковой цены нет, это платформа купли/продажи товаров для огромного количества независимых поставщиков обьединенных в независимые группы. сколько стоит iphone7 в мире?
 

Adelf

Administrator
Команда форума
Я думаю он имеет ввиду понятие offer. С ценой, опциями и т.д.
 
Сверху