DDD, связность модулей

Обсуждаем, как правильно строить приложения
Аватара пользователя
ElisDN
Сообщения: 5459
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DDD, связность модулей

Сообщение ElisDN » 2017.02.24, 18:28

anton_z писал(а):
2017.02.24, 16:41
Не не не. Под SET amount = amount-10 я имею ввиду SQL выражение, именно таким запрос и пойдет в БД. Реляционная алгебра)
Я про конкурентность и пишу. Пока в консоли запускаете:

Код: Выделить всё

UPDATE table SET amount = amount - 10 WHERE ...;
в админке кто-то редактирует запись и сохраняет:

Код: Выделить всё

SELECT * FROM table WHERE id = 5;
if ($product->amount ...)  // 23
$product->amount = $model->amount - 20;
save($product);
UPDATE table SET amount = 3 WHERE id = 5
И получаете 3 вместо доменного ексепшена по -7. Так что блокировка всё равно понадобится.

paurlift
Сообщения: 26
Зарегистрирован: 2017.01.29, 20:16

Re: DDD, связность модулей

Сообщение paurlift » 2017.02.24, 21:37

anton_z писал(а):
2017.02.23, 16:16
По поводу интерфейсов. Никакие два модуля не могут ничего знать друг о друге. Даже об интерфейсах.
Вот чтобы даже об интерфейсах, как-то не очень похоже на правду.
У меня при создании комментария на вход приходит AuthorInterface, его реализует клиент или еще кто-то, кто может быть автором чего-либо на сайте, т.е. уже получается модуль отзывов знает о интерфейсах других модулей.
anton_z писал(а):
2017.02.23, 16:16
Каждый модуль должен объявлять интерфейсы для зависимостей, реализации которых ему должен предоставить КОРЕНЬ КОМПОНОВКИ (приложение). В корне компоновки могут содержаться адаптеры, обеспечивающие реализацию того или иного интерфейса модуля с помощью классов другого модуля. Например, в модуле интернет-магазина (ecommerce) у вас объявлен интерфейс для оплаты с помощью платежного агрегатора PaymentAggregatorInterface. У вас есть модуль для платежей через Robokassa, Interkassa и т.д. В приложении можете создать реализацию интерфейса PaymentAggregatorInterface с помощью данных модулей. Также можно сделать модуль-связку: rk-ecommerce и положить реализацию туда. В свою очередь модуль платежной системы может требовать реализацию какого-то своего интерфейса для обработки событий прихода денег, проверки возможности оплаты и.т.п. Реализация последнего также может находиться в корне компоновки или модуле-связке.

В итоге получаете два полностью независимых друг от доуга модуля (ecommerce, rk) и корень комноновки, который знает как их связать.
Про "корень компоновки" можно подробнее, а желательно на моем примере с модулем отзывов и модулем клиента. Все что Вы говорите очень похоже на ANTICORRUPTION LAYER (Адаптеры, фасады), но его использование оправдано когда есть две отдельные подсистемы (два разных контекста).
В Вашем примере получается создание каких-то модулей связок(тоже что-то новое для меня) на каждый агрегатор - Robokassa и ecommerce, Interkassa и ecommerce и т.д.
anton_z писал(а):
2017.02.23, 16:24
paurlift писал(а):
2017.02.23, 15:34
3.1) Mapper - это же инфраструктура? Почему он знает так много о domain?
Все могут знать о домене, в т.ч. инфраструктура. Не бывает независимой инфраструктуры. Она по природе своей пишется под конкретный домен. Домен не должен знать об инфраструктуре и других доменах. Он в центре системы.

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

zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DDD, связность модулей

Сообщение zelenin » 2017.02.24, 21:52

