Владимир Хориков - Domain-driven design: Cамое важное

  Рет қаралды 56,366

DotNext — конференция для .NET‑разработчиков

DotNext — конференция для .NET‑разработчиков

Күн бұрын

Пікірлер: 114
@ИгорьВасилевич-э4р
@ИгорьВасилевич-э4р 2 жыл бұрын
Отличный доклад - редко когда видно, что человек понимает о чем говорит, а значит и может донести мысль до слушателя
@slikeiv4477
@slikeiv4477 2 жыл бұрын
шикарный доклад и огромное спасибо Владимиру за талант понятно доносить материал
@xonicov
@xonicov 2 жыл бұрын
Владимир, Вы потрясающий докладчик! Давно не слушал настолько крутого доклада!
@antonshinkevich7019
@antonshinkevich7019 Жыл бұрын
Тайм-коды: 2:32 Начало. План лекции 3:20 Основные принципы DDD. Ограниченные контексты (bounded context). Problem space, solution space 10:55 Единый язык (ubiquitous language) 15:58 Фокус на доменной модели. Многослойные архитектуры 21:51 Разница между анемичной и богатой моделью 23:32 Богатая модель = Инкапсулированная модель. Про понятие инкапсуляции 27:31 (Не) анемичная доменная модель в рамках функционального программирования 30:17 Рефакторинг анемичной модели через два шага. Строгая типизация 34:15 Уменьшение количества методов, которые изменяют состояние класса 41:06 Вопрос: влияние единого языка на развитие проекта 42:38 Изоляция доменной модели 49:21 Взаимосвязь между инкапсуляцией и изоляцией доменной модели 53:19 DDD трилемма. Изоляция > Инкапсуляция > Быстродействие 59:57 Конец доклада. Вопросы 1:00:56 Как склонить коллег к переходу к богатой модели от анемичной? 1:02:20 Интеграция между Entity Framework и DDD. Наследование от POCO (или DTO?) 1:04:55 Что-то там про передачу интерфейса 1:06:41 Разница между subdomain и bounded context 1:09:00 Рефакторинг при database first approach 1:11:30 Стоит ли использовать DDD прототипирование?
@judexmars4214
@judexmars4214 8 ай бұрын
Интересный подход. Вроде как и много сказанное здесь звучит логично и правильно, но и очень непривычно. Спасибо за доклад
@Chat-Mayevskogo
@Chat-Mayevskogo 3 жыл бұрын
Пока лучшее что я видел по DDD для чайников (коим и являюсь). 33 минута, по этой логике и Name нужно обернуть в класс ведь можно указать и пробел или символ и т.п. Важно найти баланс но с другой стороны обернуть в класс не сложно оставив различные валидации и усовершенствования класса своим потомкам)))
@nikolay4362
@nikolay4362 Жыл бұрын
на редкость хорошая лекция
@alexanderinkognito8379
@alexanderinkognito8379 3 жыл бұрын
Книга по тестированию супер! рекомендую всем, must read
@denisthestudent
@denisthestudent 3 ай бұрын
Спасибо, наконец-то я узнал, что такое инкапсуляция! Спустя год и 8 месяцев учёбы
@learning867
@learning867 Жыл бұрын
56:00 для таких инвариантов придется знание о доменной модели выносить в бд - уникальный индекс на email. И тогда при вставке бд выдаст ошибку, и ее можно будет обработать на доменном уровне. Ни один из описанных в видео способов не явлется рабочим в конкурентной среде. Если два пользователя решили одновременно сменить email на другой одинаковый, то выборка из бд и проверка в памяти потенциально могут у обоих завершиться успешно. И оба вставят в бд один и тот же email. Если вынести проверку на уровень бд, то и код в доменной модели станет проще. Да, можно сказать, что мы переносим проверку инварианиа на инфраструктурный уровень - уровень бд. Но вообще-то бд является отражением наших сущностей в доменной модели. Мы не переносим эту логику в реопозитрий. Мы переносим ее в саму бд - место хранения инфы о нашем домене. Ну и это единственный адекватный рабочий способ. Ну либо можно брать блокировки (или распределеоные блокировки), но вот это уже перенос сохранения инварианта в инфраструктуру
@ilmakeyouone
@ilmakeyouone 6 ай бұрын
а если у нас подтверждение на изменение пользовательского email зависит не только от его уникальности, но и от других факторов (например подтверждение модератором)? и количество таких условий может множится и бизнес логика может проходить сквозь всю структуру. тогда мы опять попадаем в анемичную модель.
@borisnikulitsa695
@borisnikulitsa695 2 жыл бұрын
Пример по моему подобран удачно. Сразу становится понятно про разделение контекста в случае схожих сущностей (Customer и Product) Спасибо за доклад
@user-fg6ng7ej6w
@user-fg6ng7ej6w Жыл бұрын
очень толковый доклад, спасибо
@namesecondname663
@namesecondname663 3 жыл бұрын
Супер! Отличный доклад, спасибо.
@alekseyshibayev5243
@alekseyshibayev5243 Жыл бұрын
Спасибо коллегам из мира java для windows 😊 В пет проекте так и делал, пользуясь С и О принципами солид, не догадываясь про ДДД. Оказывается ДДД расширяет эти принципы. Очень похоже про те штуки, за которые топил Егор Бугаенко. Единственное не согласен, что надо лепить все в один класс. Я бы выделил емеил и статус в отдельную бизнес сущность, и создал класс ответственный за эту сущность и пусть он ее меняет. Книгу записал в todo.
@user-lp6rp
@user-lp6rp 6 ай бұрын
Нам бы проблемы трехлетней давности. Печально вспоминать из 2024г.
@-dubok-
@-dubok- 2 жыл бұрын
Мне кажется, что Владимир на 41:13 приуменьшает роль DDD в проекте. Потому что, на мой взгляд, хотя я только его ещё изучаю, DDD даёт не только единый язык и взаимопонимание, но и в целом раскладывает всё в проекте по полочкам, позволяя легко в нём ориентироваться, легко его поддерживать и вносить изменения. Благодаря DDD избегается превращение проекта в то, что адепты DDD называют «большим комом грязи». А это уже очень полезно и в разы улучшает поддерживаемость кода и экономит по-настоящему огромные ресурсы компании, обеспечивая при этом высокую функциональность, feature-richness продукта. По-моему, DDD в корне меняет всё, он просто переворачивает всю игру с головы на ноги, раскладывая все яйца по своим корзинам. DDD - это must have на любых проектах, связанных с реальным миром, реальными предметными областями и бизнесом в частности. DDD - это инструкция к тому, как правильно писать код, как сделать его чистым и логичным, и никак не меньше. Ну а в целом доклад очень крутой, всё чётко и по полочкам. Особенно понравилось как показано превращение анемичной модели в богатую. Вообще, когда что-то на примерах показывается - это очень хорошо воспринимается всегда. За это прям большое спасибо! А насчёт трилеммы. Лично я не думаю, что использование репозитория в модели - это страшно, потому что репозиторий - это основа любой программы, так как он сохраняет стейт, загружает его, работает с ним, а это - основа основ. Поэтому бояться его и тем более отказываться от него в пользу меньшего быстродействия, по-моему, не разумно. Наоборот, работая с репозиторием в модели, ты видишь, где необходима транзакционная целостность, а значит видишь какие агрегаты ты должен объединить в один, чтобы транзакции по нему проходили нормально. Лично я бы поставил на инкапсуляцию + быстродействие. Смещать логику в контроллеры - это тоже ерунда, так как логика приложения должна быть в модели, и не важно, что эта логика зависит от репозитория. Просто считаем репозиторий частью модели - вот и всё, ведь по сути так оно и есть. Репозиторий хранит данные по бизнесу, а разве это не часть бизнеса? Списки e-mail'ов, адресов - это ведь всё часть бизнеса, это не что-то, связанное с инфраструктурой. Это реальные данные по бизнесу. К тому же репозиторий - это виртуальная сущность, которая изолирует модель от прямой связи с базой. Базу репозитория всегда можно заменить. Это вообще может под капотом быть какой-нибудь API, или частично API, частично БД, частично вообще файловая система или LDAP - всё, что угодно, может внутри содержать репозиторий, и это никак не повлияет на модель, потому что репозиторий всегда выдаёт лишь те данные, которые реально связаны с моделью и являются частью бизнеса.
@tedikvredik
@tedikvredik Жыл бұрын
отличный коммент! Спасибо
@sergafanasiev7956
@sergafanasiev7956 Жыл бұрын
Согласен! Отличный коммент! Действительно, что плохого в том, чтобы модель могла делать save, пусть даже в абстрактную БД, чтобы потом, в случае смены БД, можно было через адаптер подменить логику Хранилища! Более того, что если Фабрика, создающая Агрегат, будет также создавать Хранилище и подсовывать его Агрегату на старте?
@natasha1059
@natasha1059 Жыл бұрын
Очень емко, точно, мне все стало понятно, спасибо!
@Berill82
@Berill82 Жыл бұрын
33:15 Очень хочется посмотреть, что будет с этой скидкой, если она будет зависеть от чего-то ещё, кроме статуса. И вообще, как можно поместить функцию расчета скидки в объект Статус?! А если от статуса будет ещё что-то зависеть? Тоже сделаем методом в классе Статус?!
@alekseykouzmenko9096
@alekseykouzmenko9096 6 ай бұрын
Ответ чуть далее по ходу - там где требуется использовать внешние данные инвариант должен быть неизменяемым.
@СергейКрылов-ж4н
@СергейКрылов-ж4н Жыл бұрын
Спасибо, отличный доклад
@sau9703
@sau9703 3 жыл бұрын
Вот те раз , всегда боролись и пропагандировали за анемичную модель , из-за ее слабой связанности и гибкости в плане расширения возможных операций над ней , и тут на тебе , снова в 90-е ) . У богатой модели много проблем , это паутина , в которой с ростом модели не разобраться , ее тяжело масштабировать , а при внезапно новом бизнес правиле многое переписывать. При анемичном подходе , нам ничего не мешает возложить валидацию консистентности модели на доменные сервисы , а клиентам отдавать record-ы дабы не могли накосячить с моделью напрямую. , ну и нет никаких проблем с добавлением новых бизнес правил , при этом не затрагивая существующие модели и методы работы с ними.
@-dubok-
@-dubok- 2 жыл бұрын
Сервисная модель полна излишеств и не отражает сущность бизнеса. Глядя на неё ты не понимаешь, для чего она существует. В ней также перемешана логика и инфраструктура. В богатой модели как раз таки всё понятно. Она описывает саму себя. Главное - всегда рисовать её диаграмму.
@SergeMSO
@SergeMSO Жыл бұрын
Аналогичное чувство появилось, только связал с серединой 2000-х. Очередные ребята сделали "открытие". "Я не знаю почему так лучше, но бизнесу нравится"
@SergeMSO
@SergeMSO Жыл бұрын
А, вот это вообще пушка: "вот в таком подходе сделаете за 2 дня, а в старом займёт 2 месяца".
@Игорь-з8ю9я
@Игорь-з8ю9я Жыл бұрын
на контексты надо разбивать, про это сказано вначале
@theeasywaytr4293
@theeasywaytr4293 2 жыл бұрын
Владимир отличный пример привел! Спасибо за доклад!
@ryazanov13
@ryazanov13 Жыл бұрын
58:18 Если мы выберем вариант с инкапсуляцией и интерфейсом, то можно прекрасно всё тестировать без моков. При этом 3 вариант где плохое быстродействие не обеспечит инкапсуляции. Я имею ввиду вариант прокинуть все заказы в кастомера, т.к. ничто нам не мешает прокинуть пустой или неполный массив (и вообще будет не очевидно какой список кидать в метод). Как по мне нормальная реализация 3го варианта (с инкапсуляцией, изоляцией, но плохой скоростью) это запихнуть список кастомеров в другую модель.
@emotional_stuff
@emotional_stuff 5 ай бұрын
спасибо за практические примеры, Очень важный момент
@zscauer
@zscauer Жыл бұрын
очень крутой доклад
@rtm0076
@rtm0076 10 ай бұрын
Почему вы пропускаете тот момент что CustomerService так же инкапсулирует в себя DataLayer + CacheLayer? Можно приводить примеры более как то приближенные к жизни?
@alexanderinkognito8379
@alexanderinkognito8379 3 жыл бұрын
Такой вопрос, разбили на контексты и написали приложение. Через год понимаем что помимо Продаж и Поддержка нужен еще контекст Маркетинг(или любой другой), как быть в такой ситуации? Насколько деление на контексты является гибким решением? А бывает так что "добавьте вот такую маленькую фичу", фича и правда маленькая но не ложится в существующие контексты, а создавать новый может быть дорого для бизнеса.
@magicmanam
@magicmanam 2 жыл бұрын
Вероятность того, что "маленькая" фича станет со временем большой > 0. В этом случае поддержка изменённого существующего контекста будет тоже дорога для бизнеса, т.к. будет требовать всё более и более объёмной регрессии при будущих модификациях этого контекста с "маленьким" костылём. Это нужно иметь в виду, ну а поступать так, как считаете нужным. Ведь лучше ошибиться и получить опыт, чем пытаться найти "общий" ответ там, где его нет)
@timur43378
@timur43378 Жыл бұрын
Так добавление нового контекста никак не влияет на другие контексты, в этом и есть смысл, чтобы ограничить влияние контекстов. Так что новый контекст добиваться легко
@alexanderinkognito8379
@alexanderinkognito8379 3 жыл бұрын
Спасибо за доклад. В примере с изменением почтового адреса можно соблюсти изоляцию, инкапсуляцию и быстродействие: ChangeEmail(Email email, List usersWithEmail) а в контролере выбрать не всех пользователей а только тех что имеют такую же почту, оверхед - 1 запрос к БД, но запрос все равно должен быть, лист будет либо пустым либо содержать одного пользователя. Понятно, что не всегда можно провернуть такой фокус.
@МихаилДевятов-ь5г
@МихаилДевятов-ь5г 3 жыл бұрын
В этой ситуации контроллер всё ещё частично "догадывается" об ограничениях, которые существуют в предметной области, поэтому предоставляет все необходимые данные для принятия решения, но зачем-то отдаёт само право принятия решения доменной сущности. При изменении и расширении этих требований необходимо будет актуализировать код как в контроллере, так и в модели. Точно так же можно было бы в метод просто передавать булево значение, указывающее на то, есть ли другой активный пользователь с данным имейлом. В общем, на мой скромный взгляд, это решение, где контроллер лезет в домен, но мы пытаемся обмануть себя и сделать вид, что это по каким-то формальным признакам не так.
@ilya3894
@ilya3894 Жыл бұрын
Очень хороший доклад!
@volumesurup2078
@volumesurup2078 Жыл бұрын
Wow!Killlin!!!
@zond_amond
@zond_amond 2 жыл бұрын
Не думал, что рекомендуется заводить 2 разные сущности кастомера физически.
@KikrAzz
@KikrAzz 11 ай бұрын
Спасибо. Очень ценно. Докладчик - супер!
@ФилиппБондарев
@ФилиппБондарев Жыл бұрын
Можно уточнить с момент - Должны быть Рич модели, которые знают сами что можно делать с ними, но они не должны знать как себя сохранить? То есть, рич на пол-шишечки?!
@serg4568
@serg4568 Жыл бұрын
А еще возникает вопрос, как быть, если какое-то поле сущности lazy-инициализируемо. При обращении к этому полю его значение нужно получить из другого сервиса, например. В этом случае сущность должна еще и знать как себя дозагрузить.
@timur43378
@timur43378 Жыл бұрын
Она должна знать все о себе в терминах предметной области. Сохранение это уже техническая, инфраструктурная деталь и об этом модели знать не надо.
@timur43378
@timur43378 Жыл бұрын
​​@@serg4568нет, как раз тут сущность не может быть на полшишечки дозагруженной, она должна быть целостная. Лучше конкретный пример привести, что за lazy свойство такое может быть у модели. Если значение этого поля находится в другом сервисе, то скорее всего это поле не этой модели, а что-то совершенно другое
@sergafanasiev7956
@sergafanasiev7956 Жыл бұрын
@serg4568, Вот-вот, поэтому кажется что Агрегат должен всегда иметь ссылку на своё Хранилище и дёргать по необходимости
@mikhailsloushch5052
@mikhailsloushch5052 2 жыл бұрын
не вижу проблемы передать в модель репозиторий через интерфейсную ссылку. Да, это говорит о том, что это где то храниться, но где и как - не открывает. Можно хранить по факту хоть в блокноте
@xonicov
@xonicov 2 жыл бұрын
Тоже не понимаю почему автор так против прокидывания интерфейса в модель. Если очень хочется то можно сегрегировать интерфейс. Хотя у автора есть прямо серия статей на эту тему, стоит почитать.
@DenisMakarovPersonal
@DenisMakarovPersonal Жыл бұрын
Проблема начинается когда у тебя в модель 10 разных зависимостей на разные подсистемы добавить нужно чтобыреализовать новые требования, таким образом модель превращается в монстра который делает все
@mikhailsloushch5052
@mikhailsloushch5052 Жыл бұрын
@@DenisMakarovPersonal а какая альтернатива, если для системы важна производительность?
@DenisMakarovPersonal
@DenisMakarovPersonal Жыл бұрын
@@mikhailsloushch5052 альтернативы нет, есть DDD трилема в которой нужно делать выбор, в конкретном примере я бы подумал нужно ли знать Customer уникальный он или нет, может с этим другая сущность модели должна разбираться, или можно в Customer передавать результаты проверки уникальности (флаг/статус) а не саму лямбду с вызовом функции проверки
@sergafanasiev7956
@sergafanasiev7956 Жыл бұрын
Супер, спасибо! Чуть-чуть не уловил на 47 минуте, там где Владимир говорит, что Изоляция доменной области нарушается, если Customer умеет сам себя save в БД. А как тогда будет правильно? Его должен сохранять контроллер? Ну т.е. согласно триллемы DDD (55 минута) выбираем вариант Изоляция+Время ?
@artemadeev7444
@artemadeev7444 4 ай бұрын
Есть вопрос: что делать с рич моделью когда она большая много полей и поддержание инвариантности делает количество методов тоже огромным. Как решать ? Делить модель ? Понятно что это наверно нечастый случай но
@bfdhtfyjhjj
@bfdhtfyjhjj 2 жыл бұрын
Классный доклад!
@IvanenkoStepan
@IvanenkoStepan Жыл бұрын
Жаль, что pluralsight закрыт для России. Хотел там подписаться на курсы автора
@hezymal9109
@hezymal9109 3 жыл бұрын
Супер спасибо
@ДанилПетров-р2с
@ДанилПетров-р2с 2 жыл бұрын
Спасибо за доклад! Поддержу предыдущих комментаторов - отличная подача и разъяснения, очень помогли! ЗЫ. Единственное замечание: было бы хорошо поменьше использовать англицизмы при докладах на русском языке, но я понимаю, что когда практики английского больше, чем русского, это может происходить невольно (читай "на-автомате").
@NoName-wy4pq
@NoName-wy4pq Жыл бұрын
ну это же не доклад 1с. Когда все коммуникации на английском, сложно не использовать понятный для всех сленг
@sergafanasiev7956
@sergafanasiev7956 Жыл бұрын
Глупости! Всё там норм с английским, человек умный и трудолюбивый! Вы лучше поучитесь, как надо работать
@ilmakeyouone
@ilmakeyouone 6 ай бұрын
смотрите, вот заимствованные слова из других языков, которые Вы сами используете: комментатор доклад практика автомат 🫳🏻 ⤵️ ⤵️ 🎤 💢
@wanderingxsx
@wanderingxsx 3 жыл бұрын
Очень холиварный вопрос, тестить без интерфейсов будет так себе. Засунуть всё в модель не очень хорошая идея. Возможно хотя бы сделать модель и интерфейс действий, потом это всё унаследовать в конечную сервис-модель, но опять же это не общепринято. Но искать логику по моделям размазанную, идея не очень хорошая. Триллема бы не появилась, если бы работали отдельно. К тому же CQRS или сам подход разделения чтения и записи сомнителен в озвученном подходе, и прелестно ложится на интерфейсный. Всё таки хорошо, когда есть домен, есть действия домена и объединение это в сущность домена, которая может действия.
@vladislavbondarenko6153
@vladislavbondarenko6153 7 ай бұрын
По тестам у автора есть топ 1 книга в этой области
@MrChelovek68
@MrChelovek68 Жыл бұрын
реально отличный доклад, жаль что уже 2 года прошло(
@vladislavbondarenko6153
@vladislavbondarenko6153 7 ай бұрын
почему жаль?
@MrChelovek68
@MrChelovek68 7 ай бұрын
@@vladislavbondarenko6153 потому что прошло уже 2 года,а я только дополз до ddd
@vladislavbondarenko6153
@vladislavbondarenko6153 7 ай бұрын
@@MrChelovek68 и я))
@MrChelovek68
@MrChelovek68 7 ай бұрын
@@vladislavbondarenko6153 ахахаха, ну штош, велкам ту зэ клаб,бадди)))
@GamDevRus
@GamDevRus Жыл бұрын
что такое рефорт для рефакторинга??
@zerg100500
@zerg100500 3 жыл бұрын
Черт. Нельзя еще раз лайкнуть...
@nikitanickzhukov
@nikitanickzhukov 9 ай бұрын
52:00 Получается циклическая зависимость: CustomerRepository зависит от Customer и наоборот
@Petrovich-27m
@Petrovich-27m Жыл бұрын
круто !
@ryazanov13
@ryazanov13 Жыл бұрын
1:06:30 Как это? Если приложение работает в памяти, это ещё не значит что в нём нет списка кастомеров => репозитория кастомеров хранящего этот список.
@LotmineRu
@LotmineRu Жыл бұрын
Таким образом, мы переходим к главному вопросу DDD - можно ли выкинуть репозитории из домена?
@ryazanov13
@ryazanov13 Жыл бұрын
@@LotmineRu Так вроде как репозиторий и не в домене лежит, только его интерфейс, а сам репозиторий в инфраструктуре. Вопрос был больше в том, почему наличие репозитория обязательно требует БД?
@LotmineRu
@LotmineRu Жыл бұрын
​@@ryazanov13 ссылочная прозрачность же, класть в домен реализацию или интерфейс - принципиальной разницы нет вводя интерфейс, хранилище все равно никуда не пропадает, зависимость все равно есть, хоть мы ее "замели под ковер"
@ryazanov13
@ryazanov13 Жыл бұрын
@@LotmineRu не понял причём тут ссылочная прозрачность. Если вы не используете интерфейс, то: 1) для замены реализации нужно менять домен, что нарушает OCP и DIP 2) невозможно использовать несколько реализаций 3) сложно тестировать (как следствие из п.2 , не можем написать фейковую реализацию) 4) невозможно вынести домен/инфраструктуру в отдельный пакет/гит репозиторий и т.п. И повторюсь вопрос изначально был в том, почему автор решил что без БД не нужен репозиторий. У нас вполне может быть репозиторий который хранит данные в памяти.
@ryazanov13
@ryazanov13 Жыл бұрын
для чего синхронизировать поля модели из одного контекста в другой, а потом ещё постоянно контролировать какие из них можно только читать, если можно просто хранить ID на модель из другого контекста, и всё выше перечисленное можно будет избежать
@владимирсенцов-р1ю
@владимирсенцов-р1ю 9 ай бұрын
Жертвуем быстродействием и получаем замену email за 15 секунд на запрос. И риск out of memory.
@D0nSergio
@D0nSergio 8 ай бұрын
Интересно, в чем проблема использования ICustomerRepo в домен модели, это слабая зависимость в угоду быстродействия. Эти интерфейсы и описывают в слое домена. Также не понял зачем простые вещи типа "Email" делать value object-ом, почему то мне кажется, в книжках это рекомендация , а не правило. Автор шарит, но зачем то перебарщивает с этим "православным DDD" из книжек
@ilmakeyouone
@ilmakeyouone 6 ай бұрын
@@D0nSergioпро valueobject тоже не догоняю. за коим нам стремиться, чтобы все объекты были immutable? может лучше тогда уж на haskell писать?😂
@ilmakeyouone
@ilmakeyouone 6 ай бұрын
@@D0nSergio видимо, автор имеет ввиду, что проблема не в композиционной зависимости (ведь интерфейс от неё итак избавил), а в семантической. то есть, попытка уйти от зависимости одной доменной области от другой на чисто ментальном уровне
@Berill82
@Berill82 Жыл бұрын
52:20 Зачем вытягивать из базы ВСЕГО кастомера вместе с его заказами и другими данными для изменения е-мейла??? Вы представляете какие это тормоза для простой, по сути, операции? А ещё там есть проверка на равенство "вытянутого" кастомера с самим собой. То есть, ещё надо оператор перезагрузить или метод Equals() перезагрузить. Иначе у вас будет только проверка равенства ссылок на два объекта. Короче, много кода для реализации простого функционала + тормоза в работе.
@LotmineRu
@LotmineRu Жыл бұрын
Какие тормоза, ты в онлайн магазе ежедневно делаешь тыщу заказов? А если действительно есть что-то такое, то наверняка оно и смоделировано будет иначе.
@Berill82
@Berill82 Жыл бұрын
@@LotmineRu , да, вы правы. Оно моделируется иначе. Это только в туториалах или при очень маленьких объемах данных вытягивают весь объект со всеми зависимостями чтобы поменять одно поле. В нормальном приложении никто не будет так делать. А если ещё и агрегаты использовать, то там вообще начинается веселье. А вам всего-то надо ОДНО поле поменять и сделать это можно двумя запросами: 1. Проверить есть ли вообще кто-то в базе с таким е-мейлом: db.Customers.Any(c => c.Email == email) 2. Если нет, то Update одного поля по ключу customerId. И все. Бизнес правило уникальности е-мейла обеспечено. Не надо всего пользователя поднимать из базы со всеми его данными, а потом ещё ненужный код писать. Проблему вижу в репозитории, так как чаще всего за ним стоит EF (опять же благодаря туториалам =)) ), а EF не умеет делать Update без предварительного Select. Решается заменой EF на ORM, которая умеет.
@LotmineRu
@LotmineRu Жыл бұрын
​@@Berill82 я имел ввиду, что в одних случаях нормально, когда что-то содержит коллекцию чего-то, когда понятно, что в этой коллекции и не бывает 100500 элементов а этот пример с уникальностью емейла... такой себе, уникальность емела зачастую не такое уж важное бизнес-правило, чтобы его непременно нужно было пихать в домен (но допускаю, в каких-то бизнесах оно может быть реально важным.. но чаще - нет) страшную вещь скажу - можно констрейнт в бд повесить и не париться, никто еще от этого не умирал
@Berill82
@Berill82 Жыл бұрын
@@LotmineRu , даже если оставить в стороне обновление е-мейла. Мне не понятно другое. Это же не эффективно загружать весь объект, чтобы потом произвести над ним какие-то действия. В этом примере у нас не такой уж и большой объект. А ведь потом он начинает обрастать дополнительными свойствам по мере того как бизнес начинает добавлять новый функционал. И вот как тут быть? Количество таблиц, в которых содержится вся связанная с пользователем информация, растет. Загрузка этой информации начинает тормозить, запросы усложняются и т.д. И вот тут я вижу проблему в самом подходе. Нам не нужна, допустим, информация о заказах для обновления персональных данных. Тогда зачем ее загружать?!
@LotmineRu
@LotmineRu Жыл бұрын
@@Berill82 Зачем на информация о заказах для обновления персональных данных? Т.е. почему эти две обязанности живут вместе? Ну и как бы предметная область развивается. Если поначалу что-то было ок, а потом становится как-то не ок - очевидно, нужно перерабатывать модель вслед за развитием предметной области. Короче, я бы сильно не зацикливался на примерах, это ж примеры, они не для работы в проде, а для наглядной демонстрации концепций. Во-вторых, я также же бы сильно не зацикливался на производительности, модель важнее. Вот когда припрет - тогда и надо думать об оптимизации.
@Eugene.g
@Eugene.g 3 жыл бұрын
👍
@vpurazov
@vpurazov Жыл бұрын
Вот сомневаюсь - например вычисление процентов по кредиту -там 100500 интеграций. Вот не место им сущности Заемщик
@ryazanov13
@ryazanov13 Жыл бұрын
36:15 Интересно так получается, т.е. если у вас несколько областей, которые добавляют ордера, то почему они все не используют AddOrder? Ну т.е. в случае с CustomerService мы нарушаем инварианты если в обход CustomerService меняем Customer, а в случае с богатой моделью мы нарушаем инварианты если в обход модели изменяем состояние модели (например через рефлекшны или др. способы доступа к памяти). Это получается больше вопрос договорённости: не используй рефлекшны и др. прямой доступ к памяти/используй только соответствующий сервис. Используй только соответствующий репозиторий и т.д.
@DenisMakarovPersonal
@DenisMakarovPersonal Жыл бұрын
менять поля класса рефлекшеном это конечно сильный пример )))
@ryazanov13
@ryazanov13 Жыл бұрын
@@DenisMakarovPersonal я не сторонник использования рефлекшнов, но кто-то же использует. Это просто пример. Можно сделать sql запрос на update в обход любых моделей, без всяких рефлекшнов, можно создать другую модель которая будет мапиться в ту же таблицу, и никакая инкапсуляция не спасёт, кто запрещает? Ну только лишь соглашения.
@bfg5244
@bfg5244 Жыл бұрын
@@ryazanov13 более того, бизнес вообще может не использовать софт и всё делать на бумажках. Соглашение двух людей - сделка, нескольких людей - договор, государства - закон, нескольких государств - международные конвенции.
@ryazanov13
@ryazanov13 Жыл бұрын
@@bfg5244 смотря какой бизнес. Если у вас бизнес - компьютерная игра или антиспам сервис, не понятно, что вы будете на бумажках делать :)
@ZVA_NOOK
@ZVA_NOOK 2 жыл бұрын
Хм... Программирование - точная наука. Но, сам процесс - творческий. Любой паттерн - превращает искусство программиста в ширпотреб для масс. Это НЕ плохо, но и не надо безоговорочно следовать правилам. Следовать надо контексту задачи и окружения. Тот же customer в 99% случаев принадлежит "третьей стороне" (каталогу пользователей). И, смысл городить цепочку вызовов "потому, что так в паттерне" вместо прямого обращения к каталогу на проверку дублей e-mail? Да и алгоритмы посика/сравнения в службе наверняка поинтереснее (оптимальнее) самописных. Всё больше убеждаюсь, что со времен изобретения ООП, SOA, витрин данных, "наросла" масса модных трактовок/методик суть которых - Думай прежде чем что-то написать и помни о тех, кто будет править код после тебя.
@sevaelunin
@sevaelunin 3 жыл бұрын
Владимир не очень честно поступает, показывая полную модель с передачей репозитория в агрегат =) В такой реализации модель выглядит "грязнее", чем модель без асинхронного поведения. Репозиторий это прикладной сервис и ему нечего делать в доменной модели Честнее было бы передавать доменный сервис как интерфейс IUniqueEmailCheck
@andrewtsvetsih2675
@andrewtsvetsih2675 3 жыл бұрын
Согласен. Для себя мы выбрали другой вариант - использовать делегаты. Подробности можно посмотреть тут kzbin.info/www/bejne/eJWbZKGGgMR-abc Как вам такое решение?
@sevaelunin
@sevaelunin 3 жыл бұрын
@@andrewtsvetsih2675 тоже думал над вариантом с делегатами, но обобщенными. В вашем докладе довольно изящно и выразительно выглядит, спасибо. Может быть асинхронное поведение агрегата через делегаты будет проще "продать" сторонникам анемичной или чистой модели =)
@IgorPchelko
@IgorPchelko 3 жыл бұрын
@@andrewtsvetsih2675 можно еще специализированные интерфесы делать (Interface segregation principle from SOLID). Но это если возможно. Но это не решает дилему описанную Владимиром, функция не получает ссылочной прозрачности.
@andrewtsvetsih2675
@andrewtsvetsih2675 3 жыл бұрын
​@@IgorPchelko Спасибо за ответ. Есть похожий подход в докладе kzbin.info/www/bejne/lZW0g3Spi812p6M Я считаю, что интерфейсам репозиториев (и любой другой инфраструктуры) в модели не место. А вот как их убрать из модели - это вопрос! Делать еще один уровень интерфейсов вокруг инфраструктуры - это просто лишний уровень абстракции. Так как реализация такого интерфейса будет просто прокидывать вызов к инфраструктуре. Это сильно усложнит проект а выигрыш минимален. Уж лучше напрямую инфраструктуру из модели вызывать. На мой взгляд делегаты - это лучшее решение т.к. они не создают новый уровень и изолируют модель от инфраструктуры. Хотя может я вас неверно понял. Можете привести пример как будет реализация с Interface segregation? Спасибо
@sau9703
@sau9703 3 жыл бұрын
@@andrewtsvetsih2675 Просто не воспринимайте репозиторий как обязательную завязку на инфраструктуру и БД , в общем смысле это просто интерфейс доступа к коллекции сущностей , разве доменная модель не имеет права знать о том , какие сущности существуют , если от этого зависит бизнес логика ? Другое дело , что реализация интерфейса уже зависит от инфраструктуры и должна быть размещена за рамками домена.
@MrKelebras
@MrKelebras 10 ай бұрын
жаль что лайк можно поставить только 1 раз))
@alexlo5655
@alexlo5655 Жыл бұрын
если бы я не знал аглийский то ничего бы непонял. на пример, Сущность ето Entity? @Vladimir should you publish this to Pluralsight as another DDD course? Something like "DDD in one hour"?
Алексей Мерсон - Domain-driven design: рецепт для прагматика
58:57
DotNext — конференция для .NET‑разработчиков
Рет қаралды 62 М.
Сергей Баранов - Многоликий DDD
1:06:56
DotNext — конференция для .NET‑разработчиков
Рет қаралды 9 М.
World’s strongest WOMAN vs regular GIRLS
00:56
A4
Рет қаралды 48 МЛН
Молодой боец приземлил легенду!
01:02
МИНУС БАЛЛ
Рет қаралды 1,8 МЛН
How Much Tape To Stop A Lamborghini?
00:15
MrBeast
Рет қаралды 204 МЛН
When u fight over the armrest
00:41
Adam W
Рет қаралды 30 МЛН
Ануар Нурмаканов - Event Sourcing и CQRS на конкретном примере
1:01:21
JPoint, Joker и JUG ru — Java-конференции
Рет қаралды 53 М.
Чистая архитектура и Domain-Driven Design
1:55:56
Владимир Хориков - Принципы юнит-тестирования
1:00:17
Heisenbug — конференция по тестированию
Рет қаралды 8 М.
Владимир Хориков - Validation and DDD
45:01
Конференция ArchDays
Рет қаралды 12 М.
Про Kafka (основы)
49:23
Владимир Богдановский
Рет қаралды 412 М.
Многоликий DDD - Сергей Баранов
1:19:18
Конференция ArchDays
Рет қаралды 19 М.
World’s strongest WOMAN vs regular GIRLS
00:56
A4
Рет қаралды 48 МЛН