Re[20]: DDD протаскивание других слоев через параметры методов Domain
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.12.20 15:28
Оценка: 53 (6) +4
Здравствуйте, Sharov, Вы писали:

S>Тут хорошая стать и отличная картинка на эту тему -- https://blog.pragmatists.com/domain-driven-design-vs-anemic-model-how-do-they-differ-ffdee9371a86?gi=40c25922c8e9

По-моему — очередной булшит.
1. В нормальной, современной архитектуре нет никаких отдельных E и DAO. Это какой-то онанизм — сначала грузить из базы DAO, потом их превращать в E, потом обрабатывать, потом обратно превращать в DAO, и сохранять в базу.
Так никто не делает. Более того — чувак явно забыл о том, что есть ещё и DTO — ведь сервис общается и с клиентами. Поэтому полный ЖЦ этой халабуды выходит примерно таким: "получили DTO от клиента — отдали в сервис — тот преобразовал его в Е — поднял из базы пачку DAO — преобразовал их в E — как-то обработал — потом преобразовал часть E в новые DAO и сохранил в базу, а часть в DTO и отдал клиенту".
(Да, анемика по Фаулеру — говно. Впрочем, DDD по Фаулеру тоже выходит говном, из чего мы заключаем, что проблема не в анемике и не в домейн/рич, а в Фаулере.)
Забавно, что автор и сам это понимает, поэтому в тексте у него сказано "Services make use of DAO in order to implement the business logic for specific functionality". Да, совершенно верно — сервис так и работает в терминах DAO. Никакие entity ему не нужны — зачем, ведь в них же нет никакой бизнес-логики. Рассказывать про то, что "Usually, each of our entities represents separate business case, so the number of DAO classes match the number of entities. " можно только в целях напугать детишек: у-у-у, не ходите в анемик, там каждую сущность в модели надо описывать дважды, ДВАЖДЫ!

2. Идея в том, что сервис сначала подымет Entities в память при помощи DTO, а уж потом поработает над ними, описанная в статье — полный булшит, который отстал от жизни лет эдак на пятнадцать. Ну, наверное в какой-нибудь кровавой жаве так до сих пор и делают; а в нормальных современных сервисах стараются в app server лишнего не подымать. Задача сервиса — выразить бизнес-транзакцию в терминах операций над DTO; сами эти операции не выполняются над DTO, а преобразуются напрямую в SQL и уезжают в базу, где и выполняются. Если я хочу поменять статус заказа с "оплачен" на "отгружен", то я не делаю сначала select * from orders where id = @orderId в OrderDTO, и не создаю из него OrderEntity при помощи OrderEntityFactory, чтобы потом ему сделать setStatus, а потом orderDto.UpdateFrom(OrderEntity) и unitOfWork.Save(true). Нет, всё это — пережиток эпохи "а теперь дайте мне ферму из 16 PowerEdge, чтобы ваши остатки на складах подбивались хотя бы за ночь".
Делается нормальный linq-statement, который изменяет статус у того, что нужно:
using LinqToDB;

using (var db = new DbNorthwind())
{
  db.Order
    .Where(o => .ID == orderId)
    .Set(o => o.Status, newStatus)
    .Update();
}

Всё. Это превращается в SQL стейтмент, который выполняется напрямую в сервере, без подъёма килобайтов в память и длинного удержания локов.
Да, не всегда получается сделать именно так, но, поскольку мы нафиг выкинули ентити в пользу чистых "DTO", такое получается сделать гораздо чаще, чем в той убогой анемике, о которой врёт Фаулер и его фанаты.
В тех случаях, когда нам реально надо сделать что-то относительно сложное в коде сервиса, мы тащим в память не все DTO, и не каждый из них целиком — ведь на linq проекции и прочие SQL трансформации делаются лёгким движением руки, без мучительного выписывания каких-то там aggregation root или прочего. Если мне потребуется в логике проверять средний чек данного клиента — я не буду заводить для этого целый класс, будет по месту сформирован linq expression, который его достаёт сразу в виде decimal. Благодаря этому общение между сервисом и СУБД сводится к минимуму — select avg(amount) from ... всё ещё в разы быстрее, чем делать select * from, а потом усреднять в памяти.

3. Опять же читаем статью, "the application with the anemic model has more repositories than the one with the rich model". Смотрим на картинку — автор врёт даже сам себе. На его же картинке с Anemic есть ровно 0 (ноль) репозиториев. Что, в общем-то, верно отражает современную реальность. Это в говно-DDD, которое он пропагандирует, нам нужны репозитории на каждый агрегат. А в современной анемик-архитектуре "репозиториев" примерно столько, сколько есть граней у сервиса. Скажем, вся бухгалтерия — это один "репозиторий", весь складской учёт — это ещё один; управление подписками — третий; human resources — четвёртый.
И при этом эти репозитории, в отличие от DDD, не содержат никакого императивного кода. Никаких там Find или Update, специфических для каждого типа Entity. Достаточно собственно DbContext, который описывает типы. Плюс, возможно, набор extension-методов к нему и к IQueryable, которые позволяют быстро компоновать между собой куски нужного функционала. Скажем, если нам надо часто вычислять средний чек по каким-то критериям, то мы можем отдельно построить функцию decimal Average(IQueryable<decimal> source), и в коде сервиса обращаться уже к ней, с уместными в каждом конкретном случае селектами.

В итоге появляется возможность на стороне сервисов совмещать объектную и функциональную декомпозицию; а большую часть кода из DDD/рич писать вообще не нужно и даже вредно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[19]: DDD протаскивание других слоев через параметры методов Domain
От: samius Япония http://sams-tricks.blogspot.com
Дата: 29.11.20 05:40
Оценка: 1 (1) +3
Здравствуйте, #John, Вы писали:

J>Здравствуйте, samius, Вы писали:


S>>Как так? Отличия лишь в синтаксисе и такой глубокий вывод о стиле... Метод ChangeSkin заменен методом set_skinColor. Больше ничего не изменилось...


S>>А если так?

S>>
S>>class Chameleon
S>>{
S>>    public Color skinColor { get; }
S>>}
S>>


J>Тоже самое. Стиль программирования `procedural vs oo` зависит от того как используется класс: как структура данных или как объект у которого все данные и логика прописаны в одном месте.


Что же все так радикально? В вашем примере видел UserInformationDto. Ваш пример — образец процедурного стиля?

S>>Кстати, не считаю, что процедурный стиль плох.

J>У оо больше возможностей по написанию более независимого, модульного кода.
J>В процедурном стиле: не используется сокрытие информации(модификаторы доступа), (т.к. поля/свойства всегда public).
Информацию скрывали и до изобретения модификаторов доступа.

J>потому может произойти такая ситуация, что код по изменению поля структуры будет раскидан в разных местах проекта/класса,

J>а изменение этого поля будет зависеть от разных условий. А код который меняет это поле будет зависеть еще от другого код,
J>а тот еще и еще. И когда понадобится добавить новую логику которая будет дополнительно как-то менять поле,
J>нам придется вместо того что бы подправить код в одном классе/объекте продебажить пол проекта и найти место куда воткнуть наш код.
Модификаторы доступа здесь не наводят ясность, т.к. публичные методы продолжают торчать из объекта. И если пол проекта не меняют поля объекта, которые хотелось бы скрыть, то этим занимаются методы объекта, которые никто не мешает вызывать в разных местах проекта.

Самая простая возможность контролировать изменения объекта — сделать его неизменяемым.
Re[16]: DDD протаскивание других слоев через параметры методов Domain
От: #John Европа https://github.com/ichensky
Дата: 28.11.20 16:59
Оценка: 16 (1) +1 -1
Здравствуйте, samius, Вы писали:

J>>Напр. хамелеон умеет менять цвет кожи. В коде мы и должны описывать хамелеона:

J>>
J>>class Chameleon
J>>{
J>>    public Color skinColor { get; private set; }

J>>    public void ChangeSkin(Color color) => skinColor = color; 
J>>}
J>>

S>и чем же следующий хамелеон хуже?
S>
S>class Chameleon
S>{
S>    public Color skinColor { get; set; }
S>}
S>

Он попадает под описание процедурного стиля программирования: разбиение задачи программирования на набор переменных, структур данных и подпрограмм.

S>Не, ну это детский сад какой-то. Я предпочитаю опираться на принципы, сформулированные Кэйем. У него ничего нет про "данные и логика в одном объекте".


Алан Кэй пишет

OOP to me means only messaging, local retention and protection and
hiding of state-process, and extreme late-binding of all things.


"local retention" — это и есть отсылка к тому что состояние объекта находится внутри объекта.

Там же он пишет:

I thought of objects being like biological cells and/or individual computers on a network, only able to communicate with messages (so messaging came at the very beginning – it took a while to see how to do messaging in a programming language efficiently enough to be useful).


Биологические клетки свое состояние держат внутри себя, имеют разный набор данных(митохондрии, рыбосому, цитозоль), имеют разное поведение, и общаются посредством передачи ионов и молекул через каналы.
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re: DDD протаскивание других слоев через параметры методов D
От: gyraboo  
Дата: 28.11.20 08:19
Оценка: 4 (1) +2
Здравствуйте, #John, Вы писали:

J>как вы боритесь с тем, что в методы entity, через параметры, в Domain слой протягиваютя классы из других слоев?


Тут уже много всего правильного написали. Могу рассказать как это обычно делается в Java энтерпрайзе в слоистой архитектуре:
Классы типа Logger не относятся к обычному слою, они относятся к классу т.н. сквозной функциональности, не связанной с бизнес-логикой, а умеющей внедряться в любой слой. Туда же относятся transaction и security менеджеры. Эти классы DI-фреймворк (Спринг или JEE) сам инжектит в поля класса Enity (когда мы помечаем эти поля @Autowired или @Inject), их не надо передавать в явном виде в методах.

Похоже, что в приведенном примере все протягиваемые туда классы относятся либо к сквозной функциональности, либо к слою Util (DateTimeProvider, NumberProvider — это тоже особый случай, а не обычный слой, набор классов или 3-rdparty библиотек, не знающих про бизнес-логику и который могут использовать все обычные слои приложения).

А если возникает задача протащить между слоями именно доменные объекты, то есть паттерн DTO, причём он есть как в анемичной модели так и в DDD.
Отредактировано 28.11.2020 8:21 gyraboo . Предыдущая версия . Еще …
Отредактировано 28.11.2020 8:20 gyraboo . Предыдущая версия .
Re[24]: DDD протаскивание других слоев через параметры метод
От: AndrewJD США  
Дата: 09.12.20 18:40
Оценка: 8 (1) +1
Здравствуйте, Sharov, Вы писали:

S>Еще раз: да, в каких-то случаях все будет 1 в 1. В самых, вероятно, простейших.

Я например утверждаю, что она такая же и для сложных случаев.

S>Там вся соль на картинке именно в связях,

S>т.е. ребрах между сущностями в соотв. уровне. Вот эти связи и есть сложность, которую надо контролировать.
Количество связей плюс/минус одинаково ибо оно дикуется бизнес логикой, вопрос в том где эти связи располагаются.

S>DDD предлагает подход, где эти связи отсутствуют, т.е. сложность проще контролировать. Т.е. изоляция на уровне дизайна\архитектуры. А не только в коде.

Сливание всего в кучу не означает что связи исчезли. ИМХО, в этом и проблема, что в DDD постулируется что это приводит к лучшему дизайну без доказательств. Даже в этой статье приводится "Aggregates allow us to encapsulate parts of our domain so our API becomes simpler and changes inside aggregates are easier to implement (we don’t need to analyse our changes impact on some other parts of the domain because it doesn’t exist)" без аргументов откуда это следует. Из моей практики я вижу строго наоборот, что разделние логики и данных уменьщает связанность и делает дизайн гибче, а код быстрее.
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Отредактировано 09.12.2020 19:02 AndrewJD . Предыдущая версия .
Re: DDD протаскивание других слоев через параметры методов Domain
От: samius Япония http://sams-tricks.blogspot.com
Дата: 11.11.20 11:44
Оценка: 6 (1) +1
Здравствуйте, #John, Вы писали:

J>Здравствуйте,


J>как вы боритесь с тем, что в методы entity, через параметры, в Domain слой протягиваютя классы из других слоев?


http://rsdn.org/forum/philosophy/4441613.1
Автор: Sinclair
Дата: 03.10.11
Re[12]: DDD протаскивание других слоев через параметры методов Domain
От: Буравчик Россия  
Дата: 13.01.21 10:19
Оценка: 5 (1) +1
Здравствуйте, gandjustas, Вы писали:

G>Вот как должен выглядеть такой код (в плохом случае):


Код ты не сильно и изменил. Уменьшил количество строк в data-классах — норм.

И объединил репозиторий с сервисом, прибив сервис к БД. Но в твоем сервисе содержится код для двух задача:
— код для обработки бизнес-логики
— код для обработки хранения данных

Когда код бизнес-логики усложнится (требования бизнеса), или код хранения данных усложнится (изменится схема БД, или, вдруг, решишь хранение пользователей передать в какой-нибудь микросервис), то тебе захочется их разделить. Как это уже сделал (возможно, более опытный) товарищ выше.

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

G>Лучше раскажи как ты в своем коде сделаешь такое:


Просто добавить этот код в репозиторий
Best regards, Буравчик
Re[3]: DDD протаскивание других слоев через параметры методов Domain
От: Буравчик Россия  
Дата: 21.11.20 07:28
Оценка: 1 (1) +1
Здравствуйте, #John, Вы писали:

J>Но и у него есть недостатки: бизнес логика дробится.


И какая проблема из этого возникает (пример)?

Вообще, она всегда дробится. Вопрос лишь как — по сущностям или по сервисам.
Best regards, Буравчик
Re[14]: DDD протаскивание других слоев через параметры методов Domain
От: #John Европа https://github.com/ichensky
Дата: 28.11.20 02:36
Оценка: :))
Здравствуйте, samius, Вы писали:


S>метод UpdateInformation вероятно будет и в анемике тоже. Ключевой поинт анемика лишь в том, нахрена этот метод нужен User-у? Не отменяя того, что User- агрегат для изменения его информации, можно записать

S>UpdateInformation(User user, string info, string email),

Это процедурный стиль программирования, типы данных отдельно, логика отдельно.
Объектно ориентированный подход — это когда данные и логика в одном объекте и мы работаем с объекатами.
В ОО объекты представляют сущности из реального мира(ограниченные условиями проекта).
Напр. хамелеон умеет менять цвет кожи. В коде мы и должны описывать хамелеона:
class Chameleon
{
    public Color skinColor { get; private set; };

    public void ChangeSkin(Color color) => skinColor = color; 
}


ObjectsAndDataStructures

S>Объекты всегда в правильном состоянии для чего? Для какого процесса?