paurlift писал(а):
2017.02.24, 21:37
Вот чтобы даже об интерфейсах, как-то не очень похоже на правду.
У меня при создании комментария на вход приходит AuthorInterface, его реализует клиент или еще кто-то, кто может быть автором чего-либо на сайте, т.е. уже получается модуль отзывов знает о интерфейсах других модулей.
потому и знает об интерфейсе, поскольку вы его создали и расшарили, а надо было модель Author создать и адаптеры каких либо сущностей (Client / User) в сущность Author. Адаптеры не будут принадлежать ни первому ни второму модулю, но будут принадлежать модулю Application или Core (то, что anton_z называет корнем компоновки), который связывает остальные модули воедино.
paurlift писал(а):
2017.02.24, 21:37
Про "корень компоновки" можно подробнее, а желательно на моем примере с модулем отзывов и модулем клиента. Все что Вы говорите очень похоже на ANTICORRUPTION LAYER (Адаптеры, фасады), но его использование оправдано когда есть две отдельные подсистемы (два разных контекста).
у нас и есть независимые модули, независимые контексты, которые где-то надо привести к одному контексту - контексту приложения.
paurlift писал(а):
2017.02.24, 21:37
Слоенная архитектура не предполагает, что слои низшего уровня знают о слоях высших уровней. Инфраструктура самый низший уровень.
это не совсем так. инфраструктура - это собственно реализация доменных сервисов/репозиториев, а реализация не может не знать о том, что реализует.

paurlift
Сообщения: 26
Зарегистрирован: 2017.01.29, 20:16

Re: DDD, связность модулей

Сообщение paurlift » 2017.02.24, 22:26

ElisDN писал(а):
2017.02.23, 16:32
paurlift писал(а):
2017.02.23, 15:34
1.1) На сколько корректно когда entity из одного модуля создает entity из другого модуля?
Если такое необходимо, то это у Вас один модуль.
Если один, то как бы его Вы назвали и где бы Вы создавали отзыв? Отзыв могут оставлять не только клиенты. Да и клиенты еще могут писать на сайт посты на форум, создавать заявку в службу поддержки и т.д. (это я к тому, что так можно все действия связанные с клиентом свалить в один модуль, вместо того чтобы провести между модулями разумную грань в виде однонаправленной связности)
В моем случае - это точно 2 разных модуля.

ElisDN писал(а):
2017.02.23, 16:32
paurlift писал(а):
2017.02.23, 15:34
1.3) Местонахождения интерфейсов.
Если он нужен для review, то и кладите в review.
AuthorInterface - реализуют разные сущности и нужен он не только для review.
Я так понял, что для Вас нормальная ситуация, когда интерфейс лежит в одном модуле, а его реализация в другом? (Это своего рода тоже coupling, только за счет интерфейса менее критичный)
ElisDN писал(а):
2017.02.23, 16:32
paurlift писал(а):
2017.02.23, 15:34
3) Mapper или Repository знает о domain. Mapper - это же инфраструктура? Почему он знает так много о domain?
Естественно, что класс сохранения сущности в базу знает всё о сущности. Лишь бы не наоборот.
Не находите в этом нарушения слоенной архитектуры? Если то что мапер знает namespace модели, можно еще как-то отнести к исключению, то вот как Вы относитесь к явному созданию VO при сборке агрегата ($client->phoneNumbers[] = new PhoneNumber($phoneNumber);) ?
ElisDN писал(а):
2017.02.23, 16:32
paurlift писал(а):
2017.02.23, 15:34
4.1) У репозитория есть интерфейс, где он должен находится?
Интерфейс - в домене. Реализация - в инфраструктуре.
Я говорю здесь про репозиторий у которого нет домена. В application сервисе вызываю метод репозитория, который сохранит данные для аналитики. В этом случае где должен лежать интерфейс репозитория?
ElisDN писал(а):
2017.02.23, 16:32
paurlift писал(а):
2017.02.23, 15:34
7) Интефейсы инфраструктурных сервисов кладем на доменный уровень, чтобы не лишать себя возможности использовать их в Domain Service?
Интерфейс - в домене. Реализация - в инфраструктуре.
Я не понял, я правильно сформулировал причину? Пример, у меня есть инфраструктурный сервис отправляющий уведомления клиентам всеми доступными способами(email, sms). 90% случаев использования этого сервиса:

Код: Выделить всё

namespace application/payment;

use domain/contracts/infrastructure/NotificationServiceInterface;

