Наверняка обсуждалось тут, но что-то не могу припомнить когда...
Итак, имеем сл. картинку -- тыц.
1)Правильно ли я понимаю, что слой controller'ов взаимодействие с *Service? Скорее всего это так.
2)Далее, а вот контроллер в кач-ве параметров в тот или иной *service должен передавать DTO или бизнес сущность? И соотв. получать от *Service должен уже DTO или сущность? Или он просто DTO прокидывает и возвращает тоже DTO? Т.е. в задачи контроллера входить отображения DTO в бизнес сущности или нет? Судя по картинке,
DTO и AppService в одном слое, поэтому AppService должен что-то знать о DTO?
Здравствуйте, Sharov, Вы писали:
S>1)Правильно ли я понимаю, что слой controller'ов взаимодействие с *Service? Скорее всего это так.
Да
S>2)Далее, а вот контроллер в кач-ве параметров в тот или иной *service должен передавать DTO или бизнес сущность? И соотв. получать от *Service должен уже DTO или сущность? Или он просто DTO прокидывает и возвращает тоже DTO? Т.е. в задачи контроллера входить отображения DTO в бизнес сущности или нет?
Да, в задачи контроллера входит преобразование из DTO в сущности и наоборот. Это его основная и единственная задача.
Принимает DTO, преобразовывает в сущности, вызывает сервисы, получает от них сущности, отдает DTO.
S>Судя по картинке, DTO и AppService в одном слое, поэтому AppService должен что-то знать о DTO?
Нет, не должны. AppService является фасадом приложения, делает всю полезную работу, оперирует бизнес-сущностями, а не DTO.
Здравствуйте, Буравчик, Вы писали:
Б>Нет, не должны. AppService является фасадом приложения, делает всю полезную работу, оперирует бизнес-сущностями, а не DTO.
Благодарю, еще вдогонку вопрос: а это нормально, если у меня AppService зависит от нескольких репозиториев. SRP не нарушается. Или по DDD -- 1 к 1?
Здравствуйте, Sharov, Вы писали:
S>Благодарю, еще вдогонку вопрос: а это нормально, если у меня AppService зависит от нескольких репозиториев. SRP не нарушается. Или по DDD -- 1 к 1?
Если несколько зависимостей (репозиториев), то нормально.
Если слишком много — то вероятно SRP нарушается, класс делает слишком много.
Если 1:1 — то может нормально, но может абстракции (интерфейсы) неправильно выбраны, и часть кода должно уйти из сервиса в репозиторий.
Здравствуйте, Sharov, Вы писали:
S>Здравствуйте.
S>Наверняка обсуждалось тут, но что-то не могу припомнить когда...
Такое тут всегда обсуждается.
S>Итак, имеем сл. картинку -- тыц.
Так себе картинка
S>1)Правильно ли я понимаю, что слой controller'ов взаимодействие с *Service? Скорее всего это так.
Да. Верхние слои вызывают нижние слои. Не наоборот.
S>2)Далее, а вот контроллер в кач-ве параметров в тот или иной *service должен передавать DTO или бизнес сущность? И соотв. получать от *Service должен уже DTO или сущность? Или он просто DTO прокидывает и возвращает тоже DTO? Т.е. в задачи контроллера входить отображения DTO в бизнес сущности или нет? Судя по картинке,
Получать IQueryable<BusinessEntity>, передавать BusinessEnitty, может несколько.
S>DTO и AppService в одном слое, поэтому AppService должен что-то знать о DTO?
DTO это не слой. Они логики не содержат. Более логично было бы на картинке нарисовать DTO в слое Presentation.
Здравствуйте, Sharov, Вы писали:
S>Здравствуйте, Буравчик, Вы писали:
Б>>Нет, не должны. AppService является фасадом приложения, делает всю полезную работу, оперирует бизнес-сущностями, а не DTO.
S>Благодарю, еще вдогонку вопрос: а это нормально, если у меня AppService зависит от нескольких репозиториев. SRP не нарушается. Или по DDD -- 1 к 1?
Это не нормально. репозитории вообще надо выкинуть и сжечь.
S>>Итак, имеем сл. картинку -- тыц. G>Так себе картинка
Почему, если не секрет?
S>>2)Далее, а вот контроллер в кач-ве параметров в тот или иной *service должен передавать DTO или бизнес сущность? И соотв. получать от *Service должен уже DTO или сущность? Или он просто DTO прокидывает и возвращает тоже DTO? Т.е. в задачи контроллера входить отображения DTO в бизнес сущности или нет? Судя по картинке, G>Получать IQueryable<BusinessEntity>, передавать BusinessEnitty, может несколько.
Это для *Service слоя от контроллера? Или что это?
S>>DTO и AppService в одном слое, поэтому AppService должен что-то знать о DTO? G>DTO это не слой. Они логики не содержат. Более логично было бы на картинке нарисовать DTO в слое Presentation.
Presentations -- это уже View. Высоковато, наверное.
Здравствуйте, Sharov, Вы писали:
S>Здравствуйте, gandjustas, Вы писали:
S>>>Итак, имеем сл. картинку -- тыц. G>>Так себе картинка
S>Почему, если не секрет?
Потому что слои это "кто кого вызывает". А на картинке много путаницы в этом плане.
S>>>2)Далее, а вот контроллер в кач-ве параметров в тот или иной *service должен передавать DTO или бизнес сущность? И соотв. получать от *Service должен уже DTO или сущность? Или он просто DTO прокидывает и возвращает тоже DTO? Т.е. в задачи контроллера входить отображения DTO в бизнес сущности или нет? Судя по картинке, G>>Получать IQueryable<BusinessEntity>, передавать BusinessEnitty, может несколько.
S>Это для *Service слоя от контроллера? Или что это?
Контроллер вызывает app service. Следуя парадигме CQRS, когда запрос данных и команды на изменение это разные методы, то у нас есть две категории методов — "получить данные" или "отправить команду на изменение".
То что "получить данные" возвращает IQueryable<BusinessEntity>, а то что "отправить команду на изменение" в качестве параметров принимает BusinessEntity или другие скалярные параметры.
Контроллеры занимаются:
— валидацией данных от клиента
— мэппингом в обе стороны
— кешированием (особенно HTTP)
— аутентификацией и, если возможно, авторизацией.
— обработкой ошибок (чтобы не вываливать клиенту стектрейс)
И больше никакой код этим не занимается.
Теперь вернемся к вопросу "что не так на картинке"... много чего.
Такой вопрос -- вот у меня appsrv получает извне файл, по типу файла(расширение) создает обработчик. Обработчик похож
на domainsrv, ибо специфические вещи происходят на ряду с просто сохранением файла в хранилище. Так вот, я этот domainsrv
создаю в appsrv при помощи фабрики, на основе типа файла. Это нормальная практика создавать доменные сервисы с
помощью фабрики? Или я что-то не так делаю. Т.е. с одной стороны не SL (ибо анти-паттерн), с другой стороны я динамически
создаю некий типизированный доменный сервис. Это как-то в DDD укладывается?
Что-то вроде:
IFileHandlerService handler = null;
switch(fileEnum)
{
case fileEnum.TypeA:
handler = _fileHandlerSrvFactory.CreateTypeAFileHandlerSrv();
break;
case fileEnum.TypeB:
handler = _fileHandlerSrvFactory.CreateTypeBFileHandlerSrv();
break;
default:
throw new ArgumentOutOfRangeException();
}
Здравствуйте, Sharov, Вы писали:
S>Это как-то в DDD укладывается?
В современном понимании DDD прежде всего не про паттерны или набор каких-то классов, а про аналитическую часть. То есть про то, как эксперты предметной области работают с технарями и насколько точно в итоге ваша модель отражает область, с короторый вы работаете. Насколько хорошо там определены контексты и изолированы друг от друга (то есть изменение в одном не затрагивает другие). А всякие конкретные технические решения вторичны. Например, репозитории, которые в связке с EF точно не нужны. Это я всё к тому, что ваш вопрос мало отношения имеет к DDD, это просто один из технических приёмов
Здравствуйте, Буравчик, Вы писали:
Б>Да, в задачи контроллера входит преобразование из DTO в сущности и наоборот. Это его основная и единственная задача. Б>Принимает DTO, преобразовывает в сущности, вызывает сервисы, получает от них сущности, отдает DTO.
Вот здесь несколько иная точка зрения
Makes you feel like you are pulling the guts out right? According to Martin Fowler: the Service Layer defines the application's boundery, it encapsulates the domain. In other words it protects the domain.
Если показать контроллеру сущности, то это означает выпустить их за пределы домена в слой представления.
и ниже
If you use domain models in your presentation layer (MVC-Controllers/View, WebForms, ConsoleApp), then the presentation layer is tightly coupled to your domain, any changes in the domain requires you to change your controllers.
Так что DTO — это объекты для взаимодействия контроллера с сервисом, а в сущности должен преобразовывать сервис, и он же должен возвращать DTO.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, Буравчик, Вы писали:
Б>>Да, в задачи контроллера входит преобразование из DTO в сущности и наоборот. Это его основная и единственная задача. Б>>Принимает DTO, преобразовывает в сущности, вызывает сервисы, получает от них сущности, отдает DTO.
PD>Вот здесь несколько иная точка зрения
PD>Makes you feel like you are pulling the guts out right? According to Martin Fowler: the Service Layer defines the application's boundery, it encapsulates the domain. In other words it protects the domain.
PD>https://stackoverflow.com/questions/21554977/should-services-always-return-dtos-or-can-they-also-return-domain-models
PD>Если показать контроллеру сущности, то это означает выпустить их за пределы домена в слой представления.
Ну и что, изменения в интерфейсе не потребуют изменения в домене, т.е. он "изолирован".
PD>и ниже
PD>If you use domain models in your presentation layer (MVC-Controllers/View, WebForms, ConsoleApp), then the presentation layer is tightly coupled to your domain, any changes in the domain requires you to change your controllers.
PD>Так что DTO — это объекты для взаимодействия контроллера с сервисом, а в сущности должен преобразовывать сервис, и он же должен возвращать DTO.
Выделять отдельный слой с функцией "изолятора" и работы с сущностными не лучшая идея. Я пробовал так, все время кажется, что он тут лишний.
Здравствуйте, Qulac, Вы писали:
PD>>Makes you feel like you are pulling the guts out right? According to Martin Fowler: the Service Layer defines the application's boundery, it encapsulates the domain. In other words it protects the domain.
PD>>https://stackoverflow.com/questions/21554977/should-services-always-return-dtos-or-can-they-also-return-domain-models
PD>>Если показать контроллеру сущности, то это означает выпустить их за пределы домена в слой представления.
Q>Ну и что, изменения в интерфейсе не потребуют изменения в домене, т.е. он "изолирован".
Если он виден presentation layer, то он не изолирован
Q>Выделять отдельный слой с функцией "изолятора" и работы с сущностными не лучшая идея. Я пробовал так, все время кажется, что он тут лишний.
Зачем отдельный слой ? Сервис и есть этот слой. Выделил в цитате выше.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, Qulac, Вы писали:
PD>>>Makes you feel like you are pulling the guts out right? According to Martin Fowler: the Service Layer defines the application's boundery, it encapsulates the domain. In other words it protects the domain.
PD>>>https://stackoverflow.com/questions/21554977/should-services-always-return-dtos-or-can-they-also-return-domain-models
PD>>>Если показать контроллеру сущности, то это означает выпустить их за пределы домена в слой представления.
Q>>Ну и что, изменения в интерфейсе не потребуют изменения в домене, т.е. он "изолирован".
PD>Если он виден presentation layer, то он не изолирован
Смотря что понимать под "изолированостью".
Q>>Выделять отдельный слой с функцией "изолятора" и работы с сущностными не лучшая идея. Я пробовал так, все время кажется, что он тут лишний.
PD>Зачем отдельный слой ? Сервис и есть этот слой. Выделил в цитате выше.
Все равно лишний. Сервисы могут пригодится когда нужно выделить общий функционал у разных видом интерфейсов приложения, а так они не нужны. Зачем плодить лишние сущности?
Здравствуйте, Qulac, Вы писали:
PD>>Если показать контроллеру сущности, то это означает выпустить их за пределы домена в слой представления.
Q>Ну и что, изменения в интерфейсе не потребуют изменения в домене, т.е. он "изолирован".
Вот приходит запрос на получение документа. Документ — сложная сущность, для сборки которой надо залезть в несколько таблиц БД и дернуть сторонний сервис по http. Если это все будет делать контроллер, то чем займется следующий слой?
Имхо контроллеры это чисто утилитарный слой, в котором не должно быть никакой логики. Если говорить конкретно про asp net контроллеры, то их задача — описать интерфейс модуля в терминах http и заодно взять на себя автоматический вызов авторизации, валидации и маршрутизации запроса в нужный обработчик. Отсюда следует, что для контроллеров не нужны юнит тесты т.к. там нечего тестировать.
Здравствуйте, MaxRos, Вы писали:
MR>Здравствуйте, Qulac, Вы писали:
PD>>>Если показать контроллеру сущности, то это означает выпустить их за пределы домена в слой представления.
Q>>Ну и что, изменения в интерфейсе не потребуют изменения в домене, т.е. он "изолирован".
MR>Вот приходит запрос на получение документа. Документ — сложная сущность, для сборки которой надо залезть в несколько таблиц БД и дернуть сторонний сервис по http. Если это все будет делать контроллер, то чем займется следующий слой?
MR>Имхо контроллеры это чисто утилитарный слой, в котором не должно быть никакой логики. Если говорить конкретно про asp net контроллеры, то их задача — описать интерфейс модуля в терминах http и заодно взять на себя автоматический вызов авторизации, валидации и маршрутизации запроса в нужный обработчик. Отсюда следует, что для контроллеров не нужны юнит тесты т.к. там нечего тестировать.
А контролеры нельзя протестировать, по моему запросто.
Домен может содержать сервисы по бизнес логике, но это бизнес логика, а не что то добавленное из вне.
Здравствуйте, Qulac, Вы писали:
Q>А контролеры нельзя протестировать, по моему запросто.
В asp.net core можно тестировать контроллеры очень просто, но на уровне интеграционных тестов, они как раз позволят проверить работу всей обвязки вокруг контроллеров включая вызов бизнес логики.
Q>Домен может содержать сервисы по бизнес логике, но это бизнес логика, а не что то добавленное из вне.
Ну вот так иногда бывает, что бизнес логике приходится работать с данными извне, если речь про внешний сервис. Ничего страшного в этом нет, если сборкой таких сущностей не заняты контроллеры, конечно.
Здравствуйте, Sharov, Вы писали:
S>Такой вопрос -- вот у меня appsrv получает извне файл, по типу файла(расширение) создает обработчик. Обработчик похож S>на domainsrv, ибо специфические вещи происходят на ряду с просто сохранением файла в хранилище. Так вот, я этот domainsrv S>создаю в appsrv при помощи фабрики, на основе типа файла. Это нормальная практика создавать доменные сервисы с S>помощью фабрики? Или я что-то не так делаю. Т.е. с одной стороны не SL (ибо анти-паттерн), с другой стороны я динамически S>создаю некий типизированный доменный сервис. Это как-то в DDD укладывается?
Я бы сделал прокси, который бы работал как IFileHandlerService, но для любого известного типа файла.
class AnyTypeFileHandler: IFileHandlerService
Этот сервис выбирал бы нужный обработчик и передавал бы ему все операции.
Вся эта switch-магия была бы внутри этого сервиса (в дальнейшем и от нее можно избавиться).
S>Это как-то в DDD укладывается?
Как уже упоминалось другим участником беседы, это все-таки вопросы не про DDD, а, скорее, про дизайн.
Здравствуйте, Qulac, Вы писали:
PD>>Если он виден presentation layer, то он не изолирован
Q>Смотря что понимать под "изолированостью".
Невозможность внесения изменений в структуры данных домена и ниже (БД) извне его. Только он сам может эти изменения вносить.
Q>>>Выделять отдельный слой с функцией "изолятора" и работы с сущностными не лучшая идея. Я пробовал так, все время кажется, что он тут лишний.
Q>Все равно лишний. Сервисы могут пригодится когда нужно выделить общий функционал у разных видом интерфейсов приложения, а так они не нужны. Зачем плодить лишние сущности?
Ты предлагаешь все в контроллере делать ? Тогда, у него будет 2 функции : presentation layer и бизнес-логика. Как заменить presentation layer в случае необходимости ? Например, вместо REST — GUI. Домен не должен измениться — он определяется задачей, а не способом передачи запросов и показа ответов.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, Qulac, Вы писали:
PD>>>Если он виден presentation layer, то он не изолирован
Q>>Смотря что понимать под "изолированостью".
PD>Невозможность внесения изменений в структуры данных домена и ниже (БД) извне его. Только он сам может эти изменения вносить.
Q>>>>Выделять отдельный слой с функцией "изолятора" и работы с сущностными не лучшая идея. Я пробовал так, все время кажется, что он тут лишний.
Q>>Все равно лишний. Сервисы могут пригодится когда нужно выделить общий функционал у разных видом интерфейсов приложения, а так они не нужны. Зачем плодить лишние сущности?
PD>Ты предлагаешь все в контроллере делать ? Тогда, у него будет 2 функции : presentation layer и бизнес-логика. Как заменить presentation layer в случае необходимости ? Например, вместо REST — GUI. Домен не должен измениться — он определяется задачей, а не способом передачи запросов и показа ответов.
Здравствуйте, Sharov, Вы писали:
S>Такой вопрос -- вот у меня appsrv получает извне файл, по типу файла(расширение) создает обработчик. Обработчик похож S>на domainsrv, ибо специфические вещи происходят на ряду с просто сохранением файла в хранилище. Так вот, я этот domainsrv S>создаю в appsrv при помощи фабрики, на основе типа файла. Это нормальная практика создавать доменные сервисы с S>помощью фабрики?
Этот вопрос звучит как "это нормальная практика использовать шлифованные деревянные балки для перекрытий". Мало данных для ответа на вопрос.
S>Или я что-то не так делаю. Т.е. с одной стороны не SL (ибо анти-паттерн), с другой стороны я динамически S>создаю некий типизированный доменный сервис. Это как-то в DDD укладывается?
Возможно и укладывается. Но если вдруг не укладывается, то что?