Что бы можно было создать/достать из бд агрегат рут, вызвать любой метод и объект был в валидном состоянии, и ни каких ошибок не выкинуло(напр. NRE),
что бы агрегат рут без дополнительных проверок, можно было просто взять и сохранить в бд целиком, одной транзакцией, и не получилось что мы потеряли часть данных.
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[17]: DDD протаскивание других слоев через параметры методов Domain
От: samius Япония http://sams-tricks.blogspot.com
Дата: 28.11.20 23:09
Оценка: +2
Здравствуйте, #John, Вы писали:

J>Здравствуйте, samius, Вы писали:


S>>и чем же следующий хамелеон хуже?

S>>
S>>class Chameleon
S>>{
S>>    public Color skinColor { get; set; }
S>>}
S>>

J>Он попадает под описание процедурного стиля программирования: разбиение задачи программирования на набор переменных, структур данных и подпрограмм.

Как так? Отличия лишь в синтаксисе и такой глубокий вывод о стиле... Метод ChangeSkin заменен методом set_skinColor. Больше ничего не изменилось...
Кстати, не считаю, что процедурный стиль плох.
А если так?
class Chameleon
{
    public Color skinColor { get; }
}


S>>Не, ну это детский сад какой-то. Я предпочитаю опираться на принципы, сформулированные Кэйем. У него ничего нет про "данные и логика в одном объекте".


J>Алан Кэй пишет

J>

J>OOP to me means only messaging, local retention and protection and
J>hiding of state-process, and extreme late-binding of all things.


J>"local retention" — это и есть отсылка к тому что состояние объекта находится внутри объекта.


J>Там же он пишет:

J>

J>I thought of objects being like biological cells and/or individual computers on a network, only able to communicate with messages (so messaging came at the very beginning – it took a while to see how to do messaging in a programming language efficiently enough to be useful).


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


Да, сокрытие состояние объекта таки приветствуется. Но есть некоторое "но". Анемик не пытается делать из всего объекты. В нем моделируется не поведение пользователя, а поведение сервиса, производящего над пользователем некие действия. Поведение обработчика доменного события, если угодно. Пользователь в нем — сообщение и не стоит рассматривать его поля как его состояние. Не более, чем символы — состояние (неизменяемой) строки.
Re[18]: DDD протаскивание других слоев через параметры методов Domain
От: #John Европа https://github.com/ichensky
Дата: 29.11.20 01:23
Оценка: +1 -1
Здравствуйте, samius, Вы писали:

S>Как так? Отличия лишь в синтаксисе и такой глубокий вывод о стиле... Метод ChangeSkin заменен методом set_skinColor. Больше ничего не изменилось...


S>А если так?

S>
S>class Chameleon
S>{
S>    public Color skinColor { get; }
S>}
S>


Тоже самое. Стиль программирования `procedural vs oo` зависит от того как используется класс: как структура данных или как объект у которого все данные и логика прописаны в одном месте.

S>Кстати, не считаю, что процедурный стиль плох.

У оо больше возможностей по написанию более независимого, модульного кода.
В процедурном стиле: не используется сокрытие информации(модификаторы доступа), (т.к. поля/свойства всегда public).
потому может произойти такая ситуация, что код по изменению поля структуры будет раскидан в разных местах проекта/класса,
а изменение этого поля будет зависеть от разных условий. А код который меняет это поле будет зависеть еще от другого код,
а тот еще и еще. И когда понадобится добавить новую логику которая будет дополнительно как-то менять поле,
нам придется вместо того что бы подправить код в одном классе/объекте продебажить пол проекта и найти место куда воткнуть наш код.
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[19]: DDD протаскивание других слоев через параметры методов Domain
От: alexsoff Россия  
Дата: 29.11.20 04:50
Оценка: +2
Здравствуйте, #John, Вы писали:

J>У оо больше возможностей по написанию более независимого, модульного кода.

Т.е. вы не видите разницу между двумя понятиями — процедурное и функциональное программирование и думаете, что это одно и тоже?
Re[21]: DDD протаскивание других слоев через параметры методов Domain
От: Sharov Россия  
Дата: 04.12.20 12:25
Оценка: :))
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Sharov, Вы писали:


S>>Тут хорошая стать и отличная картинка на эту тему -- https://blog.pragmatists.com/domain-driven-design-vs-anemic-model-how-do-they-differ-ffdee9371a86?gi=40c25922c8e9

S>По-моему — очередной булшит.
S>1. В нормальной, современной архитектуре нет никаких отдельных E и DAO. Это какой-то онанизм — сначала грузить из базы DAO, потом их превращать в E, потом обрабатывать, потом обратно превращать в DAO, и сохранять в базу.
S>Так никто не делает. Более того — чувак явно забыл о том, что есть ещё и DTO — ведь сервис общается и с клиентами. Поэтому полный ЖЦ этой халабуды выходит примерно таким: "получили DTO от клиента — отдали в сервис — тот преобразовал его в Е — поднял из базы пачку DAO — преобразовал их в E — как-то обработал — потом преобразовал часть E в новые DAO и сохранил в базу, а часть в DTO и отдал клиенту".

DTO тут совершенно ортогонален, чтобы показать отличия он не нужен.

S>2.

S>3. Опять же читаем статью, "the application with the anemic model has more repositories than the one with the rich model". Смотрим на картинку — автор врёт даже сам себе. На его же картинке с Anemic есть ровно 0 (ноль) репозиториев. Что, в общем-то, верно отражает современную реальность. Это в говно-DDD, которое он пропагандирует, нам нужны репозитории на каждый агрегат. А в современной анемик-архитектуре "репозиториев" примерно столько, сколько есть граней у сервиса. Скажем, вся бухгалтерия — это один "репозиторий", весь складской учёт — это ещё один; управление подписками — третий; human resources — четвёртый.
S>И при этом эти репозитории, в отличие от DDD, не содержат никакого императивного кода. Никаких там Find или Update, специфических для каждого типа Entity. Достаточно собственно DbContext, который описывает типы. Плюс, возможно, набор extension-методов к нему и к IQueryable, которые позволяют быстро компоновать между собой куски нужного функционала. Скажем, если нам надо часто вычислять средний чек по каким-то критериям, то мы можем отдельно построить функцию decimal Average(IQueryable<decimal> source), и в коде сервиса обращаться уже к ней, с уместными в каждом конкретном случае селектами.

Вы к каким-то деталям прицепились, дескать в анемичной модели у него не ноль репозиториев в анемике. Ну с его тз
DAO и есть простенький репозиторий. Повтрюсь, суть иллюстрации в связях между компонентами соотв. уровня. В один случае дизайна
архитектуры они допускаются, и даже не неизбежны, в другом (DDD) их можно избежать. Все, больше данная картинка не на что
не претендует. Неточностей там наверняка не мало, но главное отличие картинка отлично передает. В DDD вообще практически нету
зависимостей, сложность контролируема.
Кодом людям нужно помогать!
Re[13]: DDD протаскивание других слоев через параметры методов Domain
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 13.01.21 11:17
Оценка: +2
Здравствуйте, Буравчик, Вы писали:

Б>Здравствуйте, gandjustas, Вы писали:


G>>Вот как должен выглядеть такой код (в плохом случае):


Б>Код ты не сильно и изменил. Уменьшил количество строк в data-классах — норм.

Именно. Он делает то же самое и приерно в 3 раза короче, имеет меньше классов, меньше покозатель связности.

Б>И объединил репозиторий с сервисом, прибив сервис к БД. Но в твоем сервисе содержится код для двух задача:

Б>- код для обработки бизнес-логики
Б>- код для обработки хранения данных
О ужас, как с этим жить...

Б>Когда код бизнес-логики усложнится (требования бизнеса), или код хранения данных усложнится (изменится схема БД, или, вдруг, решишь хранение пользователей передать в какой-нибудь микросервис), то тебе захочется их разделить. Как это уже сделал (возможно, более опытный) товарищ выше.

Когда требования изменятся, тогда и код изменится, независимо от того что было написано ранее. Причем чем меньше было написано, тем проще менять.


Б>Плюс, когда репозитория отделен, для него очень удобно писать интеграционный тест.

А когда не отделен, то этот тест вообще не нужен. Нуюен тст — делай тестовую inmemory базу, EF позволяет.

G>>Лучше раскажи как ты в своем коде сделаешь такое:


Б>Просто добавить этот код в репозиторий

А потом вызывать его из сервиса. Вот и кончился DDD с его Entity и Aggregate Root.
Re: DDD протаскивание других слоев через параметры методов Domain
От: takTak  
Дата: 21.01.21 12:07
Оценка: +2
З
J>и в каком-то менеджере:
J>
J>rootAgreagete.Do("xxx","yyy", this.system1, this.system2, this.system3, this.logger, this.provider1, this.provider2, ....);

J>


тоже добавлю свои 3 копейки:
за что, собственно, отвечает обьект типа Entity ? не слишком ли много он на себя берёт, если ему нужно аж 8 зависимостей?

т.е. со стороны выглядит так, что он занят какими-то левыми вещами: бывают, конечно, случаи, когда нужно сделать то и это, но это относится, скорее, либо к слою application service либо абстрагируется событиями, для этого этому обьекту достаточно просто прокинуть событие, а уже вот тот компонент, который на это событие подписан и занимается тем, что вытягивает эти 8 зависимотей, что-то там делает и тому подобное
Re[11]: DDD протаскивание других слоев через параметры методов Domain
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 13.01.21 09:22
Оценка: 76 (1)
Здравствуйте, #John, Вы писали:

J>Допустим у нас есть пользователь у него есть контактная информация и нам нужно добавить

J>бизнес логику, когда пользователь нажимает кнопку "Save", нам приходят данные: `Info` и `email` и мы их обрабатываем.

J>В DDD это выглядело бы вот так:


  Domain Layer
J>
J>    public class User
J>    {
J>        public Guid Id { get; private set; }

J>        public string UserName { get; private set; }

J>        public string Info { get; private set; }

J>        public ContactInformation ContactInformation { get; private set; }

J>        protected internal User() { }

J>        /// <summary>
J>        /// Used for loading for ex. from the DB
J>        /// </summary>
J>        public static User Create(Guid id, string userName, string info, ContactInformation contactInformation)
J>        {
J>            return new User
J>            {
J>                Id = id,
J>                Info = info,
J>                UserName = userName,
J>                ContactInformation = contactInformation,
J>            };
J>        }

J>        /// <summary>
J>        /// Used for creation 
J>        /// </summary>
J>        public static User Create(string userName, string info, ContactInformation contactInformation)
J>        {
J>            if (string.IsNullOrWhiteSpace(userName))
J>            {
J>                throw new ArgumentException();
J>            }
J>            // other validation ...

J>            var id = Guid.NewGuid();

J>            return Create(id, info, userName, contactInformation);
J>        }

J>        public virtual ContactInformation GetContactInformation() => ContactInformation;

J>        public virtual void UpdateInformation(string info, string email)
J>        {
J>            // validation ..

J>            this.Info = info;
J>            GetContactInformation().UpdateEmail(email);
J>        }
J>    }
J>    public class ContactInformation
J>    {
J>        public Guid Id { get; private set; }

J>        public string Phone { get; private set; }

J>        public string Email { get; private set; }

J>        protected internal ContactInformation() { }

J>        public static ContactInformation Create(Guid id, string phone, string email) => new ContactInformation
J>        {
J>            Id = id,
J>            Phone = phone,
J>            Email = email
J>        };

J>        public static ContactInformation Create(string phone, string email)
J>        {
J>            var id = Guid.NewGuid();
J>            return Create(phone, email);
J>        }

J>        public static ContactInformation Create(string email) => Create(null, email);

J>        internal virtual void UpdateEmail(string newEmail)
J>        {
J>            if (newEmail.Contains("admin"))
J>            {
J>                throw new ArgumentException();
J>            }

J>            this.Email = newEmail;
J>        }
J>    }

J>


  Infrastructure Layer
J>
J>    public class UserRepository
J>    {

J>        public User Load(Guid id)
J>        {
J>            // Loading from the DB ...
J>            var contactInformation = ContactInformation.Create(Guid.NewGuid(), "bob@example.com", "+123456");
J>            var user = User.Create(id, "Bob", "Smth", contactInformation);
J>            return user;
J>        }
J>        public void Save(User user)
J>        {

J>        }
J>    }
J>


  Application Layer
J>
J>   public class UserInformationDto
J>    {
J>        public string Email { get; set; }
J>        public string Info { get; set; }
J>    }

J>    public class UserService
J>    {

J>        // IUserRepository
J>        private UserRepository userRepository;

J>        public UserService(UserRepository userRepository)
J>        {
J>            this.userRepository = userRepository;
J>        }

J>        public void UpdateUserInformation(Guid userId, UserInformationDto userInformation)
J>        {

J>            // validation ..

J>            var user = userRepository.Load(userId);

J>            user.UpdateInformation(userInformation.Info, userInformation.Email);

J>            userRepository.Save(user);
J>        }
J>    }
J>


Если у меня программист напишет такое больше одного раза, то он будет уволен, потому что тратит мои деньги.

Вот как должен выглядеть такой код (в плохом случае):
public class User
{
    public Guid Id { get; set; }
    public string UserName { get; set; }
    public string Info { get; set; }
    public ContactInformation ContactInformation { get; set; }
}

public class ContactInformation
{
    public Guid Id { get; set; }
    public string Phone { get; set; }
    public string Email { get; set; }
}

public class UserInformationDto
{
    public string Email { get; set; }
    public string Info { get; set; }
}


public class UserService
{
    public async Task UpdateUserInformation(Guid userId, UserInformationDto userInformation)
    {
        // validation ..
        var user = await dbContext.Users.Include(u => u.ContactInformation).FindAsync(userId);
        user.Info = userInformation.Info;
        user.ContactInformation.Email = userInformation.Email;
        dbContext.Save(user);
        dbContext.Save(user.ContactInformation);
        await dbContext.SaveChangesAsync();
    }
}


А в идеале еще и два класса данных объединить в один и испольовать modelbinding или мапперы, а не ручное присваивание DTO. И избавится от UserService, а код написать непосредственно в контроллере.
И мне все равно что там более или менее ООП, что там думает фаулер, эванс или буч. Мне важно что я плачу фактически за каждую строку кода и чем меньше программисты созают строк кода для решения задачи, чем больше я могу заработать.



J>В трехслойной/четырехслойной архитектуре с анемичными моделями, нам точно так уже пришлось бы мокать `IChangeContactInformationService`

J>и метод "GetContactInformation". Потому разницы в сложности поддержания/написания тестов — нет.
Этих методов просто не будет. Можно конечно каждое присваивание вынести в отдельный метод, чтобы его протестировать, но лучше мапперы использовать, а не труд программистов.

J>Бизнес логика в одном месте, работа с данными и все остальное отдельно, все легко тестируется и поддерживается.