class PaymentService
{
	public function __construct(NotificationServiceInterface $notificationService)
	{
		$this->notificationService = $notificationService;
	}
	
	public function execute()
	{
		// Оплата
		$this->notificationService->notify('success_buy', $client);
	}
}
Т.е. почти всегда это операционный уровень, и разумно было положить интерфейс NotificationServiceInterface куда-то на уровень application, у домена нет к нему никакой привязки. Но, завтра мне нужно его использовать в доменном сервисе, а интерфейс то уже лежит в application. Мне придется переносить интерфейс на доменный уровень.

paurlift
Сообщения: 26
Зарегистрирован: 2017.01.29, 20:16

Re: DDD, связность модулей

Сообщение paurlift » 2017.02.24, 22:43

zelenin писал(а):
2017.02.24, 21:52
paurlift писал(а):
2017.02.24, 21:37
Вот чтобы даже об интерфейсах, как-то не очень похоже на правду.
У меня при создании комментария на вход приходит AuthorInterface, его реализует клиент или еще кто-то, кто может быть автором чего-либо на сайте, т.е. уже получается модуль отзывов знает о интерфейсах других модулей.
потому и знает об интерфейсе, поскольку вы его создали и расшарили, а надо было модель Author создать и адаптеры каких либо сущностей (Client / User) в сущность Author. Адаптеры не будут принадлежать ни первому ни второму модулю, но будут принадлежать модулю Application или Core (то, что anton_z называет корнем компоновки), который связывает остальные модули воедино.
paurlift писал(а):
2017.02.24, 21:37
Про "корень компоновки" можно подробнее, а желательно на моем примере с модулем отзывов и модулем клиента. Все что Вы говорите очень похоже на ANTICORRUPTION LAYER (Адаптеры, фасады), но его использование оправдано когда есть две отдельные подсистемы (два разных контекста).
у нас и есть независимые модули, независимые контексты, которые где-то надо привести к одному контексту - контексту приложения.

Спасибо, стоит для модулей тоже использовать anticorruption layer.
zelenin писал(а):
2017.02.24, 21:52
paurlift писал(а):
2017.02.24, 21:37
Слоенная архитектура не предполагает, что слои низшего уровня знают о слоях высших уровней. Инфраструктура самый низший уровень.
это не совсем так. инфраструктура - это собственно реализация доменных сервисов/репозиториев, а реализация не может не знать о том, что реализует.
Реализация доменных сервисов - это инфраструктура? Можете пример какой-нибудь привести? Реализация репозитория - да, это инфраструктура. Ну вот когда реализация репозитория, которая в инфраструктуре находится, начинает много чего знать о домене, мне кажется, это прямое нарушение слоев. Допускаю, как исключение, что репозиторий будет знать о namespace модели + знать о названиях её свойств, которые ему нужно заполнить. А желательно это вынести в какой-то конфиг файл. (как в Doctrine). В Yii я делаю это в container.

zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DDD, связность модулей

Сообщение zelenin » 2017.02.24, 22:47

paurlift писал(а):
2017.02.24, 22:26
Если один, то как бы его Вы назвали и где бы Вы создавали отзыв? Отзыв могут оставлять не только клиенты. Да и клиенты еще могут писать на сайт посты на форум, создавать заявку в службу поддержки и т.д. (это я к тому, что так можно все действия связанные с клиентом свалить в один модуль, вместо того чтобы провести между модулями разумную грань в виде однонаправленной связности)
В моем случае - это точно 2 разных модуля.
он намекает, что у вас этот модуль протек во все остальные - не независим.
paurlift писал(а):
2017.02.24, 22:26
Не находите в этом нарушения слоенной архитектуры? Если то что мапер знает namespace модели, можно еще как-то отнести к исключению, то вот как Вы относитесь к явному созданию VO при сборке агрегата ($client->phoneNumbers[] = new PhoneNumber($phoneNumber);) ?
маппер - это то, что маппит непосредственно результат выборки из хранилища к конкретной сущности. то есть маппер не может не знать о об этой сущности (другое дело, что сам маппинг может быть описан в конфигах или в фабрике, но это детали реализации)
paurlift писал(а):
2017.02.24, 22:26
Я говорю здесь про репозиторий у которого нет домена. В application сервисе вызываю метод репозитория, который сохранит данные для аналитики. В этом случае где должен лежать интерфейс репозитория?
там же в application
paurlift писал(а):
2017.02.24, 22:26
Я не понял, я правильно сформулировал причину? Пример, у меня есть инфраструктурный сервис отправляющий уведомления клиентам всеми доступными способами(email, sms). 90% случаев использования этого сервиса:

Код: Выделить всё

namespace application/payment;

use domain/contracts/infrastructure/NotificationServiceInterface;

class PaymentService
{
	public function __construct(NotificationServiceInterface $notificationService)
	{
		$this->notificationService = $notificationService;
	}
	
	public function execute()
	{
		// Оплата
		$this->notificationService->notify('success_buy', $client);
	}
}
Т.е. почти всегда это операционный уровень, и разумно было положить интерфейс NotificationServiceInterface куда-то на уровень application, у домена нет к нему никакой привязки. Но, завтра мне нужно его использовать в доменном сервисе, а интерфейс то уже лежит в application. Мне придется переносить интерфейс на доменный уровень.
инфраструктура - это инфраструктура не приложения, а доменного слоя. то есть сервис приложения должен находиться в слое приложения (и интерфейс и реализация). Если понадобятся уведомления в доменном слое, тогда создадите новый интерфейс в домене и реализуете его в инфра.

zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DDD, связность модулей

Сообщение zelenin » 2017.02.24, 22:58

paurlift писал(а):
2017.02.24, 22:43
Реализация доменных сервисов - это инфраструктура?
именно
собственно название само за себя говорит. вы создаете рабочую инфраструктуру для работы доменного слоя.
paurlift писал(а):
2017.02.24, 22:43
Можете пример какой-нибудь привести?
не понимаю, какие примеры надо? тут все как везде. интерфейс, реализация
paurlift писал(а):
2017.02.24, 22:43
Реализация репозитория - да, это инфраструктура. Ну вот когда реализация репозитория, которая в инфраструктуре находится, начинает много чего знать о домене, мне кажется, это прямое нарушение слоев.
это инфраструктура - воспринимайте это слово не как термин DDD, а в общем смысле - обслуживание определенной области чего-либо. Инфраструктура района, инфраструктура гостиницы, инфраструктура города. Инфраструктура может знать о домене, т.к. она домен непосредственно обслуживает. Она не может и не должна обслуживать другой слой через адаптеры, т.к. это не имеет смысла. Инфраструктура существует для конкретного домена. Естественно надо ограничить знания, чтобы не размазывать его по многим местам, например сущности создавать через доменные фабрики, но это не вопрос слоев, а вопрос чистой архитектуры и разделения ответственностей.

Аватара пользователя
ElisDN
Сообщения: 5459
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DDD, связность модулей

Сообщение ElisDN » 2017.02.25, 00:19

paurlift писал(а):
2017.02.24, 22:26
Если один, то как бы его Вы назвали и где бы Вы создавали отзыв?
Отзывы к товарам магазина у меня в модуле "Магазин". Отзывы к фирмам - в модуле "Каталог организаций". А "отзывы" или "категории" - это не совсем модули.
paurlift писал(а):
2017.02.24, 22:26
Отзыв могут оставлять не только клиенты. Да и клиенты еще могут писать на сайт посты на форум, создавать заявку в службу поддержки и т.д. (это я к тому, что так можно все действия связанные с клиентом свалить в один модуль, вместо того чтобы провести между модулями разумную грань в виде однонаправленной связности)
Это называют ограниченными контекстами. Обычно взаимодействующими через доменные события. При этом и однонаправленные связи между ними оказываются не нужны: http://www.elisdn.ru/blog/86/module-relations-on-yii2
paurlift писал(а):
2017.02.24, 22:26