Ты серьезно считашь что 4 класса и 6 методов легче поддерживаются чем один класс и один метод?
У меня для тебя плохие новости.

J>Из дополнительных плюсов с DDD мы легко можем применить CQRS подход.

Лучше раскажи как ты в своем коде сделаешь такое:
dbContext.Users.Select(u => new UserInformationDto { Info = u.Info, Email = u.ContactInformationюEmail }).ToListAsync()

Это тебе понадобится 100%, а CQRS не понадобится совсем.
Re[10]: DDD протаскивание других слоев через параметры методов Domain
От: #John Европа https://github.com/ichensky
Дата: 26.11.20 00:20
Оценка: 8 (1)
Здравствуйте, samius, Вы писали:

S>То, что не требует мокать — лучше тестируется. Полагаю, что это правда, согласен с автором. Он ведь не утверждает о невозможности.


Допустим у нас есть пользователь у него есть контактная информация и нам нужно добавить
бизнес логику, когда пользователь нажимает кнопку "Save", нам приходят данные: `Info` и `email` и мы их обрабатываем.

В DDD это выглядело бы вот так:

  Domain Layer
    public class User
    {
        public Guid Id { get; private set; }

        public string UserName { get; private set; }

        public string Info { get; private set; }

        public ContactInformation ContactInformation { get; private set; }

        protected internal User() { }

        /// <summary>
        /// Used for loading for ex. from the DB
        /// </summary>
        public static User Create(Guid id, string userName, string info, ContactInformation contactInformation)
        {
            return new User
            {
                Id = id,
                Info = info,
                UserName = userName,
                ContactInformation = contactInformation,
            };
        }

        /// <summary>
        /// Used for creation 
        /// </summary>
        public static User Create(string userName, string info, ContactInformation contactInformation)
        {
            if (string.IsNullOrWhiteSpace(userName))
            {
                throw new ArgumentException();
            }
            // other validation ...

            var id = Guid.NewGuid();

            return Create(id, info, userName, contactInformation);
        }

        public virtual ContactInformation GetContactInformation() => ContactInformation;

        public virtual void UpdateInformation(string info, string email)
        {
            // validation ..

            this.Info = info;
            GetContactInformation().UpdateEmail(email);
        }
    }
    public class ContactInformation
    {
        public Guid Id { get; private set; }

        public string Phone { get; private set; }

        public string Email { get; private set; }

        protected internal ContactInformation() { }

        public static ContactInformation Create(Guid id, string phone, string email) => new ContactInformation
        {
            Id = id,
            Phone = phone,
            Email = email
        };

        public static ContactInformation Create(string phone, string email)
        {
            var id = Guid.NewGuid();
            return Create(phone, email);
        }

        public static ContactInformation Create(string email) => Create(null, email);

        internal virtual void UpdateEmail(string newEmail)
        {
            if (newEmail.Contains("admin"))
            {
                throw new ArgumentException();
            }

            this.Email = newEmail;
        }
    }


  Infrastructure Layer
    public class UserRepository
    {

        public User Load(Guid id)
        {
            // Loading from the DB ...
            var contactInformation = ContactInformation.Create(Guid.NewGuid(), "bob@example.com", "+123456");
            var user = User.Create(id, "Bob", "Smth", contactInformation);
            return user;
        }
        public void Save(User user)
        {

        }
    }


  Application Layer
   public class UserInformationDto
    {
        public string Email { get; set; }
        public string Info { get; set; }
    }

    public class UserService
    {

        // IUserRepository
        private UserRepository userRepository;

        public UserService(UserRepository userRepository)
        {
            this.userRepository = userRepository;
        }

        public void UpdateUserInformation(Guid userId, UserInformationDto userInformation)
        {

            // validation ..

            var user = userRepository.Load(userId);

            user.UpdateInformation(userInformation.Info, userInformation.Email);

            userRepository.Save(user);
        }
    }


В трехслойной/четырехслойной архитектуре с анемичными моделями, нам точно так уже пришлось бы мокать `IChangeContactInformationService`
и метод "GetContactInformation". Потому разницы в сложности поддержания/написания тестов — нет.

  Unit tests
public class UserTests
    {
        private User user;
        private ContactInformation contactInformation;

        public UserTests()
        {
            contactInformation = Mock.Of<ContactInformation>();
            user = Mock.Of<User>();
        }

        [Fact]
        public void UpdateInformationTest()
        {
            // Arrange
            var email = "bob2@example.com";
            Mock.Get(user).Setup(x => x.GetContactInformation()).Returns(contactInformation);

            // Act
            var ex = Record.Exception(() => user.UpdateInformation("xxx", email));

            // Assert
            Assert.Null(ex);
        }
    }


Бизнес логика в одном месте, работа с данными и все остальное отдельно, все легко тестируется и поддерживается.
Если придется работать с внешним сервисом, придется создавать DomainService и дробить бизнес логику в rich-моделях.

Из дополнительных плюсов с DDD мы легко можем применить CQRS подход.
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re: Посоветуйте сайты для поиска работы в США, Канада или Германия
От: Gurney Великобритания www.kharlamov.biz
Дата: 11.11.20 12:36
Оценка: -1
Здравствуйте, #John, Вы писали:

J>Здравствуйте,


J>как вы боритесь с тем, что в методы entity, через параметры, в Domain слой протягиваютя классы из других слоев?


ORM и Dependency Injection?
Re: DDD протаскивание других слоев через параметры методов Domain
От: Буравчик Россия  
Дата: 11.11.20 16:16
Оценка: +1
Здравствуйте, #John, Вы писали:

J>как вы боритесь с тем, что в методы entity, через параметры, в Domain слой протягиваютя классы из других слоев?


Выделяю поведение в отдельные классы — бизнес-сервисы. Зависимости прокидываю через конструктор в composition root.
Best regards, Буравчик
Re[5]: DDD протаскивание других слоев через параметры методов Domain
От: Sinclair Россия https://github.com/evilguest/
Дата: 24.11.20 07:26
Оценка: +1
Здравствуйте, #John, Вы писали:

J>Если тут использовать бизнес сервис, то придется часть метода(или весь метод) `UpdateStatus()` вынести в бизнес сервис,

J>там сделать проверку результата, а потом продолжить выполнение логики из метода "UpdateStatus".
А Foo и Bar у вас что — типы предметной области?
В нормальной архитектуре метод UpdateStatus не является членом класса "данных", а принадлежит сервису.
Поэтому никакого дробления не будет.

J>Чем выше будет цикломатическая сложность/вложеных_методов тем сложнее/больше_кода придется вынести в бизнес сервис.


Б>>Вообще, она всегда дробится. Вопрос лишь как — по сущностям или по сервисам.

J>Если выносить код в бизнес сервисы, то данные и способы их обработки оказываются разделены, что нарушает один из принципов ООП,
J>т.к. не позволяет модели обеспечивать собственные инварианты.
Нет такого принципа.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: DDD протаскивание других слоев через параметры методов Domain
От: samius Япония http://sams-tricks.blogspot.com
Дата: 25.11.20 16:48
Оценка: +1
Здравствуйте, #John, Вы писали:

J>Здравствуйте, Sinclair, Вы писали:


J>>>Если выносить код в бизнес сервисы, то данные и способы их обработки оказываются разделены, что нарушает один из принципов ООП,

J>>>т.к. не позволяет модели обеспечивать собственные инварианты.
S>>Нет такого принципа.

J>В посте про амемичную модель Фовлер пишет:

J>

J>... the basic idea of object-oriented design; which is to combine data and process together ...


Есть писатели об обратном.
https://blog.inf.ed.ac.uk/sapm/2014/02/04/the-anaemic-domain-model-is-no-anti-pattern-its-a-solid-design/

In this blog post I will consider the arguments against the ADM, and contend that in some scenarios, the ADM appears be an reasonable choice of design, in terms of adherence to the SOLID principles of Object-Oriented design, established by Robert Martin [3], [4].

Re[11]: DDD протаскивание других слоев через параметры методов Domain
От: samius Япония http://sams-tricks.blogspot.com
Дата: 26.11.20 18:07
Оценка: +1
Здравствуйте, #John, Вы писали:

J>Здравствуйте, samius, Вы писали:


S>>То, что не требует мокать — лучше тестируется. Полагаю, что это правда, согласен с автором. Он ведь не утверждает о невозможности.


J>Допустим у нас есть пользователь у него есть контактная информация и нам нужно добавить

J>бизнес логику, когда пользователь нажимает кнопку "Save", нам приходят данные: `Info` и `email` и мы их обрабатываем.

J>В DDD это выглядело бы вот так:


Удивительно рафинированно-анемичный получился пример DDD. Я не вижу в нем ничего, что нельзя было бы выполнить на голом DTO, за исключением, разве что, комментариев
// validation ..
PurchaseItem из статьи был куда более типичен для DDD.
А так же исходный
internal void DoCool(string value, Ac.System system, ILogger logger, IDateTimeProvider, INumberProvider)

или Foo.UpdateStatus с заходом в HttpClient.

J>В трехслойной/четырехслойной архитектуре с анемичными моделями, нам точно так уже пришлось бы мокать `IChangeContactInformationService`

J>и метод "GetContactInformation". Потому разницы в сложности поддержания/написания тестов — нет.

Разница есть и для меня она очевидна. Она в том числе в количестве сущностей, которые придется мокать при взаимодействии множества объектов предметной области между собой.
И в анемике нет нужды мокать вообще все.

J>Бизнес логика в одном месте, работа с данными и все остальное отдельно, все легко тестируется и поддерживается.

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

J>Если придется работать с внешним сервисом, придется создавать DomainService и дробить бизнес логику в rich-моделях.

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

J>Из дополнительных плюсов с DDD мы легко можем применить CQRS подход.

Сорян, я не вижу причин, почему мы не можем легко применить CQRS подход с анемиком.
Re[13]: DDD протаскивание других слоев через параметры методов Domain
От: samius Япония http://sams-tricks.blogspot.com
Дата: 27.11.20 23:20
Оценка: +1
Здравствуйте, #John, Вы писали:

J>Здравствуйте, samius, Вы писали:


S>>Бизнес логики я в этом примере не увидел. Хотелось посмотреть на чуть более сложном примере, где взаимодействуют покупатель, корзина товаров, набор акций на отдельные группы товаров, накопительные бонусные программы или что-то в этом роде.

S>>Я не прошу приводить код, я его довольно ясно представляю, в том числе с тестами и обилием моков.

J>>>Если придется работать с внешним сервисом, придется создавать DomainService и дробить бизнес логику в rich-моделях.

S>>Проблема рич в том, что чем больше сценариев, тем больше придется дробить бизнес логику в рич моделях.
S>>Та же валидация внутри рич моделей говорит "ой", когда внезапно выясняется, что для одних процессов должна быть одна валидация, а для других — другая.

J>В DDD есть такие понятия как Entity, Value Object, Aggregate, Aggregate Root.

J>Entity/Value Object — это объекты. Концепция эквивалентности ссылок относится к Entity (User), в то время как структурая эквивалентность — к Value Object(Contact Information). швабра.
J>Aggregate: набор Entities или Value Objects, связанных друг с другом через объект Aggregate Root.
J>Aggregate Root: каждый агрегат имеет корень (в примере выше: User) и границу, агрегатный корень владеет агрегатом и служит шлюзом для всех модификаций внутри агрегата,

J>Бизнес логику желательно писать в самых конечных объектах (Value Objects).

Что? Бизнес логика в ContactInformation? ИмейлАдрес.Отправляйся(), Земля.Копайся() ???

J>В моделях валидацию можно рассматривать как инварианты. Проверка того что объекты всегда в правильном состоянии,

J>весь остальной код в моделях относится только к бизнес логике.
Объекты всегда в правильном состоянии для чего? Для какого процесса?

J>Валидация типа

J>
J>if(repo.GetUserById(id) != null)
J>{
J>    throw new NotFoundException(); 
J>}
J>

J>будет в Application Layer-e.

J>Бизнес логика — это все что говорит заказчик. Сначала определяется уникальный язык(термины) которые заказчик/менеджеры/бизнес аналитик/девы будут использовать чтобы понимать друг друга.

J>Потом договаривают что напр. "Хотим изменить `Info` и `email` у пользователя".
J>Т.к. это относится к сущности User, в моделе User создается метод `UpdateInformation(string info, string email)`, который является прокси методом к бизнес логике,
J>которая будет писаться во вложеных Entitites и Value Objects.

метод UpdateInformation вероятно будет и в анемике тоже. Ключевой поинт анемика лишь в том, нахрена этот метод нужен User-у? Не отменяя того, что User- агрегат для изменения его информации, можно записать
UpdateInformation(User user, string info, string email),
Не говоря уж о том, что можно сделать из этого целый workflow с подтверждением имейла и мобилы, не затрагивая код User-а.

J>Покупатель, корзина товаров, набор акций — это все будут разные агрегаты/агрегат руты.

J>Для взаимодействия агрегатов, что бы проще было расширять бизнес логику и меньше было локов при сохранении данных в бд, в DDD есть понятие как DomainEvents. msdn
J>Напр. у нас есть агрегат руты: User, Order, Product. Пользователь делает заказ.

J>В модель `Order` при создании будет передается 'userId' (Id агрегат рута пользователя) и кидается event создания заказа.

J>После мы можем добавить товар или изменить статус, при изменении статуса будет кидаться другой event.

Вот, DomainEvents — это такой мост между ричем и анемиком в моем понимании. Т.е. появляется обработчик — это что-то внешнее по отношению к модели данных.
J>
  код
J>полный пример

J>

J>public class Order
J>{
J>  // ..

J>  public Order(string userId, string userName, Address address, int cardTypeId, string cardNumber, string cardSecurityNumber,
J>                string cardHolderName, DateTime cardExpiration, int? buyerId = null, int? paymentMethodId = null) : this()
J>        {
J>            _buyerId = buyerId;
J>            _paymentMethodId = paymentMethodId;
J>            _orderStatusId = OrderStatus.Submitted.Id;
J>            _orderDate = DateTime.UtcNow;
J>            Address = address;

J>            // Add the OrderStarterDomainEvent to the domain events collection 
J>            // to be raised/dispatched when comitting changes into the Database [ After DbContext.SaveChanges() ]
J>            AddOrderStartedDomainEvent(userId, userName, cardTypeId, cardNumber,
J>                                       cardSecurityNumber, cardHolderName, cardExpiration);
J>        }

J>  public void AddOrderItem(int productId, string productName, decimal unitPrice, decimal discount, int units = 1)
J>        {
J>            var existingOrderForProduct = _orderItems.Where(o => o.ProductId == productId)
J>                .SingleOrDefault();

J>            if (existingOrderForProduct != null)
J>            {
J>                //if previous line exist modify it with higher discount  and units..

J>                if (discount > existingOrderForProduct.GetCurrentDiscount())
J>                {
J>                    existingOrderForProduct.SetNewDiscount(discount);
J>                }

J>                existingOrderForProduct.AddUnits(units);
J>            }
J>            else
J>            {
J>                //add validated new order item

J>                var orderItem = new OrderItem(productId, productName, unitPrice, discount, pictureUrl, units);
J>                _orderItems.Add(orderItem);
J>            }
J>        }

J>    // ...

J>     public void SetPaidStatus()
J>        {
J>            if (_orderStatusId == OrderStatus.StockConfirmed.Id)
J>            {
J>                AddDomainEvent(new OrderStatusChangedToPaidDomainEvent(Id, OrderItems));

J>                _orderStatusId = OrderStatus.Paid.Id;
J>                _description = "The payment was performed at a simulated \"American Bank checking bank account ending on XX35071\"";
J>            }
J>        }
J>}
J>