Я так понял, что для Вас нормальная ситуация, когда интерфейс лежит в одном модуле, а его реализация в другом? (Это своего рода тоже coupling, только за счет интерфейса менее критичный)
Не нормальная. Нормальная - это когда между модулями есть трансформер, преобразующий объекты одного модуля к интерфейсам другого:

Код: Выделить всё

[ модуль 1: интерфейс 1 ] <- конвертер -> [ модуль 2: интерфейс 2 ]
paurlift писал(а):
2017.02.24, 22:26
Не находите в этом нарушения слоенной архитектуры? Если то что мапер знает namespace модели, можно еще как-то отнести к исключению, то вот как Вы относитесь к явному созданию VO при сборке агрегата?
Репозиторию нужно их как-то создавать. Если не получается явно из-за хитрого конструктора, то создавайте через рефлексию как сущности. Инфраструктура - это не самостоятельный слой.
paurlift писал(а):
2017.02.24, 22:26
Я говорю здесь про репозиторий у которого нет домена. В application сервисе вызываю метод репозитория, который сохранит данные для аналитики. В этом случае где должен лежать интерфейс репозитория?
Создайте папку analytics. Но я аналитику через события собираю.
paurlift писал(а):
2017.02.24, 22:26
Т.е. почти всегда это операционный уровень... Мне придется переносить интерфейс на доменный уровень.
Поставите курсор на имя интерфейса в PhpStorm, нажмёте F6, поменяете namespace и нажмёте Enter.

paurlift
Сообщения: 26
Зарегистрирован: 2017.01.29, 20:16

Re: DDD, связность модулей

Сообщение paurlift » 2017.02.25, 16:33

zelenin писал(а):
2017.02.24, 22:58
paurlift писал(а):
2017.02.24, 22:43
Реализация доменных сервисов - это инфраструктура?
именно
собственно название само за себя говорит. вы создаете рабочую инфраструктуру для работы доменного слоя.
paurlift писал(а):
2017.02.24, 22:43
Можете пример какой-нибудь привести?
не понимаю, какие примеры надо? тут все как везде. интерфейс, реализация
paurlift писал(а):
2017.02.24, 22:43
Реализация репозитория - да, это инфраструктура. Ну вот когда реализация репозитория, которая в инфраструктуре находится, начинает много чего знать о домене, мне кажется, это прямое нарушение слоев.
это инфраструктура - воспринимайте это слово не как термин DDD, а в общем смысле - обслуживание определенной области чего-либо. Инфраструктура района, инфраструктура гостиницы, инфраструктура города. Инфраструктура может знать о домене, т.к. она домен непосредственно обслуживает. Она не может и не должна обслуживать другой слой через адаптеры, т.к. это не имеет смысла. Инфраструктура существует для конкретного домена. Естественно надо ограничить знания, чтобы не размазывать его по многим местам, например сущности создавать через доменные фабрики, но это не вопрос слоев, а вопрос чистой архитектуры и разделения ответственностей.
Пример доменного сервиса - CreateOrderFromCart. Он создает объект заказа(Entity) из корзины (VO). Вот я никак не могу представить, чтобы реализация находилась на инфраструктурном уровне. Т.е. инфраструктура должна создавать domain объекты. Не получается к инфраструктуре относится, как не к слою в разрезе слоенной архитектуры (DDD тут даже не при чем, но слоенная архитектура, часто используемый архитектурный патерн совместно с DDD)
Вот никак это не может уложиться у меня в голове, можете ссылку на какой-нибудь проверенный источник дать?

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

zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DDD, связность модулей

Сообщение zelenin » 2017.02.25, 18:30

paurlift писал(а):
2017.02.25, 16:33
Пример доменного сервиса - CreateOrderFromCart. Он создает объект заказа(Entity) из корзины (VO). Вот я никак не могу представить, чтобы реализация находилась на инфраструктурном уровне.
из описания следует, что это сервис без зависимостей, т.е. может быть реализован в рамках домена.

Аватара пользователя
ElisDN
Сообщения: 5459
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DDD, связность модулей

Сообщение ElisDN » 2017.02.26, 11:31

paurlift писал(а):
2017.02.25, 16:33
Пример доменного сервиса - CreateOrderFromCart. Он создает объект заказа(Entity) из корзины (VO). Вот я никак не могу представить, чтобы реализация находилась на инфраструктурном уровне.
Domain\Service\CreateOrderFromCart - самодостаточный доменный сервис. Делаем классом. Но ему (или соседнему сервису регистрации пользователя) может понадобиться хешер паролей Domain\Service\PasswordHasher, если нужно автоматом создать пользователя при быстром заказе.

Этот хешер паролей - тоже доменный сервис, но уже зависящий от средств фреймворка. Просто классом в домене мы его сделать не сможем. Поэтому в домене вместо класса объявляем его интерфейсом:

Код: Выделить всё

namespase Domain\Service;

use Domain\Entity\User\Password;
use Domain\Entity\User\Hash;

interface PasswordHasher
{
    function hash(Password $password): Hash;
    function validate(Password $password, Hash $hash): bool;
}
который работает с VO домена.

А реализацию уже делаем в инфраструктуре:

Код: Выделить всё

namespase Infrastructure\Service;

use Domain\Service\PasswordHasher;
use Domain\Entity\User\Password;
use Domain\Entity\User\Hash;

class YiiPasswordHasher implements PasswordHasher;
{
    function hash(Password $password): Hash
    {
        return new Hash(Yii::$app->security->generatePasswordHash($password->getValue()));
    }
    ...
}
и настраиваем в контейнере его привязку к интерфейсу.

В итоге контроллер дёргает сервис приложения, он дёргает доменные сервисы, доменные репозитории и управляет доменными сущностями и VO. Но при этом ни контроллер, ни приложение, ни домен не догадываются, что есть какая-то там инфраструктура и что половина сервисов подменены интерфейсами и реализованы в ней. Единственное упоминание инфраструктурных классов имеется только в настройках контейнера. В итоге "инфраструктура" здесь - это полностью невидимый слой-адаптер, реализующий взаимодействие с внутренностями фреймворка.

paurlift
Сообщения: 26
Зарегистрирован: 2017.01.29, 20:16

Re: DDD, связность модулей

Сообщение paurlift » 2017.02.26, 13:01

zelenin писал(а):
2017.02.24, 21:52
paurlift писал(а):
2017.02.24, 21:37
Вот чтобы даже об интерфейсах, как-то не очень похоже на правду.
У меня при создании комментария на вход приходит AuthorInterface, его реализует клиент или еще кто-то, кто может быть автором чего-либо на сайте, т.е. уже получается модуль отзывов знает о интерфейсах других модулей.
потому и знает об интерфейсе, поскольку вы его создали и расшарили, а надо было модель Author создать и адаптеры каких либо сущностей (Client / User) в сущность Author. Адаптеры не будут принадлежать ни первому ни второму модулю, но будут принадлежать модулю Application или Core (то, что anton_z называет корнем компоновки), который связывает остальные модули воедино.
В итоге получается что-то такое, если я правильно понял:

Код: Выделить всё



namespace application\reviews;

use domain\base\TransactionManagerInterface;
use domain\client\ClientRepositoryInterface;
use domain\client\ManageReviewInterface;
use domain\reviews\ReviewRepositoryInterface;

class CreateReviewService extends ApplicationService
{
    public function __construct(
        ClientRepositoryInterface $clientRepository,
        TransactionManagerInterface $transactionManager,
        ReviewRepositoryInterface $reviewRepository,
        ManageReviewInterface $clientAuthor
    ){
        $this->transactionManager = $transactionManager;
        $this->clientRepository = $clientRepository;
        $this->reviewRepository = $reviewRepository;
        $this->clientAuthor = $clientAuthor;
    }

    public function execute($paceId, $reviewDto)
    {
        $client = $this->clientRepository->findById($this->currentClient->id);
        $this->clientAuthor->setClient($client);

        $this->transactionManager->beginTransaction();

        try {
            $reviewId = $this->reviewRepository->nextIdentity();
            $review = $this->clientAuthor->createReview($reviewId, $paceId, $reviewDto);
            $this->reviewRepository->save($review);
            $this->transactionManager->commit();
        } catch (\Exception $e){
            $this->transactionManager->rollback();
        }
    }
}