Но здесь обработчик лишь вызывает метод объекта, хотя мог бы иметь такой метод сам. Ну и какой смысл совать все такие методы в объекты?

J>В ApplicationLayer-e мы можем подписаться на все эти события и на каждое событие написать свой обработчик (DomainHandler). github


J>Из примеров проектов которые можно посмотреть:

J>https://github.com/aspnetboilerplate/aspnetboilerplate
J>https://github.com/zkavtaskin/Domain-Driven-Design-Example
J>https://github.com/dotnet-architecture/eShopOnContainers

J>и книга по ddd без воды: "Alexey Zimarev, Hands-On Domain-Driven Design with .NET Core — Tackling complexity in the heart of software by putting DDD principles into practice (2019)"


Эти примеры не отвечают на вопрос протаскивания других слоев через параметры методов?
Re[21]: DDD протаскивание других слоев через параметры методов Domain
От: samius Япония http://sams-tricks.blogspot.com
Дата: 29.11.20 19:16
Оценка: +1
Здравствуйте, #John, Вы писали:

J>Здравствуйте, samius, Вы писали:


J>>>В процедурном стиле: не используется сокрытие информации(модификаторы доступа), (т.к. поля/свойства всегда public).

S>>Информацию скрывали и до изобретения модификаторов доступа.

J>Да, можно скрыть неявным образом даже в паскале, напр. написав комментарий:"//Use this struct only from the XXX procedure.".

В паскале есть модули, нет необходимости обходиться подобными комментариями. Можно создать полную аналогию PIMPL.

S>>Модификаторы доступа здесь не наводят ясность, т.к. публичные методы продолжают торчать из объекта. И если пол проекта не меняют поля объекта, которые хотелось бы скрыть, то этим занимаются методы объекта, которые никто не мешает вызывать в разных местах проекта.


J>Публичные методы дают легальную возможность изменить состояние объекта, отсекая все остальные пути(не в счет рефлексию).

Т.е. сокрытие модификатором доступа в C# — и есть тот самый комментарий // Use this field only from the XXX
J>Что бы класс в ооп использовался правильно придумали: SOLID, GoF patterns.
не соглашусь.
SRP был сформулирован для модулей, мало касался объектов напрямую.
OCP был сформулирован так же для модулей, хоть и любителем объектов Мейером. Но активно использовался при проектировании ранее.
LSP — тут соглашусь, это касается исключительно объектов.
ISP — да, Мартин для программных интерфейсов. Но не думаю, что он был первый тут.
DIP — специфичная для объектов форма связности модулей.
В большинстве случаев принципы были сформулированы ранее для модулей, но переформулированы для объектов позднее.

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

J>Классическая идея ооп — изменяемый объект со временем.

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

S>>Что же все так радикально? В вашем примере видел UserInformationDto. Ваш пример — образец процедурного стиля?


J>Нет, DTO — это объект без логики который используется,

J>_только_ для пересылки данных между подсистемами. Обычно это не неизменяемый объект. Но он так же может содержать логику по сериализации/десериализации.
О, все-таки есть в ооп объекты без логики? А я встречал соображения что DTO — это структура данных, а не объект.

S>>Самая простая возможность контролировать изменения объекта — сделать его неизменяемым.

J>Ок. Делать все анемик модели неизменяемыми — это функциональный подход.
Модель — это все-таки про поведение. В анемике у тех сущностей, которые в рич принято считать объектами, нет поведения. Т.е. это не модели, а описания структур, используемых в сообщениях.

J>У функционального подхода есть свои минусы; C# не заточен по фп.

Я бы сказал, что у C# есть свои минусы — он не заточен под фп. Но с каждым обновлением эти минусы значительно сокращаются. Сейчас писать на нем фп далеко не так кошмарно, как это было в 2005-м, например.
Re[22]: DDD протаскивание других слоев через параметры метод
От: gyraboo  
Дата: 29.11.20 19:29
Оценка: :)
Здравствуйте, alexsoff, Вы писали:

J>>Или вы хотите сказать что когда используете anemic модели, то пишите код на C# в функциональном стиле, а не в процедурном?


A>Я хочу сказать, что Anemic модель — шаг в сторону функционального программирования, а если и соблюдать иммутабельность для anamic моделей — то можно говорить, что это почти целевая точка движения современных языков.


Насчёт целевой точки, я бы добавил: если говорить про энтерпрайз, то долгое время властвовал подход анемичной модели с подачи Фаулера и Ко. Эта модель была ненастоящим ООП и ненастоящим процедурным, а неким бастардом, потом по мере распространения ФП этому бастарду в кровь впрыснули ДНК функциональщины, но тоже не-по "настоящему", а в виде эпизодических функциональных вставок, типа "тут мы заменим итератор на стрим с лямбдой". Мне кажется, анемик властвовал в умах потому, что энтерпрайз ещё только формировался, а у всемирного программистского разума есть некое ограничение по мощности, и первые пару десятков лет этот разум был занят формированием базовых основ энтерпрайза и поиском оптимальных решений типичных проблем (продумывание разных видов архитеуктур — слоистых, луковых, гексагональных... придумыванием EE-паттернов, разработкой транзакционных механизмов, механизмов DI, отимистик и пессимистик блокировок и т.д.), и у этого всеобщего разума не хватало сил на качественное продумывание самой сердцевины — бизнес-логики, поэтому первое время порешили что наиболее простым решением будет сделать тупо анемик-классы "почти как во взрослом ООП", а бизнес-логику тупо кидать в "почти процедурные" бизнес-сервисные методы (да, был SOLID, но он слишком был абстрактен и скорее как база и предтеча появления DDD). Но сейчас многие типичные проблемы решены и всеобщий энтерпрайзный разум обратил внимание на реализацию бизнес-логики и решил что пора вводить взрослое ООП — и всё больше проектов начинает обращать внимание на DDD (и главное, иметь силы и компетенции чтобы это самое DDD реализовывать, правда с разной степенью успеха и похожести на оригинальный DDD). Допустим, взять типичные энтерпрайз проекты 20-10 летней давности — основные усилия команды разрабов в том время заключались в том, чтобы реализовать типичные задачи энтерпрайза (и были жуткеи случаи когда целые команды разрабов не владели ни понятием транзакционности, ни блокировок, и всё это выкатывалось на прод и уже на живом продукте внешние более опытные консультанты накатывали на продукт транзакции и прочие патчи, чтобы система работала как энтепрайз), а сейчас каждый средний энтерпрайз-разраб уже ориентируется в этих типичных энтерпрайзных проблемах и умеет их решать "на раз", не нагружая свой мозг, и может направить высвободившуюся ментальную энергию на проработку фишек DDD — "настоящий" ООП: агрегаты, поведение в объектах (вместо поведения в процедурных бизнес-методах как в анемик-модели) с сохранением инварианта, репозитории, единый язык и т.д. Хотя делается это часто отвратно (на прод выводятся проекты, где DDD реализован криво), т.к. разрабы ещё не освоили DDD в полной мере, знаю эту дисциплину не полностью (а она вообще непроста к освоению), но уже пишутся реальные проекты на нём, на хабре всё больше статей, т.е. культура разработки в плане DDD развивается, что только радует. Ситуация с DDD сейчас очень похожа на паттерны: в начале про них все говорили (даже были требования от бизнеса и аналитиков о применении конкретных паттернов, конечно же часто вообще не к месту), разрабы очень часто готовили их неправильно или вообще дальше разговоров дело не заходило, а сейчас паттерны являются частью обще культуры разработки. И получается, что DDD — это ещё одна целевая точка развития, в которой ФП играет лишь роль а-ля "замены итераторов на стримы+лямбды", а скажем иммутабельность в DDD имеет самостоятельную ценность и без ФП, а как одна из стратегий сохранения инварианта объекта или как многопоточный паттерн.

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


И/или за DDD, по причинам, описанным выше))
Отредактировано 29.11.2020 19:31 gyraboo . Предыдущая версия .
Re[23]: DDD протаскивание других слоев через параметры метод
От: alexsoff Россия  
Дата: 30.11.20 02:51
Оценка: +1
Здравствуйте, gyraboo, Вы писали:

G>И/или за DDD, по причинам, описанным выше))

Я ставлю на FP по одной причине = она из-коробки поддерживает параллельность и децентрализацию. Но это не значит, что я предлагаю DDD выкидывать на свалку. Многие верхнеуровневые концепции оттуда (например ограниченные контексты и т.д.) можно применять и в функциональном подходе.
Re[16]: DDD протаскивание других слоев через параметры методов Domain
От: Sharov Россия  
Дата: 14.01.21 15:36
Оценка: :)
Здравствуйте, gandjustas, Вы писали:

S>>А в чем проблема, если код будет вызываться из доменного сервиса? Репозитории как раз для этого и нужны.

G>Для чего в этом примере нужен репозиторий?

Четко обозначить ключевые сущности DDD. Так если подумать, для в примеров из всяких книжек по DDD
репозитории и много чего еще также излишне.
Кодом людям нужно помогать!
Re[17]: DDD протаскивание других слоев через параметры методов Domain
От: Sinclair Россия https://github.com/evilguest/
Дата: 21.01.21 04:00
Оценка: +1
Здравствуйте, #John, Вы писали:

J>Покрывать код тестами, большого продукта, у которого есть план развития, который интенсивно развивается, выгодно бизнесу.

Это всё бесспорные утверждения.
Речь не идёт об отказе от тестирования. Речь идёт о бессмысленном коде абстрактных слоёв — вроде конверсии выхлопа СУБД в DTO, а DTO — в Entities.
Вот мы написали метод, который строит OrderEntity на основе OrderDTO — ок, теперь нам надо к нему написать серию юнит-тестов.
Если мы добавляем в наш Order новое свойство, то оно пролезло и в Entity, и в DTO, и в код по отображению — и теперь надо править существуюшие тесты, а также добавлять новые.
Ещё больше бессмысленной работы и нагрева атмосферы.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DDD протаскивание других слоев через параметры методов Domain
От: #John Европа https://github.com/ichensky
Дата: 11.11.20 11:12
Оценка:
Здравствуйте,

как вы боритесь с тем, что в методы entity, через параметры, в Domain слой протягиваютя классы из других слоев?


internal class Entity : BaseDomainClass<RootAggregate>
{

  internal Entity(RootAggregate root, int id)
  {
     this.root = root;
     this.id = id;
  }

  internal void DoCool(string value, Ac.System system, ILogger logger, IDateTimeProvider, INumberProvider)
  {
     // domain logic       
     ...
     if(...)
     {
        var data = system.GetData(...);
        logger.Log(...);
     }

     // domain logic 
     ...
  }
}


и в каком-то менеджере:
rootAgreagete.Do("xxx","yyy", this.system1, this.system2, this.system3, this.logger, this.provider1, this.provider2, ....);
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[2]: DDD протаскивание других слоев через параметры методов Domain
От: #John Европа https://github.com/ichensky
Дата: 20.11.20 22:05
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>Выделяю поведение в отдельные классы — бизнес-сервисы. Зависимости прокидываю через конструктор в composition root.


Спасибо за ответ, поискал информацию еще в интернете, получается, бизнес-сервисы это один из оптимальных вариантов.
Но и у него есть недостатки: бизнес логика дробится.
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[4]: DDD протаскивание других слоев через параметры методо
От: #John Европа https://github.com/ichensky
Дата: 23.11.20 19:32
Оценка:
Здравствуйте, Буравчик, Вы писали:

J>>Но и у него есть недостатки: бизнес логика дробится.


Б>И какая проблема из этого возникает (пример)?


class Root
{
  // ..

  void Smth()
  {
    bar.DoBar();

    // other logic ..
  }
}

class Bar
{
  // ..

  void DoBar()
  {
        foo.UpdateStatus();

        // other logic ..
  }
}

class Foo
{
  // ..
  private StatusEnum status;

  void UpdateStatus()
  {
    switch(..)
    {
        case "yyy":
            status = StatusEnum.Old;
            break;
        case "xxx": 
            // Если не создавать бизнес сервис,
            // бизнес-логика выглядит последовательной. 
            var x = new HttpClient().GetString("http://...");
            if(x == "str")
            {
                status = StatusEnum.New;
                // other logic ..
            }
        //..
    }
    
    // other logic ..
    
  }
}


Если тут использовать бизнес сервис, то придется часть метода(или весь метод) `UpdateStatus()` вынести в бизнес сервис,
там сделать проверку результата, а потом продолжить выполнение логики из метода "UpdateStatus".

Чем выше будет цикломатическая сложность/вложеных_методов тем сложнее/больше_кода придется вынести в бизнес сервис.

Б>Вообще, она всегда дробится. Вопрос лишь как — по сущностям или по сервисам.

Если выносить код в бизнес сервисы, то данные и способы их обработки оказываются разделены, что нарушает один из принципов ООП,
т.к. не позволяет модели обеспечивать собственные инварианты.
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Отредактировано 24.11.2020 12:03 #John . Предыдущая версия .
Re[6]: DDD протаскивание других слоев через параметры методов Domain
От: #John Европа https://github.com/ichensky
Дата: 24.11.20 16:18
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А Foo и Bar у вас что — типы предметной области?

Да, Foo, Bar, Root — это модели из предметной области; Root — это агрегат рут.

S>В нормальной архитектуре метод UpdateStatus не является членом класса "данных", а принадлежит сервису.

S>Поэтому никакого дробления не будет.
В примере не дописал код.
UpdateStatus меняет значение переменной `status` у класса Foo:
(`status` — потом буде сохранено в бд)
class Foo
{
  // ..
  private StatusEnum status;

  void UpdateStatus()
  {
    switch(..)
    {
        case "yyy":
            status = StatusEnum.Old;
            break;
        case "xxx": 
            var x = new HttpClient().GetString("http://...");
            if(x == "str")
            {
                status = StatusEnum.New;
                // other logic ..
            }
        //..
    }
    
    // other logic ..
    
  }
}
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[6]: DDD протаскивание других слоев через параметры методов Domain
От: #John Европа https://github.com/ichensky
Дата: 24.11.20 18:15
Оценка:
Здравствуйте, Sinclair, Вы писали:

J>>Если выносить код в бизнес сервисы, то данные и способы их обработки оказываются разделены, что нарушает один из принципов ООП,

J>>т.к. не позволяет модели обеспечивать собственные инварианты.
S>Нет такого принципа.

В посте про амемичную модель Фовлер пишет:

... the basic idea of object-oriented design; which is to combine data and process together ...

Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[7]: DDD протаскивание других слоев через параметры методов Domain
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.11.20 10:52
Оценка:
Здравствуйте, #John, Вы писали:

J>В посте про амемичную модель Фовлер пишет:

J>

J>... the basic idea of object-oriented design; which is to combine data and process together ...

Ну, вот за это мы Фаулера и не любим.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: DDD протаскивание других слоев через параметры методов Domain
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.11.20 11:04
Оценка:
Здравствуйте, #John, Вы писали:

S>>В нормальной архитектуре метод UpdateStatus не является членом класса "данных", а принадлежит сервису.

S>>Поэтому никакого дробления не будет.
J>В примере не дописал код.
J>UpdateStatus меняет значение переменной `status` у класса Foo:
J>(`status` — потом буде сохранено в бд)
J>
J>class Foo
J>{
J>  // ..
J>  private StatusEnum status;

J>  void UpdateStatus()
J>  {
J>    switch(..)
J>    {
J>        case "yyy":
J>            status = StatusEnum.Old;
J>            break;
J>        case "xxx": 
J>            var x = new HttpClient().GetString("http://...");
J>            if(x == "str")
J>            {
J>                status = StatusEnum.New;
J>                // other logic ..
J>            }
J>        //..
J>    }
    
J>    // other logic ..
    
J>  }
J>}

J>


Ну всё верно — поэтому-то рич модель плохо работает. Вы втаскиваете внутрь объекта несвойственную ему логику. Он уже вон и в интернет побежал, и всякое прочее делает.
В нормальном дизайне у вас будет что-то вроде FooService.UpdateStatus(foo). Или FooService.UpdateStatus(IEnumerable<Foo> foos).
А уже вот этот FooService будет оборудован каким-нибудь XProvider, который в него инжектируется DI фреймворком или вообще вручную, если нет нужды поддерживать разнообразие конфигураций. Так что вместо new HttpClient().GetString там будет XProvider.GetX()
Это позволит, в частности, тестировать поведение FooService без подключения к интернету и вызова настоящих внешних сервисов.
А также повторно использовать его код в тех случаях, когда у нас есть классы, которые по данным неотличимы от Foo, но с другим поведением. Или вообще — может оказаться, что это тот же самый Foo, только на другом этапе жизненного цикла.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: DDD протаскивание других слоев через параметры методов Domain
От: #John Европа https://github.com/ichensky
Дата: 25.11.20 19:08
Оценка:
Здравствуйте, samius, Вы писали:

S>Есть писатели об обратном.

S>https://blog.inf.ed.ac.uk/sapm/2014/02/04/the-anaemic-domain-model-is-no-anti-pattern-its-a-solid-design/

Читал перевод этой статьи на швабре. Там много не правды. Напр.

Анемичная модель предметной области лучше поддерживает автоматизированное тестирование.
...

В юнит тестах бизнес логику из БМПО можно легко тестировать и поддерживать если мокать БМПО которые используются в коде.
Потому тесты будут одинаково поддерживаемыми. (Думаю об этом автор даже не подумал, т.к. думает если класс хранит данные, значит его мокать нельзя?).

Если меняются требования к хранилищу данных — в АМПО задача решается путем передачи в PurchaseService из вышестоящего класса служб приложения новой реализации существующего интерфейса репозитория [17], [19], не требуя модификации существующего кода; в БМПО так легко не отделаться, модификация базового класса затронет все классы бизнес-сущностей

Автор статьи перепутал Domain Layer и Application Layer. Когда пишут проект по ДДД, БМПО с бизнес логикой находятся в доменном слое(а не в Application Layer), а репозиторий c доступом к данным — в инфраструктурном слое, Domain Layer не зависит от Infrastructure Layer, зависит только от фреймверка на котором пишется код и вспомогательных компонентов/хелперов. В ДДД мы легко можем заменить напр. `ms sql на cosmodb`, при этом не поменяв ни строчки кода в доменном слое.
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[9]: DDD протаскивание других слоев через параметры методов Domain
От: samius Япония http://sams-tricks.blogspot.com
Дата: 25.11.20 20:03
Оценка:
Здравствуйте, #John, Вы писали:

J>Здравствуйте, samius, Вы писали:


S>>Есть писатели об обратном.

S>>https://blog.inf.ed.ac.uk/sapm/2014/02/04/the-anaemic-domain-model-is-no-anti-pattern-its-a-solid-design/

J>Читал перевод этой статьи на швабре. Там много не правды. Напр.

J>

J>Анемичная модель предметной области лучше поддерживает автоматизированное тестирование.
J>...

J>В юнит тестах бизнес логику из БМПО можно легко тестировать и поддерживать если мокать БМПО которые используются в коде.
J>Потому тесты будут одинаково поддерживаемыми. (Думаю об этом автор даже не подумал, т.к. думает если класс хранит данные, значит его мокать нельзя?).

То, что не требует мокать — лучше тестируется. Полагаю, что это правда, согласен с автором. Он ведь не утверждает о невозможности.

J>

J>Если меняются требования к хранилищу данных — в АМПО задача решается путем передачи в PurchaseService из вышестоящего класса служб приложения новой реализации существующего интерфейса репозитория [17], [19], не требуя модификации существующего кода; в БМПО так легко не отделаться, модификация базового класса затронет все классы бизнес-сущностей

J>Автор статьи перепутал Domain Layer и Application Layer. Когда пишут проект по ДДД, БМПО с бизнес логикой находятся в доменном слое(а не в Application Layer), а репозиторий c доступом к данным — в инфраструктурном слое, Domain Layer не зависит от Infrastructure Layer, зависит только от фреймверка на котором пишется код и вспомогательных компонентов/хелперов. В ДДД мы легко можем заменить напр. `ms sql на cosmodb`, при этом не поменяв ни строчки кода в доменном слое.
Тут в самом деле лукавство, т.к. изолировать часть инфраструктуры за интерфейсом репозитория позволяет и рич модель тоже. Но анемик к этому тяготеет по своей природе, а рич требует специальных усилий, что приводит к образованию тем вроде "DDD протаскивание других слоев через параметры методов Domain".
Re[12]: DDD протаскивание других слоев через параметры методов Domain
От: #John Европа https://github.com/ichensky
Дата: 26.11.20 22:10
Оценка:
Здравствуйте, samius, Вы писали:

S>Бизнес логики я в этом примере не увидел. Хотелось посмотреть на чуть более сложном примере, где взаимодействуют покупатель, корзина товаров, набор акций на отдельные группы товаров, накопительные бонусные программы или что-то в этом роде.

S>Я не прошу приводить код, я его довольно ясно представляю, в том числе с тестами и обилием моков.

J>>Если придется работать с внешним сервисом, придется создавать DomainService и дробить бизнес логику в rich-моделях.

S>Проблема рич в том, что чем больше сценариев, тем больше придется дробить бизнес логику в рич моделях.
S>Та же валидация внутри рич моделей говорит "ой", когда внезапно выясняется, что для одних процессов должна быть одна валидация, а для других — другая.

В DDD есть такие понятия как Entity, Value Object, Aggregate, Aggregate Root.
Entity/Value Object — это объекты. Концепция эквивалентности ссылок относится к Entity (User), в то время как структурая эквивалентность — к Value Object(Contact Information). швабра.
Aggregate: набор Entities или Value Objects, связанных друг с другом через объект Aggregate Root.
Aggregate Root: каждый агрегат имеет корень (в примере выше: User) и границу, агрегатный корень владеет агрегатом и служит шлюзом для всех модификаций внутри агрегата,
т.е. из Application Layer нельзя написать код:
var contactInformation = new ContactInformation(...);
repo.Save(contactInformaion);

Все изменения нужно делать только через агрегат рут(User):
var user = userRepository.Load(userId);
user.UpdateInformation(userInformation.Info, userInformation.Email);
userRepository.Save(user);


Бизнес логику желательно писать в самых конечных объектах (Value Objects).
В моделях валидацию можно рассматривать как инварианты. Проверка того что объекты всегда в правильном состоянии,
весь остальной код в моделях относится только к бизнес логике.
Валидация типа
if(repo.GetUserById(id) != null)
{
    throw new NotFoundException(); 
}

будет в Application Layer-e.

Бизнес логика — это все что говорит заказчик. Сначала определяется уникальный язык(термины) которые заказчик/менеджеры/бизнес аналитик/девы будут использовать чтобы понимать друг друга.
Потом договаривают что напр. "Хотим изменить `Info` и `email` у пользователя".
Т.к. это относится к сущности User, в моделе User создается метод `UpdateInformation(string info, string email)`, который является прокси методом к бизнес логике,
которая будет писаться во вложеных Entitites и Value Objects.

--

Покупатель, корзина товаров, набор акций — это все будут разные агрегаты/агрегат руты.
Для взаимодействия агрегатов, что бы проще было расширять бизнес логику и меньше было локов при сохранении данных в бд, в DDD есть понятие как DomainEvents. msdn
Напр. у нас есть агрегат руты: User, Order, Product. Пользователь делает заказ.

В модель `Order` при создании будет передается 'userId' (Id агрегат рута пользователя) и кидается event создания заказа.
После мы можем добавить товар или изменить статус, при изменении статуса будет кидаться другой event.
  код
полный пример


public class Order
{
  // ..

  public Order(string userId, string userName, Address address, int cardTypeId, string cardNumber, string cardSecurityNumber,
                string cardHolderName, DateTime cardExpiration, int? buyerId = null, int? paymentMethodId = null) : this()
        {
            _buyerId = buyerId;
            _paymentMethodId = paymentMethodId;
            _orderStatusId = OrderStatus.Submitted.Id;
            _orderDate = DateTime.UtcNow;
            Address = address;

            // Add the OrderStarterDomainEvent to the domain events collection 
            // to be raised/dispatched when comitting changes into the Database [ After DbContext.SaveChanges() ]
            AddOrderStartedDomainEvent(userId, userName, cardTypeId, cardNumber,
                                       cardSecurityNumber, cardHolderName, cardExpiration);
        }

  public void AddOrderItem(int productId, string productName, decimal unitPrice, decimal discount, int units = 1)
        {
            var existingOrderForProduct = _orderItems.Where(o => o.ProductId == productId)
                .SingleOrDefault();

            if (existingOrderForProduct != null)
            {
                //if previous line exist modify it with higher discount  and units..

                if (discount > existingOrderForProduct.GetCurrentDiscount())
                {
                    existingOrderForProduct.SetNewDiscount(discount);
                }

                existingOrderForProduct.AddUnits(units);
            }
            else
            {
                //add validated new order item

                var orderItem = new OrderItem(productId, productName, unitPrice, discount, pictureUrl, units);
                _orderItems.Add(orderItem);
            }
        }

    // ...

     public void SetPaidStatus()
        {
            if (_orderStatusId == OrderStatus.StockConfirmed.Id)
            {
                AddDomainEvent(new OrderStatusChangedToPaidDomainEvent(Id, OrderItems));

                _orderStatusId = OrderStatus.Paid.Id;
                _description = "The payment was performed at a simulated \"American Bank checking bank account ending on XX35071\"";
            }
        }
}

В ApplicationLayer-e мы можем подписаться на все эти события и на каждое событие написать свой обработчик (DomainHandler). github


Из примеров проектов которые можно посмотреть:
https://github.com/aspnetboilerplate/aspnetboilerplate
https://github.com/zkavtaskin/Domain-Driven-Design-Example
https://github.com/dotnet-architecture/eShopOnContainers

и книга по ddd без воды: "Alexey Zimarev, Hands-On Domain-Driven Design with .NET Core — Tackling complexity in the heart of software by putting DDD principles into practice (2019)"
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[13]: DDD протаскивание других слоев через параметры методов Domain
От: alexsoff Россия  
Дата: 27.11.20 17:13
Оценка:
Здравствуйте, #John, Вы писали:

J>и

[]
Все споры anemic vs rich можно закончить примером наблюдений за новыми языками и обновлениями старых. Почти везде основной упор идет на фишки ФП. Так что anemic, а именно ее можно сделать через ФП, побеждает сейчас.
Re[14]: DDD протаскивание других слоев через параметры методов Domain
От: #John Европа https://github.com/ichensky
Дата: 27.11.20 22:04
Оценка:
Здравствуйте, alexsoff, Вы писали:

A>Все споры anemic vs rich можно закончить примером наблюдений за новыми языками и обновлениями старых. Почти везде основной упор идет на фишки ФП. Так что anemic, а именно ее можно сделать через ФП, побеждает сейчас.


Оставлю для дополнительного размышления ссылку на статью "Про Anemic Domain Model" . В принципе там все сказано.
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[15]: DDD протаскивание других слоев через параметры методов Domain
От: alexsoff Россия  
Дата: 28.11.20 06:48
Оценка:
Здравствуйте, #John, Вы писали:

J>Оставлю для дополнительного размышления ссылку на статью "Про Anemic Domain Model" . В принципе там все сказано.

Такие статьи очень трудно рассматривать всерьез, т.к. они используют прием из демагогии "отсылка к авторитету", Посчитайте сколько в статье встречается Фаулер и Мартин.
Еще раз — функциональные программы (т.е. написанные в функциональном сителе) очень легко параллелить между процессорами/машинами и т.д, потому как функциональный стиль предполагает иммутабельность с самого начала. Чего не скажешь о RichModel — в этом случае нужно осуществить много танцев с бубнами.
Для меня на данный момент (2021 год) это один из главных аргументов в пользу выбора подходов к проектированию. Т.е. общая тенденция идет к децентрализации.
Re[15]: DDD протаскивание других слоев через параметры методов Domain
От: samius Япония http://sams-tricks.blogspot.com
Дата: 28.11.20 13:45
Оценка:
Здравствуйте, #John, Вы писали:

J>Здравствуйте, samius, Вы писали:



S>>метод UpdateInformation вероятно будет и в анемике тоже. Ключевой поинт анемика лишь в том, нахрена этот метод нужен User-у? Не отменяя того, что User- агрегат для изменения его информации, можно записать

S>>UpdateInformation(User user, string info, string email),

J>Это процедурный стиль программирования, типы данных отдельно, логика отдельно.

Единственное, что я изменил в этой записи — передал неявный параметр явно и в коде метода придется к полям user-а обращаться с явным указанием, а не с неявным (this.)