--------------------

namespace anticoruption\clientReviews;

use domain\client\Client;
use domain\client\ManageReviewInterface;
use domain\reviews\AuthorInterface;
use domain\reviews\Review;
use domain\reviews\ReviewDto;

class ClientAuthor implements ManageReviewInterface, AuthorInterface
{
    private $client;

    public function setClient(Client $client)
    {
        $this->client = $client;
    }

    public function createReview($reviewId, $paceId, ReviewDto $reviewDto)
    {
        return new Review($reviewId, $paceId, $reviewDto, $this);
    }

    public function getAuthorFullName()
    {
        return $this->client->name . ' ' . $this->client->surname;
    }
}

-----------------------

namespace  domain\reviews;

interface AuthorInterface
{
    public function getAuthorFullName();
}

-----------------------

namespace domain\client;

use domain\reviews\ReviewDto;

interface ManageReviewInterface
{
    public function createReview($reviewId, $placeId, ReviewDto $reviewDto);
}


zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DDD, связность модулей

Сообщение zelenin » 2017.02.26, 13:18

ну допустим, но дизайн всего этого престраннейший.
при таком подходе интерфейсы сущностей не нужны.
domain\reviews\Author
domain\client\Client
application\reviews\AuthorClientTransformer
плюс Dto не место в домене - это обычно слой Application и используются для создания сущностей домена в сервисах приложения (напрямую в конструктор сущности не передаются).

paurlift
Сообщения: 26
Зарегистрирован: 2017.01.29, 20:16

Re: DDD, связность модулей

Сообщение paurlift » 2017.02.26, 15:34

ElisDN писал(а):
2017.02.26, 11:31

Код: Выделить всё

namespase Domain\Service;

use Domain\Entity\User\Password;
use Domain\Entity\User\Hash;

interface PasswordHasher
{
    function hash(Password $password): Hash;
    function validate(Password $password, Hash $hash): bool;
}
который работает с VO домена.

А реализацию уже делаем в инфраструктуре:

Код: Выделить всё

namespase Infrastructure\Service;

use Domain\Service\PasswordHasher;
use Domain\Entity\User\Password;
use Domain\Entity\User\Hash;

class YiiPasswordHasher implements PasswordHasher;
{
    function hash(Password $password): Hash
    {
        return new Hash(Yii::$app->security->generatePasswordHash($password->getValue()));
    }
    ...
}
и настраиваем в контейнере его привязку к интерфейсу.

В итоге контроллер дёргает сервис приложения, он дёргает доменные сервисы, доменные репозитории и управляет доменными сущностями и VO. Но при этом ни контроллер, ни приложение, ни домен не догадываются, что есть какая-то там инфраструктура и что половина сервисов подменены интерфейсами и реализованы в ней. Единственное упоминание инфраструктурных классов имеется только в настройках контейнера. В итоге "инфраструктура" здесь - это полностью невидимый слой-адаптер, реализующий взаимодействие с внутренностями фреймворка.
Вы интерфейсы инфраструктурных сервисов располагаете в папке Domain/Service ?
Реализацию инфраструктурных сервисов в папку Infrastructure/Service ? Я делаю так - infrastructure/paswordHasher - а уже в неё YiiPasswordHasher.

paurlift
Сообщения: 26
Зарегистрирован: 2017.01.29, 20:16

Re: DDD, связность модулей

Сообщение paurlift » 2017.02.26, 15:59

zelenin писал(а):
2017.02.26, 13:18
ну допустим, но дизайн всего этого престраннейший.
Пожалуйста, конкретнее и как бы Вы сделали? Что-то может быть упустил, писал "на коленке".
zelenin писал(а):
2017.02.26, 13:18
при таком подходе интерфейсы сущностей не нужны.
domain\reviews\Author
domain\client\Client
Нужны, нет у меня модели Author как таковой, а есть интерфейс AuthorInterface. А его уже должны реализовывать AuthorClientTransformer, AuthorPartnerTransformer, AuthorManagerTransformer. А в конструктор отзыва должен всегда приходить AuthorInterface.
zelenin писал(а):
2017.02.26, 13:18
application\reviews\AuthorClientTransformer
Вы AuthorClientTransformer отнесли к операционному уровню? Я думаю, для адаптеров и фасадов хорошо выделять свой уровень (предохранительный)
zelenin писал(а):
2017.02.26, 13:18
плюс Dto не место в домене - это обычно слой Application и используются для создания сущностей домена в сервисах приложения
Я в самом первом посте об этом спросил, ElisDN ответил, что использовать его можно везде, это просто удобная замена массивам и я с ним согласен.
zelenin писал(а):
2017.02.26, 13:18
(напрямую в конструктор сущности не передаются).
А VO можно передавать? Я передаю AuthorInterface, а не сущность.

Аватара пользователя
ElisDN
Сообщения: 5459
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DDD, связность модулей

Сообщение ElisDN » 2017.02.26, 22:02

paurlift писал(а):
2017.02.26, 15:59
Нужны, нет у меня модели Author как таковой, а есть интерфейс AuthorInterface.
Вот и советуем сделать отдельную сущность review\Author вместо интерфейса AuthorInterface. Это если очень хочется сделать review именно отдельной системой.
Последний раз редактировалось ElisDN 2017.02.26, 22:32, всего редактировалось 2 раза.

Аватара пользователя
ElisDN
Сообщения: 5459
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DDD, связность модулей

Сообщение ElisDN » 2017.02.26, 22:16

paurlift писал(а):
2017.02.26, 15:59
Я в самом первом посте об этом спросил, ElisDN ответил, что использовать его можно везде, это просто удобная замена массивам и я с ним согласен.
По определению DTO это объект передачи данных. Передачи между слоями или сервисами. Идеально подходит как замена ассоциативному массиву для передачи больших наборов полей. Например, из контроллера в сервис приложения или из сервиса приложения в сервис домена. А в сущности их передавать особо не имеет смысла, так как вместо них там уже есть удобные VO.

Аватара пользователя
ElisDN
Сообщения: 5459
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DDD, связность модулей

Сообщение ElisDN » 2017.02.26, 22:32

paurlift писал(а):
2017.02.26, 15:34
Вы интерфейсы инфраструктурных сервисов располагаете в папке Domain/Service ?
Реализацию инфраструктурных сервисов в папку Infrastructure/Service ? Я делаю так - infrastructure/paswordHasher - а уже в неё YiiPasswordHasher.
Раскладываю по смыслу:

Код: Выделить всё

Domain/
    Service/
        Geo/
            Coder.php
            Address.php
            Coordinate.php
        PasswordHasher.php

paurlift
Сообщения: 26
Зарегистрирован: 2017.01.29, 20:16

Re: DDD, связность модулей

Сообщение paurlift » 2017.02.26, 22:53

ElisDN писал(а):
2017.02.26, 22:02
paurlift писал(а):
2017.02.26, 15:59
Нужны, нет у меня модели Author как таковой, а есть интерфейс AuthorInterface.
Вот и советуем сделать отдельную сущность review\Author вместо интерфейса AuthorInterface. Это если очень хочется сделать review именно отдельной системой.
Мне хотелось узнать как подружить 2 модуля в первую очередь и Ваши советы очень помогли, спасибо всем кто отвечал.

Думал создать модель автора и вопросы бы все отпали, кроме одного:
1) Если создам модель автор, то мне нужен будет репозиторий для автора в модуле reviews, автор - клиент и автор - менеджер службы поддержки лежат в разных таблицах.

Аватара пользователя
ElisDN
Сообщения: 5459
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DDD, связность модулей

Сообщение ElisDN » 2017.02.26, 23:08

paurlift писал(а):
2017.02.26, 22:53
Если создам модель автор, то мне нужен будет репозиторий для автора в модуле reviews, автор - клиент и автор - менеджер службы поддержки лежат в разных таблицах.
В методе get($id, $type) ищите в нужной таблице в зависимости от $type.

Ответить