J>Объектно ориентированный подход — это когда данные и логика в одном объекте и мы работаем с объекатами.

J>В ОО объекты представляют сущности из реального мира(ограниченные условиями проекта).
J>Напр. хамелеон умеет менять цвет кожи. В коде мы и должны описывать хамелеона:
J>
J>class Chameleon
J>{
J>    public Color skinColor { get; private set; };

J>    public void ChangeSkin(Color color) => skinColor = color; 
J>}
J>

и чем же следующий хамелеон хуже?
class Chameleon
{
    public Color skinColor { get; set; };
}


J>ObjectsAndDataStructures

Не, ну это детский сад какой-то. Я предпочитаю опираться на принципы, сформулированные Кэйем. У него ничего нет про "данные и логика в одном объекте".

S>>Объекты всегда в правильном состоянии для чего? Для какого процесса?

J>Что бы можно было создать/достать из бд агрегат рут, вызвать любой метод и объект был в валидном состоянии, и ни каких ошибок не выкинуло(напр. NRE),
J>что бы агрегат рут без дополнительных проверок, можно было просто взять и сохранить в бд целиком, одной транзакцией, и не получилось что мы потеряли часть данных.

Я о том, когда валидное состояние для одного процесса(активности) подразумевает потерю части данных, необходимых для другого процесса (активности). При большом и все время растущем наборе активностей все данные не могут быть валидными для любых активностей.
Re[20]: DDD протаскивание других слоев через параметры методов Domain
От: #John Европа https://github.com/ichensky
Дата: 29.11.20 13:39
Оценка:
Здравствуйте, alexsoff, Вы писали:

J>>У оо больше возможностей по написанию более независимого, модульного кода.

A>Т.е. вы не видите разницу между двумя понятиями — процедурное и функциональное программирование и думаете, что это одно и тоже?
Эм, за функциональное программирование никто не говорит.

Вопрос в том как отличить процедурное от ОО.
Меня вполне устраивают описания этих различай в английской вики, т.к. они логичны.
Еще раз процитирую:

Процедурное программирование:

The focus of procedural programming is to break down a programming task into a collection of variables, data structures, and subroutines,
whereas in object-oriented programming it is to break down a programming task into objects that expose behavior (methods) and data (members or attributes) using interfaces.


Объектно-ориентированное:

Object-oriented programming (OOP) is a programming paradigm based on the concept of "objects", which can contain data and code:
data in the form of fields (often known as attributes or properties), and code, in the form of procedures (often known as methods).


Или есть мнение что ооp и procedural programming различаются по другим критериям?


A>Т.е. вы не видите разницу между двумя понятиями — процедурное и функциональное программирование и думаете, что это одно и тоже?

Или вы хотите сказать что когда используете anemic модели, то пишите код на C# в функциональном стиле, а не в процедурном?
Хотел бы глянуть пример проекта (.net default: music store или что-то подобное) реализованного в функциональном стиле на C#.

Чем отличается oop, fp, pp?
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[20]: DDD протаскивание других слоев через параметры методов Domain
От: #John Европа https://github.com/ichensky
Дата: 29.11.20 17:04
Оценка:
Здравствуйте, samius, Вы писали:

J>>В процедурном стиле: не используется сокрытие информации(модификаторы доступа), (т.к. поля/свойства всегда public).

S>Информацию скрывали и до изобретения модификаторов доступа.

Да, можно скрыть неявным образом даже в паскале, напр. написав комментарий:"//Use this struct only from the XXX procedure.".

S>Модификаторы доступа здесь не наводят ясность, т.к. публичные методы продолжают торчать из объекта. И если пол проекта не меняют поля объекта, которые хотелось бы скрыть, то этим занимаются методы объекта, которые никто не мешает вызывать в разных местах проекта.


Публичные методы дают легальную возможность изменить состояние объекта, отсекая все остальные пути(не в счет рефлексию).
Что бы класс в ооп использовался правильно придумали: SOLID, GoF patterns.
Классическая идея ооп — изменяемый объект со временем.

S>Что же все так радикально? В вашем примере видел UserInformationDto. Ваш пример — образец процедурного стиля?


Нет, DTO — это объект без логики который используется,
_только_ для пересылки данных между подсистемами. Обычно это не неизменяемый объект. Но он так же может содержать логику по сериализации/десериализации.

S>Самая простая возможность контролировать изменения объекта — сделать его неизменяемым.

Ок. Делать все анемик модели неизменяемыми — это функциональный подход.

У функционального подхода есть свои минусы; C# не заточен по фп.
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[21]: DDD протаскивание других слоев через параметры методов Domain
От: alexsoff Россия  
Дата: 29.11.20 17:49
Оценка:
Здравствуйте, #John, Вы писали:

J>Или вы хотите сказать что когда используете anemic модели, то пишите код на C# в функциональном стиле, а не в процедурном?


Я хочу сказать, что Anemic модель — шаг в сторону функционального программирования, а если и соблюдать иммутабельность для anamic моделей — то можно говорить, что это почти целевая точка движения современных языков. Я не спорю, что процедурная программа хуже ООП в плане понимания и поддержки, но я хочу сказать, что будущее все-таки за FP стилем, а тут уже Rich Model — очень трудно вписать.
Re[23]: DDD протаскивание других слоев через параметры метод
От: samius Япония http://sams-tricks.blogspot.com
Дата: 29.11.20 19:36
Оценка:
Здравствуйте, gyraboo, Вы писали:

G>Здравствуйте, alexsoff, Вы писали:


J>>>Или вы хотите сказать что когда используете anemic модели, то пишите код на C# в функциональном стиле, а не в процедурном?


A>>Я хочу сказать, что Anemic модель — шаг в сторону функционального программирования, а если и соблюдать иммутабельность для anamic моделей — то можно говорить, что это почти целевая точка движения современных языков.


G>Насчёт целевой точки, я бы добавил: если говорить про энтерпрайз, то долгое время властвовал подход анемичной модели с подачи Фаулера и Ко. Эта модель была ненастоящим ООП и ненастоящим процедурным, а неким бастардом, потом по мере распространения ФП этому бастарду в кровь впрыснули ДНК функциональщины, но тоже не-по "настоящему", а в виде эпизодических функциональных вставок, типа "тут мы заменим итератор на стрим с лямбдой". Мне кажется, анемик властвовал в умах потому, что энтерпрайз ещё только формировался, а у всемирного программистского разума есть некое ограничение по мощности, и первые пару десятков лет этот разум был занят формированием базовых основ энтерпрайза и поиском оптимальных решений типичных проблем (продумывание разных видов архитеуктур — слоистых, луковых, гексагональных... придумыванием EE-паттернов, разработкой транзакционных механизмов, механизмов DI, отимистик и пессимистик блокировок и т.д.), и у этого всеобщего разума не хватало сил на качественное продумывание самой сердцевины — бизнес-логики, поэтому первое время порешили что наиболее простым решением будет сделать тупо анемик-классы "почти как во взрослом ООП", а бизнес-логику тупо кидать в "почти процедурные" бизнес-сервисные методы (да, был SOLID, но он слишком был абстрактен и скорее как база и предтеча появления DDD). Но сейчас многие типичные проблемы решены и всеобщий энтерпрайзный разум обратил внимание на реализацию бизнес-логики и решил что пора вводить взрослое ООП — и всё больше проектов начинает обращать внимание на DDD (и главное, иметь силы и компетенции чтобы это самое DDD реализовывать, правда с разной степенью успеха и похожести на оригинальный DDD). Допустим, взять типичные энтерпрайз проекты 20-10 летней давности — основные усилия команды разрабов в том время заключались в том, чтобы реализовать типичные задачи энтерпрайза (и были жуткеи случаи когда целые команды разрабов не владели ни понятием транзакционности, ни блокировок, и всё это выкатывалось на прод и уже на живом продукте внешние более опытные консультанты накатывали на продукт транзакции и прочие патчи, чтобы система работала как энтепрайз), а сейчас каждый средний энтерпрайз-разраб уже ориентируется в этих типичных энтерпрайзных проблемах и умеет их решать "на раз", не нагружая свой мозг, и может направить высвободившуюся ментальную энергию на проработку фишек DDD — "настоящий" ООП: агрегаты, поведение в объектах (вместо поведения в процедурных бизнес-методах как в анемик-модели) с сохранением инварианта, репозитории, единый язык и т.д. Хотя делается это часто отвратно (на прод выводятся проекты, где DDD реализован криво), т.к. разрабы ещё не освоили DDD в полной мере, знаю эту дисциплину не полностью (а она вообще непроста к освоению), но уже пишутся реальные проекты на нём, на хабре всё больше статей, т.е. культура разработки в плане DDD развивается, что только радует. Ситуация с DDD сейчас очень похожа на паттерны: в начале про них все говорили (даже были требования от бизнеса и аналитиков о применении конкретных паттернов, конечно же часто вообще не к месту), разрабы очень часто готовили их неправильно или вообще дальше разговоров дело не заходило, а сейчас паттерны являются частью обще культуры разработки. И получается, что DDD — это ещё одна целевая точка развития, в которой ФП играет лишь роль а-ля "замены итераторов на стримы+лямбды", а скажем иммутабельность в DDD имеет самостоятельную ценность и без ФП, а как одна из стратегий сохранения инварианта объекта или как многопоточный паттерн.


alexsoff писал о целевой точки движения именно языков, а не энтерпрайза как такового. Тут я с ним соглашусь. Движение именно языков в сторону DDD вовсе не видно. В сторону ФП — очевидно.
Re[24]: DDD протаскивание других слоев через параметры метод
От: gyraboo  
Дата: 29.11.20 19:52
Оценка:
Здравствуйте, samius, Вы писали:

S>alexsoff писал о целевой точки движения именно языков, а не энтерпрайза как такового. Тут я с ним соглашусь. Движение именно языков в сторону DDD вовсе не видно. В сторону ФП — очевидно.


Ну да, невнимательно прочитал исходную мысль)
Re[24]: DDD протаскивание других слоев через параметры метод
От: AndrewJD США  
Дата: 30.11.20 16:39
Оценка:
Здравствуйте, alexsoff, Вы писали:

A>Многие верхнеуровневые концепции оттуда (например ограниченные контексты и т.д.) можно применять и в функциональном подходе.

А что нового в этой концепции? Можно подумать логическое разделение не применялось раньше.
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re[25]: DDD протаскивание других слоев через параметры метод
От: alexsoff Россия  
Дата: 30.11.20 18:47
Оценка:
Здравствуйте, AndrewJD, Вы писали:

AJD>А что нового в этой концепции? Можно подумать логическое разделение не применялось раньше.

применялось, но общеупотребимый термин сложился благодаря DDD
Re[11]: DDD протаскивание других слоев через параметры методов Domain
От: Sharov Россия  
Дата: 03.12.20 12:25
Оценка:
Здравствуйте, #John, Вы писали:

J>Если придется работать с внешним сервисом, придется создавать Domain Service и дробить бизнес логику в rich-моделях.


Почему DomianService, это должен быть либо ApplicationService/Infrastructure.
Кодом людям нужно помогать!
Re: DDD протаскивание других слоев через параметры методов Domain
От: Sharov Россия  
Дата: 03.12.20 12:29
Оценка:
Здравствуйте, #John, Вы писали:

J>как вы боритесь с тем, что в методы entity, через параметры, в Domain слой протягиваютя классы из других слоев?


Как минимум нужно использовать DI, если уж пришлось так делать. По-хорошему, их там быть не должно -- из app layer так точно.
Кодом людям нужно помогать!
Re[13]: DDD протаскивание других слоев через параметры методов Domain
От: Sharov Россия  
Дата: 03.12.20 14:16
Оценка:
Здравствуйте, #John, Вы писали:


J>т.е. из Application Layer нельзя написать код:

J>
J>var contactInformation = new ContactInformation(...);
J>repo.Save(contactInformaion);
J>

J>Все изменения нужно делать только через агрегат рут(User):
J>
J>var user = userRepository.Load(userId);
J>user.UpdateInformation(userInformation.Info, userInformation.Email);
J>userRepository.Save(user);
J>


J>Бизнес логику желательно писать в самых конечных объектах (Value Objects).

J>В моделях валидацию можно рассматривать как инварианты. Проверка того что объекты всегда в правильном состоянии,
J>весь остальной код в моделях относится только к бизнес логике.
J>Валидация типа
J>
J>if(repo.GetUserById(id) != null)
J>{
J>    throw new NotFoundException(); 
J>}
J>

J>будет в Application Layer-e.

Вообще данная логика должна быть в DomainService, зачем app srv. знать про какой-то репо. Выше же сами об этом написали.
Кодом людям нужно помогать!
Re[19]: DDD протаскивание других слоев через параметры методов Domain
От: Sharov Россия  
Дата: 03.12.20 14:37
Оценка:
Здравствуйте, #John, Вы писали:

J>У оо больше возможностей по написанию более независимого, модульного кода.

J>В процедурном стиле: не используется сокрытие информации(модификаторы доступа), (т.к. поля/свойства всегда public).
J>потому может произойти такая ситуация, что код по изменению поля структуры будет раскидан в разных местах проекта/класса,
J>а изменение этого поля будет зависеть от разных условий. А код который меняет это поле будет зависеть еще от другого код,
J>а тот еще и еще. И когда понадобится добавить новую логику которая будет дополнительно как-то менять поле,
J>нам придется вместо того что бы подправить код в одном классе/объекте продебажить пол проекта и найти место куда воткнуть наш код.

Тут хорошая стать и отличная картинка на эту тему -- https://blog.pragmatists.com/domain-driven-design-vs-anemic-model-how-do-they-differ-ffdee9371a86?gi=40c25922c8e9
Кодом людям нужно помогать!
Re[22]: DDD протаскивание других слоев через параметры методов Domain
От: Sharov Россия  
Дата: 03.12.20 14:47
Оценка:
Здравствуйте, alexsoff, Вы писали:

A>Я не спорю, что процедурная программа хуже ООП в плане понимания и поддержки, но я хочу сказать, что будущее все-таки за FP стилем, а тут уже Rich Model — очень трудно вписать.


Поправка: функциональная программа.
Кодом людям нужно помогать!
Re[22]: GoF и ФП
От: Sharov Россия  
Дата: 03.12.20 14:55
Оценка:
Здравствуйте, samius, Вы писали:


S>GoF — целиком и полностью адаптация ранее использовавшихся практик для функций высших порядков (и не только), функторов и т.п.

S>Применение паттерна "Стратегия" можно обнаружить в стандартной процедуре сортировки в "C", в WinAPI и т.п... Остальное так или иначе использовалось за десятки лет до GoF-а в функциональных языках.

А можно примеры? Мне казалось, что GoF больше про декоратор, template method, observer, и, наконец, mvc.
Как это было реализовано в ФП? А главное зачем все это для фп?
Кодом людям нужно помогать!
Re[23]: GoF и ФП
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.12.20 16:24
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, samius, Вы писали:



S>>GoF — целиком и полностью адаптация ранее использовавшихся практик для функций высших порядков (и не только), функторов и т.п.

S>>Применение паттерна "Стратегия" можно обнаружить в стандартной процедуре сортировки в "C", в WinAPI и т.п... Остальное так или иначе использовалось за десятки лет до GoF-а в функциональных языках.

S>А можно примеры?

Стратегия — посмотрите на ту же сортировку в любом ФП языке. http://www.n-a-n-o.com/lisp/cmucl-tutorials/LISP-tutorial-22.html — сортировка принимает на вход функцию, которая реализует стратегию сравнения элементов.
S>Мне казалось, что GoF больше про декоратор, template method, observer, и, наконец, mvc.
S>Как это было реализовано в ФП? А главное зачем все это для фп?
Декоратор — любая функция map в FP это и есть декоратор. Как мы отлаживаем самописанную функцию filter?
Описываем предикат вот так:
(defn debugPred[f]
 (fn [x]
   (print x)
   (f x)
 )
)

Всё, задекорировали. Теперь мы можем проверять, что когда вызывается:
(my-filter coll (debugPred even?))

template method — всё ровно то же самое: имеем некоторый метод, в котором есть общая часть, а есть — настраиваемая. И делаем настраиваемую зависящей от типа объекта.
Например, примерно так делается символьное дифференцирование — само дифференцирование делается шаблоном; а внутри оно делает поиск правила для переданного узла AST.
Разве что обзёрвера у нас нету, т.к. обзёрвить нечего — обычно в ООП мы обзёрвим какие-то изменения.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[23]: GoF и ФП
От: samius Япония http://sams-tricks.blogspot.com
Дата: 03.12.20 17:24
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, samius, Вы писали:



S>>GoF — целиком и полностью адаптация ранее использовавшихся практик для функций высших порядков (и не только), функторов и т.п.

S>>Применение паттерна "Стратегия" можно обнаружить в стандартной процедуре сортировки в "C", в WinAPI и т.п... Остальное так или иначе использовалось за десятки лет до GoF-а в функциональных языках.

S>А можно примеры? Мне казалось, что GoF больше про декоратор, template method, observer, и, наконец, mvc.


Например, тут
https://fsharpforfunandprofit.com/fppatterns/
а если почитать, то тут. Но это нашел навскидку.
https://dev.to/patferraggi/do-you-need-design-patterns-in-functional-programming-370c

S>Как это было реализовано в ФП? А главное зачем все это для фп?

Ну это не то, что бы кто-то сидел и повторял на ФП то, что сделали на ООП. В ФП всякие fold-ы появились со времен абстракции односвязного списка, т.е. предполагаю что на заре LISP, когда объектами еще и не пахло. Там уже умели комбинировать функции как для накопления результата при обходе графа (а накапливать могли кол-во вершин, стоимость пути и т.п. Обход один, а накопления разные, т.е. стратегия), так и что бы записывать в лог вызовы функций. Т.е. функционал декоратора, обсервера и template не требовал оглядки на ООП.

Не знаю, как было на самом деле, списывал ли кто-то решения, но одинаковые идеи часто приходят много кому в голову и в разных сферах бытия. Сетевой адаптер для измерения силы тока — тот же декоратор по сути. Источник бесперебойного питания, всевозможные умные розетки и т.п.
Как это создается? Сначала делаем некий стандартный интерфейс, куда можно подключать разные штуки. Дальше (естественно) хотим в этот же интерфейс втыкать не только стандартные штуки, а еще и штуки, выходящие за стандарт по своей функциональности. Так рождается идея адаптера/декоратора. Но вот обернуть одну функцию другой, как и другие способы комбинирования функций, в фп настолько примитивная идея, что она вряд ли заслуживает каких-то специальных терминов. Композиция — да, но это уже термин из математики.

На счет mvc — оно вряд ли могло родиться в фп.
Re[20]: DDD протаскивание других слоев через параметры методов Domain
От: AndrewJD США  
Дата: 03.12.20 21:29
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Тут хорошая стать и отличная картинка на эту тему -- https://blog.pragmatists.com/domain-driven-design-vs-anemic-model-how-do-they-differ-ffdee9371a86?gi=40c25922c8e9


Это бредовая картинка, потому что анемика может имееть как раз такую же структуру как в DTD, с условием что вся логика в сервисах.
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re[21]: DDD протаскивание других слоев через параметры методов Domain
От: Sharov Россия  
Дата: 03.12.20 22:14
Оценка:
Здравствуйте, AndrewJD, Вы писали:

S>>Тут хорошая стать и отличная картинка на эту тему -- https://blog.pragmatists.com/domain-driven-design-vs-anemic-model-how-do-they-differ-ffdee9371a86?gi=40c25922c8e9

AJD>Это бредовая картинка, потому что анемика может имееть как раз такую же структуру как в DTD, с условием что вся логика в сервисах.

Вероятно, в самых простых приложениях, т.е частный случай. Когда AggregateRoot по сути состоит из одной Entity и т.п.
Во всяком случае, разницу в подходах иллюстрирует хорошо, мне понравилось.
Кодом людям нужно помогать!
Re[22]: DDD протаскивание других слоев через параметры методов Domain
От: AndrewJD США  
Дата: 04.12.20 02:51
Оценка:
Здравствуйте, Sharov, Вы писали:

AJD>>Это бредовая картинка, потому что анемика может имееть как раз такую же структуру как в DTD, с условием что вся логика в сервисах.

S>Вероятно, в самых простых приложениях, т.е частный случай. Когда AggregateRoot по сути состоит из одной Entity и т.п.

Что мешает иметь сложную систему? Отсуствие логики в entity?
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re[23]: DDD протаскивание других слоев через параметры методов Domain
От: Sharov Россия  
Дата: 04.12.20 10:58
Оценка:
Здравствуйте, AndrewJD, Вы писали:

AJD>>>Это бредовая картинка, потому что анемика может имееть как раз такую же структуру как в DTD, с условием что вся логика в сервисах.

S>>Вероятно, в самых простых приложениях, т.е частный случай. Когда AggregateRoot по сути состоит из одной Entity и т.п.
AJD>Что мешает иметь сложную систему? Отсуствие логики в entity?

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

Это бредовая картинка, потому что анемика может имееть как раз такую же структуру как в DTD, с условием что вся логика в сервисах.


Еще раз: да, в каких-то случаях все будет 1 в 1. В самых, вероятно, простейших. Там вся соль на картинке именно в связях,
т.е. ребрах между сущностями в соотв. уровне. Вот эти связи и есть сложность, которую надо контролировать.
DDD предлагает подход, где эти связи отсутствуют, т.е. сложность проще контролировать. Т.е. изоляция на уровне дизайна\архитектуры.
А не только в коде.
Кодом людям нужно помогать!
Re[24]: GoF и ФП
От: Sharov Россия  
Дата: 04.12.20 12:38
Оценка:
Здравствуйте, samius, Вы писали:

S>>Как это было реализовано в ФП? А главное зачем все это для фп?

S>Ну это не то, что бы кто-то сидел и повторял на ФП то, что сделали на ООП. В ФП всякие fold-ы появились со времен абстракции односвязного списка, т.е. предполагаю что на заре LISP, когда объектами еще и не пахло. Там уже умели комбинировать функции как для накопления результата при обходе графа (а накапливать могли кол-во вершин, стоимость пути и т.п. Обход один, а накопления разные, т.е. стратегия), так и что бы записывать в лог вызовы функций. Т.е. функционал декоратора, обсервера и template не требовал оглядки на ООП.

Да, декаратор это чуть ли не простейший паттерн, который можно сделать на ФП. Тут я ошибся.

S>Не знаю, как было на самом деле, списывал ли кто-то решения, но одинаковые идеи часто приходят много кому в голову и в разных сферах бытия. Сетевой адаптер для измерения силы тока — тот же декоратор по сути. Источник бесперебойного питания, всевозможные умные розетки и т.п.


А какая разница кто раньше? Главное где это выразительнее -- кмк, большинство паттернов в ООП будут
выразительнее и понятнее именно в ООП парадигме. Т.е. какие-то приемы в ФП можно проще выразить в ООП. И наоборот.
Кодом людям нужно помогать!
Re[25]: GoF и ФП
От: samius Япония http://sams-tricks.blogspot.com
Дата: 04.12.20 13:08
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, samius, Вы писали:


S>>Не знаю, как было на самом деле, списывал ли кто-то решения, но одинаковые идеи часто приходят много кому в голову и в разных сферах бытия. Сетевой адаптер для измерения силы тока — тот же декоратор по сути. Источник бесперебойного питания, всевозможные умные розетки и т.п.


S>А какая разница кто раньше? Главное где это выразительнее -- кмк, большинство паттернов в ООП будут

S>выразительнее и понятнее именно в ООП парадигме. Т.е. какие-то приемы в ФП можно проще выразить в ООП. И наоборот.

Не соглашусь. Сколько строчек кода нужно написать, что бы выразить в ООП суть паттерна Стратегия?
На хаскеле примерно 1:
fold (+) [1,2,3,4,5]

тут мы передаем в функцию свертки списка операцию сложения элементов. И зачем нам тут ООП?
Re[26]: GoF и ФП
От: Sharov Россия  
Дата: 04.12.20 13:09
Оценка:
Здравствуйте, samius, Вы писали:

S>Не соглашусь. Сколько строчек кода нужно написать, что бы выразить в ООП суть паттерна Стратегия?

S>На хаскеле примерно 1:
S>
S>fold (+) [1,2,3,4,5]
S>

S>тут мы передаем в функцию свертки списка операцию сложения элементов. И зачем нам тут ООП?

В любом языке, где есть указатель на ф-ию вряд ли больше одной строчки кода понадобиться.
Кодом людям нужно помогать!
Re[22]: DDD протаскивание других слоев через параметры методов Domain
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.12.20 16:56
Оценка:
Здравствуйте, Sharov, Вы писали:
S>Вы к каким-то деталям прицепились, дескать в анемичной модели у него не ноль репозиториев в анемике. Ну с его тз
S>DAO и есть простенький репозиторий.
Ну, то есть не выиграл, а проиграл, и не Волгу, а пять рублей.
S>Повтрюсь, суть иллюстрации в связях между компонентами соотв. уровня. В один случае дизайна
S>архитектуры они допускаются, и даже не неизбежны, в другом (DDD) их можно избежать. Все, больше данная картинка не на что
S>не претендует. Неточностей там наверняка не мало, но главное отличие картинка отлично передает. В DDD вообще практически нету
S>зависимостей, сложность контролируема.
Ну это же враньё опять. Связи обоснованы бизнес-логикой. Если нам для бухгалтерии нужны остатки на складах — то связь между ними будет хоть в анемике, хоть в DDD.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[23]: DDD протаскивание других слоев через параметры методов Domain
От: Sharov Россия  
Дата: 04.12.20 17:26
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>>Повтрюсь, суть иллюстрации в связях между компонентами соотв. уровня. В один случае дизайна

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

Речь о том, где эти связи находятся\локализованы -- по всему коду, от DAO к сервисам, или только в AggregateRoot?
Кодом людям нужно помогать!
Re[27]: GoF и ФП
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.12.20 03:55
Оценка:
Здравствуйте, Sharov, Вы писали:

S>В любом языке, где есть указатель на ф-ию вряд ли больше одной строчки кода понадобиться.

Не совсем. Ещё нужна возможность конструировать функции на лету.
В приведённом примере нам повезло — функция + уже была в стандартной библиотеке, и мы ей воспользовались.
В более интересных случаях могут потребоваться одноразовые функции, которые никто в библиотеку складывать не будет. Например, функция "отрезать и выкинуть последние 4 символа строки" — чтобы избавиться от единиц измерения.
Или наоборот, "добавить ко всем строчкам указанный суффикс".
Вот такую простейшую вещь вы на языке C вспотеете записывать — потому, что в нём нету ни замыканий, ни анонимных функций. А указатели на функцию в нём, конечно же, есть.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[28]: GoF и ФП
От: Sharov Россия  
Дата: 05.12.20 15:55
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Sharov, Вы писали:


S>>В любом языке, где есть указатель на ф-ию вряд ли больше одной строчки кода понадобиться.

S>Не совсем. Ещё нужна возможность конструировать функции на лету.
S>В приведённом примере нам повезло — функция + уже была в стандартной библиотеке, и мы ей воспользовались.
S>В более интересных случаях могут потребоваться одноразовые функции, которые никто в библиотеку складывать не будет. Например, функция "отрезать и выкинуть последние 4 символа строки" — чтобы избавиться от единиц измерения.
S>Или наоборот, "добавить ко всем строчкам указанный суффикс".
S>Вот такую простейшую вещь вы на языке C вспотеете записывать — потому, что в нём нету ни замыканий, ни анонимных функций. А указатели на функцию в нём, конечно же, есть.

Если in-place, то да, нужны лямбды. Ну в С понадобится отдельно написать ф-ию, но на паттерне Стратегия это не скажется...
Кодом людям нужно помогать!
Re[29]: GoF и ФП
От: samius Япония http://sams-tricks.blogspot.com
Дата: 05.12.20 16:10
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, Sinclair, Вы писали:


S>>Вот такую простейшую вещь вы на языке C вспотеете записывать — потому, что в нём нету ни замыканий, ни анонимных функций. А указатели на функцию в нём, конечно же, есть.


S>Если in-place, то да, нужны лямбды. Ну в С понадобится отдельно написать ф-ию, но на паттерне Стратегия это не скажется...


А на прокси скажется.
Re[30]: GoF и ФП
От: Sharov Россия  
Дата: 05.12.20 18:11
Оценка:
Здравствуйте, samius, Вы писали:

S>>Если in-place, то да, нужны лямбды. Ну в С понадобится отдельно написать ф-ию, но на паттерне Стратегия это не скажется...

S>А на прокси скажется.

Не понял почему? Прокси это же вообще отдельная сущность/ф-ия.
Кодом людям нужно помогать!
Re[29]: GoF и ФП
От: Sinclair Россия https://github.com/evilguest/
Дата: 06.12.20 06:18
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Если in-place, то да, нужны лямбды. Ну в С понадобится отдельно написать ф-ию, но на паттерне Стратегия это не скажется...

В С понадобится не только написать функцию; потребуется протаскивать в неё контекст.
Но вы совершенно правы — сам паттерн будет иметь место и в C. Точнее, определённый вариант паттерна.
Надо просто понимать, что паттерны — это обобщённые описания решений типичных задач в рамках определённой технологии.
Если у нас какое-то решение сразу встроено в язык, то паттерн "исчезает" — то есть его можно заметить только опытным взглядом.
Поэтому в ФП никто не говорит о паттернах "стратегия" и "декоратор" — их реализация встроена в язык.
Точно так же нет паттерна subscriber/publisher в дотнете — там есть ивенты, которые реализуют его из коробки.
В дельфи нет фабрик — есть виртуальные конструкторы.
В С++ нет паттерна "VMT", которым можно реализовать наследование реализаций в C — потому что порождение VMT и обращение к нему встроены в язык.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[31]: GoF и ФП
От: samius Япония http://sams-tricks.blogspot.com
Дата: 06.12.20 18:38
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, samius, Вы писали:


S>>>Если in-place, то да, нужны лямбды. Ну в С понадобится отдельно написать ф-ию, но на паттерне Стратегия это не скажется...

S>>А на прокси скажется.

S>Не понял почему? Прокси это же вообще отдельная сущность/ф-ия.

Паттерн указывает на то, что прокси хранит ссылку на то, что заменяет. С лямбдой — нет проблем. Когда лямбд нет и за них указатели на функции, то хранить там что-то кроме указателя не получается.
Re[24]: DDD протаскивание других слоев через параметры методов Domain
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.12.20 08:09
Оценка:
Здравствуйте, Sharov, Вы писали:
S>Речь о том, где эти связи находятся\локализованы -- по всему коду, от DAO к сервисам, или только в AggregateRoot?
В сервисах, естественно. AggregateRoot у вас чреват неявными зависимостями через справочные entity — когда кажется, что всё разделено, однако при изменении в одном месте разъезжается ещё в семи.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[25]: DDD протаскивание других слоев через параметры метод
От: Sharov Россия  
Дата: 10.12.20 12:34
Оценка:
Здравствуйте, AndrewJD, Вы писали:

S>>Еще раз: да, в каких-то случаях все будет 1 в 1. В самых, вероятно, простейших.

AJD>Я например утверждаю, что она такая же и для сложных случаев.

Да я не против, речь о контроле над сложностью -- внесение изменений, новый функционал и т.п.
В DDD утверждается, что если делать по "инструкции", то все будет ок.

S>>Там вся соль на картинке именно в связях,

S>>т.е. ребрах между сущностями в соотв. уровне. Вот эти связи и есть сложность, которую надо контролировать.
AJD>Количество связей плюс/минус одинаково ибо оно дикуется бизнес логикой, вопрос в том где эти связи располагаются.

Как я понял, в DDD эти связи стараются локализовать, изолировать.

S>>DDD предлагает подход, где эти связи отсутствуют, т.е. сложность проще контролировать. Т.е. изоляция на уровне дизайна\архитектуры. А не только в коде.

AJD>Сливание всего в кучу не означает что связи исчезли. ИМХО, в этом и проблема, что в DDD постулируется что это приводит к лучшему дизайну без доказательств. Даже в этой статье приводится "Aggregates allow us to encapsulate parts of our domain so our API becomes simpler and changes inside aggregates are easier to implement (we don’t need to analyse our changes impact on some other parts of the domain because it doesn’t exist)" без аргументов откуда это следует. Из моей практики я вижу строго наоборот, что разделние логики и данных уменьщает связанность и делает дизайн гибче, а код быстрее.

А что и как тут можно доказать? Задачи DDD -- уменьшение связанности за счет выделения AR, т.е.
чем меньше ребер (на любом уровне), тем лучше. В DDD утверждается, что если делать все по науке,
то ребра будут только в BL(domain service), внутри AR, край -- между AR.
Кодом людям нужно помогать!
Re[12]: DDD протаскивание других слоев через параметры методов Domain
От: Sharov Россия  
Дата: 13.01.21 16:33
Оценка:
Здравствуйте, gandjustas, Вы писали:


G>Если у меня программист напишет такое больше одного раза, то он будет уволен, потому что тратит мои деньги.


Вы бы потрудились объяснить, что с кодом выше не так? Кроме статических методов Create
(должна быть по идее фабрика какая-нибудь), особых проблем не видно.


G>А в идеале еще и два класса данных объединить в один и испольовать modelbinding или мапперы, а не ручное присваивание DTO. И избавится от UserService, а код написать непосредственно в контроллере.

G>И мне все равно что там более или менее ООП, что там думает фаулер, эванс или буч. Мне важно что я плачу фактически за каждую строку кода и чем меньше программисты созают строк кода для решения задачи, чем больше я могу заработать.

Это конечно, оффтоп, но фраза крайне странная: если Вы не платите своей кровью (мало ли, заказчик за баг отмудохает),
то тогда да, меньше строчек, меньше багов. Но Вы платите за время, а не за строчки. Т.е., получается,
за удаление строк кода (рефакторинг, например), программист Вам еще и доплатит?

J>>Из дополнительных плюсов с DDD мы легко можем применить CQRS подход.

G>Лучше раскажи как ты в своем коде сделаешь такое:
G>
G>dbContext.Users.Select(u => new UserInformationDto { Info = u.Info, Email = u.ContactInformationюEmail }).ToListAsync()
G>

G>Это тебе понадобится 100%, а CQRS не понадобится совсем.

А в чем тут затык?
Кодом людям нужно помогать!
Re[14]: DDD протаскивание других слоев через параметры методов Domain
От: Sharov Россия  
Дата: 13.01.21 16:37
Оценка:
Здравствуйте, gandjustas, Вы писали:

Б>>Просто добавить этот код в репозиторий

G>А потом вызывать его из сервиса. Вот и кончился DDD с его Entity и Aggregate Root.

А в чем проблема, если код будет вызываться из доменного сервиса? Репозитории как раз для этого и нужны.
Кодом людям нужно помогать!
Re[13]: DDD протаскивание других слоев через параметры методов Domain
От: Sharov Россия  
Дата: 13.01.21 16:39
Оценка:
Здравствуйте, Буравчик, Вы писали:


Б>И объединил репозиторий с сервисом, прибив сервис к БД. Но в твоем сервисе содержится код для двух задача:

Б>- код для обработки бизнес-логики
Б>- код для обработки хранения данных

Читал мнения, что dbContext можно рассматривать как репозиторий. Т.е. отдельно создавать репо
иногда бывает излишне. Но это скорее для совсем крошечных приложений, для которых DDD и смысла-то не имеет.
Кодом людям нужно помогать!
Re[13]: DDD протаскивание других слоев через параметры методов Domain
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 14.01.21 08:24
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, gandjustas, Вы писали:



G>>Если у меня программист напишет такое больше одного раза, то он будет уволен, потому что тратит мои деньги.


S>Вы бы потрудились объяснить, что с кодом выше не так? Кроме статических методов Create

S>(должна быть по идее фабрика какая-нибудь), особых проблем не видно.
Проблема в том, что кода сильно больше, чем необходимо для реения задачи. Это означает увеличенное количество ошибок и увеличенные затраты н поддержку.


G>>А в идеале еще и два класса данных объединить в один и испольовать modelbinding или мапперы, а не ручное присваивание DTO. И избавится от UserService, а код написать непосредственно в контроллере.

G>>И мне все равно что там более или менее ООП, что там думает фаулер, эванс или буч. Мне важно что я плачу фактически за каждую строку кода и чем меньше программисты созают строк кода для решения задачи, чем больше я могу заработать.

S>Это конечно, оффтоп, но фраза крайне странная: если Вы не платите своей кровью (мало ли, заказчик за баг отмудохает),

S>то тогда да, меньше строчек, меньше багов. Но Вы платите за время, а не за строчки. Т.е., получается,
S>за удаление строк кода (рефакторинг, например), программист Вам еще и доплатит?
Я плачу своими деньгами, это почти то же самое.
Если строчек сильно больше чем надо это значит программист уже потратил время (и деньги) на создание этого.

J>>>Из дополнительных плюсов с DDD мы легко можем применить CQRS подход.

G>>Лучше раскажи как ты в своем коде сделаешь такое:
G>>
G>>dbContext.Users.Select(u => new UserInformationDto { Info = u.Info, Email = u.ContactInformationюEmail }).ToListAsync()
G>>

G>>Это тебе понадобится 100%, а CQRS не понадобится совсем.

S>А в чем тут затык?

Затыка никакого нет. Только тако код обычно убивает весь DDD. Любая попытка прикрутить DDD-патерны к этому коду сделает его однозначно хуже.
Re[15]: DDD протаскивание других слоев через параметры методов Domain
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 14.01.21 08:25
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, gandjustas, Вы писали:


Б>>>Просто добавить этот код в репозиторий

G>>А потом вызывать его из сервиса. Вот и кончился DDD с его Entity и Aggregate Root.

S>А в чем проблема, если код будет вызываться из доменного сервиса? Репозитории как раз для этого и нужны.

Для чего в этом примере нужен репозиторий?
Re[14]: DDD протаскивание других слоев через параметры методов Domain
От: Sharov Россия  
Дата: 14.01.21 15:39
Оценка:
Здравствуйте, gandjustas, Вы писали:

S>>Вы бы потрудились объяснить, что с кодом выше не так? Кроме статических методов Create

S>>(должна быть по идее фабрика какая-нибудь), особых проблем не видно.
G>Проблема в том, что кода сильно больше, чем необходимо для реения задачи. Это означает увеличенное количество ошибок и увеличенные затраты н поддержку.

Это игрушечный пример, не более.

S>>Это конечно, оффтоп, но фраза крайне странная: если Вы не платите своей кровью (мало ли, заказчик за баг отмудохает),

S>>то тогда да, меньше строчек, меньше багов. Но Вы платите за время, а не за строчки. Т.е., получается,
S>>за удаление строк кода (рефакторинг, например), программист Вам еще и доплатит?
G>Я плачу своими деньгами, это почти то же самое.

Таки платите за время, а не за строчки.

G>Если строчек сильно больше чем надо это значит программист уже потратил время (и деньги) на создание этого.


При таком подходе имеет смысл работать только одному -- колоссальная экономия.
Кодом людям нужно помогать!
Re[15]: DDD протаскивание других слоев через параметры методов Domain
От: Sinclair Россия https://github.com/evilguest/
Дата: 19.01.21 06:15
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Таки платите за время, а не за строчки.

То на то и выйдет. Строчки — не бесплатны, даже если их порождает Intellisense.
G>>Если строчек сильно больше чем надо это значит программист уже потратил время (и деньги) на создание этого.
S>При таком подходе имеет смысл работать только одному -- колоссальная экономия.
Нет, никакой экономии нету. Строчки всё равно кто-то должен написать. Можно написать миллион LOC в одно рыло, можно командой в 100 человек.
Во втором случае получится быстрее. Но при фиксированном размере команды написать 3 миллиона строк будет дольше, чем 1 миллион строк.
А ведь у нас же ещё за кадром стоит код тестов, которым нам угрожают фанаты DDD — то есть мало того, что мы пишем больше кода в приложении, мы ещё и вынуждены писать тесты для этого бойлерплейта.
Amplification factor увеличивается, и пока в Виллариба всё ещё отлаживают очередной бессмысленный код абстрактного слоя, Виллабаджо уже запустились в продакшн и расширяют пользовательскую базу.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[16]: DDD протаскивание других слоев через параметры методов Domain
От: #John Европа https://github.com/ichensky
Дата: 20.01.21 22:36
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А ведь у нас же ещё за кадром стоит код тестов, которым нам угрожают фанаты DDD — то есть мало того, что мы пишем больше кода в приложении, мы ещё и вынуждены писать тесты для этого бойлерплейта.


Тесты — это контракт, документация, которую написал разработчик и которую разработчику придется подправить, если он изменит логику кода.
Тесты помогаю не сломать то что уже написано в старом/новом проекте.
Интеграционные тесты помогают понять логику как работает проект.
Через интеграционный тесты можно продебажить/протестировать код, который просто так не вызвать, потому что проект зависит от других внешних сервисов, которые в тесте мокаются.
Все-таки дешевле что бы программист потратил на написание кода 2-3часа вместо 1го,
но потом не пришлось тратить время кучи менеджеров/qa,архитекторов/девопсов/ба и других на обсуждение, фикс, деплой очередной баги.
Код надо покрывать на столько % на сколько хочешь быть уверенным что код работает корректно.

Если работаешь над каким-то мелким проектом, который тебя попросили сделать на вчера,
где требования меняют каждый день и все горит или это RD проект и непонятно станет он частью продукта или будет выкинут после презентации.
Или на проекте 1-3ри человека и вы просто занимаетесь поддержкой проекта и вам особо плевать как вы пишите код ибо вас ни кто не контролирует.
Можно сделать исключение и тесты не писать.

Покрывать код тестами, большого продукта, у которого есть план развития, который интенсивно развивается, выгодно бизнесу.
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re: DDD протаскивание других слоев через параметры методов Domain
От: no4  
Дата: 21.01.21 11:40
Оценка:
Здравствуйте, #John, Вы писали:

J>как вы боритесь с тем, что в методы entity, через параметры, в Domain слой протягиваютя классы из других слоев?


Если в бизнес логике нельзя использовать типы из других слоев, то можно либо выделить слой в отдельную сборку и следить, чтобы зависимости между сборками не противоречили архитектуре; либо использовать схемы зависимостей (но сам я этого не пробовал).

Если типы в принципе можно использовать, но нельзя в качестве параметров, то я не понимаю почему.
Re[2]: DDD протаскивание других слоев через параметры методов Domain
От: Sharov Россия  
Дата: 22.01.21 08:25
Оценка:
Здравствуйте, takTak, Вы писали:

T>З

J>>и в каком-то менеджере:
J>>
J>>rootAgreagete.Do("xxx","yyy", this.system1, this.system2, this.system3, this.logger, this.provider1, this.provider2, ....);

J>>


T>тоже добавлю свои 3 копейки:

T>за что, собственно, отвечает обьект типа Entity ? не слишком ли много он на себя берёт, если ему нужно аж 8 зависимостей?

Например, доменных сервис, о чем говорит название rootAggregate.
Кодом людям нужно помогать!
Re[3]: DDD протаскивание других слоев через параметры методов Domain
От: takTak  
Дата: 22.01.21 09:48
Оценка:
T>>З
J>>>и в каком-то менеджере:
J>>>
J>>>rootAgreagete.Do("xxx","yyy", this.system1, this.system2, this.system3, this.logger, this.provider1, this.provider2, ....);

J>>>


T>>тоже добавлю свои 3 копейки:

T>>за что, собственно, отвечает обьект типа Entity ? не слишком ли много он на себя берёт, если ему нужно аж 8 зависимостей?

S>Например, доменных сервис, о чем говорит название rootAggregate.


если исходить из того, что

The aggregate root is responsible for ensuring that the state is consistent with the business invariant.


то всё-равно получается, что over 8 зависимостей для обеспечения целостности и непротиворечивости предметной логики — это перебор, ну есть там какой-то доступ к хранилищу, этого же, в принципе, должно быть достаточно: вся проверка находится в этом же aggregate root , что ещё нужно -то ?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.