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

Ғылым және технология

Ближайшая конференция - DotNext 2024, 10 - 11 сентября, Москва + online
Подробности и билеты: jrg.su/x2GKnA
- -
Владимиру хотелось бы показать самые важные на его взгляд части DDD с примерами на C#. Цель - дать обзор основных вещей из DDD, чтобы зритель смог быстро начать ориентироваться в них и применять на практике.

Пікірлер: 115

  • @user-lb9rz2jg9l
    @user-lb9rz2jg9l Жыл бұрын

    Отличный доклад - редко когда видно, что человек понимает о чем говорит, а значит и может донести мысль до слушателя

  • @slikeiv4477
    @slikeiv44772 жыл бұрын

    шикарный доклад и огромное спасибо Владимиру за талант понятно доносить материал

  • @xonicov
    @xonicov Жыл бұрын

    Владимир, Вы потрясающий докладчик! Давно не слушал настолько крутого доклада!

  • @emotional_stuff
    @emotional_stuff10 күн бұрын

    спасибо за практические примеры, Очень важный момент

  • @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 прототипирование?

  • @Chat-Mayevskogo
    @Chat-Mayevskogo2 жыл бұрын

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

  • @borisnikulitsa695
    @borisnikulitsa695 Жыл бұрын

    Пример по моему подобран удачно. Сразу становится понятно про разделение контекста в случае схожих сущностей (Customer и Product) Спасибо за доклад

  • @namesecondname663
    @namesecondname6633 жыл бұрын

    Супер! Отличный доклад, спасибо.

  • @judexmars4214
    @judexmars42142 ай бұрын

    Интересный подход. Вроде как и много сказанное здесь звучит логично и правильно, но и очень непривычно. Спасибо за доклад

  • @alexanderinkognito8379
    @alexanderinkognito83792 жыл бұрын

    Книга по тестированию супер! рекомендую всем, must read

  • @learning867
    @learning86710 ай бұрын

    56:00 для таких инвариантов придется знание о доменной модели выносить в бд - уникальный индекс на email. И тогда при вставке бд выдаст ошибку, и ее можно будет обработать на доменном уровне. Ни один из описанных в видео способов не явлется рабочим в конкурентной среде. Если два пользователя решили одновременно сменить email на другой одинаковый, то выборка из бд и проверка в памяти потенциально могут у обоих завершиться успешно. И оба вставят в бд один и тот же email. Если вынести проверку на уровень бд, то и код в доменной модели станет проще. Да, можно сказать, что мы переносим проверку инварианиа на инфраструктурный уровень - уровень бд. Но вообще-то бд является отражением наших сущностей в доменной модели. Мы не переносим эту логику в реопозитрий. Мы переносим ее в саму бд - место хранения инфы о нашем домене. Ну и это единственный адекватный рабочий способ. Ну либо можно брать блокировки (или распределеоные блокировки), но вот это уже перенос сохранения инварианта в инфраструктуру

  • @ilmakeyouone

    @ilmakeyouone

    Ай бұрын

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

  • @user-fg6ng7ej6w
    @user-fg6ng7ej6w8 ай бұрын

    очень толковый доклад, спасибо

  • @theeasywaytr4293
    @theeasywaytr4293 Жыл бұрын

    Владимир отличный пример привел! Спасибо за доклад!

  • @ilya3894
    @ilya3894 Жыл бұрын

    Очень хороший доклад!

  • @alekseyshibayev5243
    @alekseyshibayev5243 Жыл бұрын

    Спасибо коллегам из мира java для windows 😊 В пет проекте так и делал, пользуясь С и О принципами солид, не догадываясь про ДДД. Оказывается ДДД расширяет эти принципы. Очень похоже про те штуки, за которые топил Егор Бугаенко. Единственное не согласен, что надо лепить все в один класс. Я бы выделил емеил и статус в отдельную бизнес сущность, и создал класс ответственный за эту сущность и пусть он ее меняет. Книгу записал в todo.

  • @nikolay4362
    @nikolay43626 ай бұрын

    на редкость хорошая лекция

  • @natasha1059
    @natasha1059 Жыл бұрын

    Очень емко, точно, мне все стало понятно, спасибо!

  • @bfdhtfyjhjj
    @bfdhtfyjhjj2 жыл бұрын

    Классный доклад!

  • @user-rh1ty5rx3h
    @user-rh1ty5rx3h7 ай бұрын

    Спасибо, отличный доклад

  • @Berill82
    @Berill82 Жыл бұрын

    33:15 Очень хочется посмотреть, что будет с этой скидкой, если она будет зависеть от чего-то ещё, кроме статуса. И вообще, как можно поместить функцию расчета скидки в объект Статус?! А если от статуса будет ещё что-то зависеть? Тоже сделаем методом в классе Статус?!

  • @alekseykouzmenko9096

    @alekseykouzmenko9096

    28 күн бұрын

    Ответ чуть далее по ходу - там где требуется использовать внешние данные инвариант должен быть неизменяемым.

  • @hezymal9109
    @hezymal91093 жыл бұрын

    Супер спасибо

  • @IvanenkoStepan
    @IvanenkoStepan6 ай бұрын

    Вангую, это видео наберёт больше всего просмотров на канале.

  • @-dubok-
    @-dubok- Жыл бұрын

    Мне кажется, что Владимир на 41:13 приуменьшает роль DDD в проекте. Потому что, на мой взгляд, хотя я только его ещё изучаю, DDD даёт не только единый язык и взаимопонимание, но и в целом раскладывает всё в проекте по полочкам, позволяя легко в нём ориентироваться, легко его поддерживать и вносить изменения. Благодаря DDD избегается превращение проекта в то, что адепты DDD называют «большим комом грязи». А это уже очень полезно и в разы улучшает поддерживаемость кода и экономит по-настоящему огромные ресурсы компании, обеспечивая при этом высокую функциональность, feature-richness продукта. По-моему, DDD в корне меняет всё, он просто переворачивает всю игру с головы на ноги, раскладывая все яйца по своим корзинам. DDD - это must have на любых проектах, связанных с реальным миром, реальными предметными областями и бизнесом в частности. DDD - это инструкция к тому, как правильно писать код, как сделать его чистым и логичным, и никак не меньше. Ну а в целом доклад очень крутой, всё чётко и по полочкам. Особенно понравилось как показано превращение анемичной модели в богатую. Вообще, когда что-то на примерах показывается - это очень хорошо воспринимается всегда. За это прям большое спасибо! А насчёт трилеммы. Лично я не думаю, что использование репозитория в модели - это страшно, потому что репозиторий - это основа любой программы, так как он сохраняет стейт, загружает его, работает с ним, а это - основа основ. Поэтому бояться его и тем более отказываться от него в пользу меньшего быстродействия, по-моему, не разумно. Наоборот, работая с репозиторием в модели, ты видишь, где необходима транзакционная целостность, а значит видишь какие агрегаты ты должен объединить в один, чтобы транзакции по нему проходили нормально. Лично я бы поставил на инкапсуляцию + быстродействие. Смещать логику в контроллеры - это тоже ерунда, так как логика приложения должна быть в модели, и не важно, что эта логика зависит от репозитория. Просто считаем репозиторий частью модели - вот и всё, ведь по сути так оно и есть. Репозиторий хранит данные по бизнесу, а разве это не часть бизнеса? Списки e-mail'ов, адресов - это ведь всё часть бизнеса, это не что-то, связанное с инфраструктурой. Это реальные данные по бизнесу. К тому же репозиторий - это виртуальная сущность, которая изолирует модель от прямой связи с базой. Базу репозитория всегда можно заменить. Это вообще может под капотом быть какой-нибудь API, или частично API, частично БД, частично вообще файловая система или LDAP - всё, что угодно, может внутри содержать репозиторий, и это никак не повлияет на модель, потому что репозиторий всегда выдаёт лишь те данные, которые реально связаны с моделью и являются частью бизнеса.

  • @tedikvredik

    @tedikvredik

    Жыл бұрын

    отличный коммент! Спасибо

  • @sergafanasiev7956

    @sergafanasiev7956

    7 ай бұрын

    Согласен! Отличный коммент! Действительно, что плохого в том, чтобы модель могла делать save, пусть даже в абстрактную БД, чтобы потом, в случае смены БД, можно было через адаптер подменить логику Хранилища! Более того, что если Фабрика, создающая Агрегат, будет также создавать Хранилище и подсовывать его Агрегату на старте?

  • @zscauer
    @zscauer7 ай бұрын

    очень крутой доклад

  • @volumesurup2078
    @volumesurup207811 ай бұрын

    Wow!Killlin!!!

  • @sergafanasiev7956
    @sergafanasiev79567 ай бұрын

    Супер, спасибо! Чуть-чуть не уловил на 47 минуте, там где Владимир говорит, что Изоляция доменной области нарушается, если Customer умеет сам себя save в БД. А как тогда будет правильно? Его должен сохранять контроллер? Ну т.е. согласно триллемы DDD (55 минута) выбираем вариант Изоляция+Время ?

  • @zond_amond
    @zond_amond2 жыл бұрын

    Не думал, что рекомендуется заводить 2 разные сущности кастомера физически.

  • @rtm0076
    @rtm00765 ай бұрын

    Почему вы пропускаете тот момент что CustomerService так же инкапсулирует в себя DataLayer + CacheLayer? Можно приводить примеры более как то приближенные к жизни?

  • @alexanderinkognito8379
    @alexanderinkognito83792 жыл бұрын

    Такой вопрос, разбили на контексты и написали приложение. Через год понимаем что помимо Продаж и Поддержка нужен еще контекст Маркетинг(или любой другой), как быть в такой ситуации? Насколько деление на контексты является гибким решением? А бывает так что "добавьте вот такую маленькую фичу", фича и правда маленькая но не ложится в существующие контексты, а создавать новый может быть дорого для бизнеса.

  • @magicmanam

    @magicmanam

    2 жыл бұрын

    Вероятность того, что "маленькая" фича станет со временем большой > 0. В этом случае поддержка изменённого существующего контекста будет тоже дорога для бизнеса, т.к. будет требовать всё более и более объёмной регрессии при будущих модификациях этого контекста с "маленьким" костылём. Это нужно иметь в виду, ну а поступать так, как считаете нужным. Ведь лучше ошибиться и получить опыт, чем пытаться найти "общий" ответ там, где его нет)

  • @timur43378

    @timur43378

    8 ай бұрын

    Так добавление нового контекста никак не влияет на другие контексты, в этом и есть смысл, чтобы ограничить влияние контекстов. Так что новый контекст добиваться легко

  • @alexanderinkognito8379
    @alexanderinkognito83792 жыл бұрын

    Спасибо за доклад. В примере с изменением почтового адреса можно соблюсти изоляцию, инкапсуляцию и быстродействие: ChangeEmail(Email email, List usersWithEmail) а в контролере выбрать не всех пользователей а только тех что имеют такую же почту, оверхед - 1 запрос к БД, но запрос все равно должен быть, лист будет либо пустым либо содержать одного пользователя. Понятно, что не всегда можно провернуть такой фокус.

  • @user-cd5se7lf5t

    @user-cd5se7lf5t

    2 жыл бұрын

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

  • @IvanenkoStepan
    @IvanenkoStepan Жыл бұрын

    Жаль, что pluralsight закрыт для России. Хотел там подписаться на курсы автора

  • @GamDevRus
    @GamDevRus9 ай бұрын

    что такое рефорт для рефакторинга??

  • @user-dv3bq6bi8g
    @user-dv3bq6bi8g7 ай бұрын

    круто !

  • @wanderingxsx
    @wanderingxsx3 жыл бұрын

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

  • @vladislavbondarenko6153

    @vladislavbondarenko6153

    Ай бұрын

    По тестам у автора есть топ 1 книга в этой области

  • @user-zt2ob3le7e
    @user-zt2ob3le7e9 ай бұрын

    Можно уточнить с момент - Должны быть Рич модели, которые знают сами что можно делать с ними, но они не должны знать как себя сохранить? То есть, рич на пол-шишечки?!

  • @serg4568

    @serg4568

    8 ай бұрын

    А еще возникает вопрос, как быть, если какое-то поле сущности lazy-инициализируемо. При обращении к этому полю его значение нужно получить из другого сервиса, например. В этом случае сущность должна еще и знать как себя дозагрузить.

  • @timur43378

    @timur43378

    8 ай бұрын

    Она должна знать все о себе в терминах предметной области. Сохранение это уже техническая, инфраструктурная деталь и об этом модели знать не надо.

  • @timur43378

    @timur43378

    8 ай бұрын

    ​​@@serg4568нет, как раз тут сущность не может быть на полшишечки дозагруженной, она должна быть целостная. Лучше конкретный пример привести, что за lazy свойство такое может быть у модели. Если значение этого поля находится в другом сервисе, то скорее всего это поле не этой модели, а что-то совершенно другое

  • @sergafanasiev7956

    @sergafanasiev7956

    7 ай бұрын

    @serg4568, Вот-вот, поэтому кажется что Агрегат должен всегда иметь ссылку на своё Хранилище и дёргать по необходимости

  • @mikhailsloushch5052
    @mikhailsloushch5052 Жыл бұрын

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

  • @xonicov

    @xonicov

    Жыл бұрын

    Тоже не понимаю почему автор так против прокидывания интерфейса в модель. Если очень хочется то можно сегрегировать интерфейс. Хотя у автора есть прямо серия статей на эту тему, стоит почитать.

  • @DenisMakarovPersonal

    @DenisMakarovPersonal

    Жыл бұрын

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

  • @mikhailsloushch5052

    @mikhailsloushch5052

    Жыл бұрын

    @@DenisMakarovPersonal а какая альтернатива, если для системы важна производительность?

  • @DenisMakarovPersonal

    @DenisMakarovPersonal

    Жыл бұрын

    @@mikhailsloushch5052 альтернативы нет, есть DDD трилема в которой нужно делать выбор, в конкретном примере я бы подумал нужно ли знать Customer уникальный он или нет, может с этим другая сущность модели должна разбираться, или можно в Customer передавать результаты проверки уникальности (флаг/статус) а не саму лямбду с вызовом функции проверки

  • @sau9703
    @sau97033 жыл бұрын

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

  • @-dubok-

    @-dubok-

    Жыл бұрын

    Сервисная модель полна излишеств и не отражает сущность бизнеса. Глядя на неё ты не понимаешь, для чего она существует. В ней также перемешана логика и инфраструктура. В богатой модели как раз таки всё понятно. Она описывает саму себя. Главное - всегда рисовать её диаграмму.

  • @SergeMSO

    @SergeMSO

    Жыл бұрын

    Аналогичное чувство появилось, только связал с серединой 2000-х. Очередные ребята сделали "открытие". "Я не знаю почему так лучше, но бизнесу нравится"

  • @SergeMSO

    @SergeMSO

    Жыл бұрын

    А, вот это вообще пушка: "вот в таком подходе сделаете за 2 дня, а в старом займёт 2 месяца".

  • @user-qp1fk8tm2v

    @user-qp1fk8tm2v

    Жыл бұрын

    на контексты надо разбивать, про это сказано вначале

  • @zerg100500
    @zerg1005002 жыл бұрын

    Черт. Нельзя еще раз лайкнуть...

  • @Eugene.g
    @Eugene.g3 жыл бұрын

    👍

  • @KikrAzz
    @KikrAzz6 ай бұрын

    Спасибо. Очень ценно. Докладчик - супер!

  • @MrChelovek68
    @MrChelovek688 ай бұрын

    реально отличный доклад, жаль что уже 2 года прошло(

  • @vladislavbondarenko6153

    @vladislavbondarenko6153

    Ай бұрын

    почему жаль?

  • @MrChelovek68

    @MrChelovek68

    Ай бұрын

    @@vladislavbondarenko6153 потому что прошло уже 2 года,а я только дополз до ddd

  • @vladislavbondarenko6153

    @vladislavbondarenko6153

    Ай бұрын

    @@MrChelovek68 и я))

  • @MrChelovek68

    @MrChelovek68

    Ай бұрын

    @@vladislavbondarenko6153 ахахаха, ну штош, велкам ту зэ клаб,бадди)))

  • @user-lp6rp
    @user-lp6rp19 күн бұрын

    Нам бы проблемы трехлетней давности. Печально вспоминать из 2024г.

  • @ryazanov13
    @ryazanov13 Жыл бұрын

    для чего синхронизировать поля модели из одного контекста в другой, а потом ещё постоянно контролировать какие из них можно только читать, если можно просто хранить ID на модель из другого контекста, и всё выше перечисленное можно будет избежать

  • @Nazaro4ka
    @Nazaro4ka9 ай бұрын

    У меня возник вопрос Будет ли богатая доменная модель прототипом так называемого God object, реализация которого не является хорошей практикой?

  • @timur43378

    @timur43378

    8 ай бұрын

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

  • @Nazaro4ka

    @Nazaro4ka

    8 ай бұрын

    @@timur43378, спасибо за исчерпывающий ответ!

  • @ryazanov13
    @ryazanov13 Жыл бұрын

    1:06:30 Как это? Если приложение работает в памяти, это ещё не значит что в нём нет списка кастомеров => репозитория кастомеров хранящего этот список.

  • @LotmineRu

    @LotmineRu

    Жыл бұрын

    Таким образом, мы переходим к главному вопросу DDD - можно ли выкинуть репозитории из домена?

  • @ryazanov13

    @ryazanov13

    Жыл бұрын

    @@LotmineRu Так вроде как репозиторий и не в домене лежит, только его интерфейс, а сам репозиторий в инфраструктуре. Вопрос был больше в том, почему наличие репозитория обязательно требует БД?

  • @LotmineRu

    @LotmineRu

    Жыл бұрын

    ​@@ryazanov13 ссылочная прозрачность же, класть в домен реализацию или интерфейс - принципиальной разницы нет вводя интерфейс, хранилище все равно никуда не пропадает, зависимость все равно есть, хоть мы ее "замели под ковер"

  • @ryazanov13

    @ryazanov13

    Жыл бұрын

    @@LotmineRu не понял причём тут ссылочная прозрачность. Если вы не используете интерфейс, то: 1) для замены реализации нужно менять домен, что нарушает OCP и DIP 2) невозможно использовать несколько реализаций 3) сложно тестировать (как следствие из п.2 , не можем написать фейковую реализацию) 4) невозможно вынести домен/инфраструктуру в отдельный пакет/гит репозиторий и т.п. И повторюсь вопрос изначально был в том, почему автор решил что без БД не нужен репозиторий. У нас вполне может быть репозиторий который хранит данные в памяти.

  • @user-gw6df6ns7e
    @user-gw6df6ns7e3 ай бұрын

    Жертвуем быстродействием и получаем замену email за 15 секунд на запрос. И риск out of memory.

  • @D0nSergio

    @D0nSergio

    2 ай бұрын

    Интересно, в чем проблема использования ICustomerRepo в домен модели, это слабая зависимость в угоду быстродействия. Эти интерфейсы и описывают в слое домена. Также не понял зачем простые вещи типа "Email" делать value object-ом, почему то мне кажется, в книжках это рекомендация , а не правило. Автор шарит, но зачем то перебарщивает с этим "православным DDD" из книжек

  • @ilmakeyouone

    @ilmakeyouone

    Ай бұрын

    @@D0nSergioпро valueobject тоже не догоняю. за коим нам стремиться, чтобы все объекты были immutable? может лучше тогда уж на haskell писать?😂

  • @ilmakeyouone

    @ilmakeyouone

    Ай бұрын

    @@D0nSergio видимо, автор имеет ввиду, что проблема не в композиционной зависимости (ведь интерфейс от неё итак избавил), а в семантической. то есть, попытка уйти от зависимости одной доменной области от другой на чисто ментальном уровне

  • @nikitazhukov7372
    @nikitazhukov73724 ай бұрын

    52:00 Получается циклическая зависимость: CustomerRepository зависит от Customer и наоборот

  • @user-gy3ei7fk8w
    @user-gy3ei7fk8w Жыл бұрын

    Спасибо за доклад! Поддержу предыдущих комментаторов - отличная подача и разъяснения, очень помогли! ЗЫ. Единственное замечание: было бы хорошо поменьше использовать англицизмы при докладах на русском языке, но я понимаю, что когда практики английского больше, чем русского, это может происходить невольно (читай "на-автомате").

  • @NoName-wy4pq

    @NoName-wy4pq

    Жыл бұрын

    ну это же не доклад 1с. Когда все коммуникации на английском, сложно не использовать понятный для всех сленг

  • @sergafanasiev7956

    @sergafanasiev7956

    7 ай бұрын

    Глупости! Всё там норм с английским, человек умный и трудолюбивый! Вы лучше поучитесь, как надо работать

  • @ilmakeyouone

    @ilmakeyouone

    Ай бұрын

    смотрите, вот заимствованные слова из других языков, которые Вы сами используете: комментатор доклад практика автомат 🫳🏻 ⤵️ ⤵️ 🎤 💢

  • @ryazanov13
    @ryazanov13 Жыл бұрын

    58:18 Если мы выберем вариант с инкапсуляцией и интерфейсом, то можно прекрасно всё тестировать без моков. При этом 3 вариант где плохое быстродействие не обеспечит инкапсуляции. Я имею ввиду вариант прокинуть все заказы в кастомера, т.к. ничто нам не мешает прокинуть пустой или неполный массив (и вообще будет не очевидно какой список кидать в метод). Как по мне нормальная реализация 3го варианта (с инкапсуляцией, изоляцией, но плохой скоростью) это запихнуть список кастомеров в другую модель.

  • @sevaelunin
    @sevaelunin3 жыл бұрын

    Владимир не очень честно поступает, показывая полную модель с передачей репозитория в агрегат =) В такой реализации модель выглядит "грязнее", чем модель без асинхронного поведения. Репозиторий это прикладной сервис и ему нечего делать в доменной модели Честнее было бы передавать доменный сервис как интерфейс IUniqueEmailCheck

  • @andrewtsvetsih2675

    @andrewtsvetsih2675

    3 жыл бұрын

    Согласен. Для себя мы выбрали другой вариант - использовать делегаты. Подробности можно посмотреть тут kzread.info/dash/bejne/dJhsldCJe8KxY7g.html Как вам такое решение?

  • @sevaelunin

    @sevaelunin

    3 жыл бұрын

    @@andrewtsvetsih2675 тоже думал над вариантом с делегатами, но обобщенными. В вашем докладе довольно изящно и выразительно выглядит, спасибо. Может быть асинхронное поведение агрегата через делегаты будет проще "продать" сторонникам анемичной или чистой модели =)

  • @IgorPchelko

    @IgorPchelko

    3 жыл бұрын

    @@andrewtsvetsih2675 можно еще специализированные интерфесы делать (Interface segregation principle from SOLID). Но это если возможно. Но это не решает дилему описанную Владимиром, функция не получает ссылочной прозрачности.

  • @andrewtsvetsih2675

    @andrewtsvetsih2675

    3 жыл бұрын

    ​@@IgorPchelko Спасибо за ответ. Есть похожий подход в докладе kzread.info/dash/bejne/kZiFtKOshsupoaQ.html Я считаю, что интерфейсам репозиториев (и любой другой инфраструктуры) в модели не место. А вот как их убрать из модели - это вопрос! Делать еще один уровень интерфейсов вокруг инфраструктуры - это просто лишний уровень абстракции. Так как реализация такого интерфейса будет просто прокидывать вызов к инфраструктуре. Это сильно усложнит проект а выигрыш минимален. Уж лучше напрямую инфраструктуру из модели вызывать. На мой взгляд делегаты - это лучшее решение т.к. они не создают новый уровень и изолируют модель от инфраструктуры. Хотя может я вас неверно понял. Можете привести пример как будет реализация с Interface segregation? Спасибо

  • @sau9703

    @sau9703

    3 жыл бұрын

    @@andrewtsvetsih2675 Просто не воспринимайте репозиторий как обязательную завязку на инфраструктуру и БД , в общем смысле это просто интерфейс доступа к коллекции сущностей , разве доменная модель не имеет права знать о том , какие сущности существуют , если от этого зависит бизнес логика ? Другое дело , что реализация интерфейса уже зависит от инфраструктуры и должна быть размещена за рамками домена.

  • @vpurazov
    @vpurazov Жыл бұрын

    Вот сомневаюсь - например вычисление процентов по кредиту -там 100500 интеграций. Вот не место им сущности Заемщик

  • @fuckptn
    @fuckptn3 ай бұрын

    Для емейла абсолютно не нужен ValueObject, верификация емейла является инкапсулированной логикой самого кастомера, валидация емейла кастомера - это одна процедура, валидация емейла админа или еще какого специфичного эктора - это другая логика, основной принцип - использование простых типов данных настолько насколько это возможно (никто не мешает валидировать при присвоении, кстати точно также как это будет делать класс Email и логика верификации будет в единственном экземпляре, потому что она кастомер-специфична, если есть необходимость проверить на соответствие RFC, это эта часть выносится в модуль "или в провайдер"). Короче ValueObject появляется, когда представление в доменной модели объекта с помощью простых типов невозможно или нецелесообразно (в частности паттерн адаптер), во всех остальных случаях - будет больше проблем из-за желания накодить побольше артефактов и разнести логику, не говоря уже о области видимости такой логики (скажем так если бы опредленное свойство было бы производным от нескольких полей кастомера, а не самодостаточным как в случае с емейл, в общем с точки зрения ООП задолбались бы вы это в отдельный объект отдавать с полноценной инкапсуляцией и нужной областью видимости). С ордером тоже проблемы, поднимаясь из базы получается, что кастомер хранит ордера, а накой их поднимать, если они не нужны и вообще не являеются частью кастомера? Это все равно что поднимать все ордера вместе с курьером который их выполнил, или возможно, которые он выполняет в данный момент??? Таких колекций будет хреналиард и они не нужны. Ну скажете вы давайте лейзи пропертю сделаем, а куда денем транзакционную целостность? И сказки про вторичность БД неуместны, потому что абсолютно все равно откуда их не надо поднимать вместе с кастомером, это я в понятных терминах описываю. Ниже там пример был про метод ChangeEmail(Email email, ....) вопрос а что если потребуется поискать в базе невалидные емейлы (для кастомера), причин - дофига, последствия интеграции с другими системами, банальная эволюция требований к емейлу и т.д. - пишется код обновляющий существующие данные, надо найти всех аффектед. Как мне проинстанциировать емейл с "неправильным" содержимым? Получается перегружаем конструктор и делаем все тоже самое, напрямую передаем стринг, который юзаем внутри емейл. Так накой нам такой емейл VO? Оверкомпликейтед, который загоняет нас туда, откуда DDD должен был вытащить. В нормальном подходе методы кастомера, которые отвечают за поиск не осуществляют валидацию на бизнес правила, а вот методы для изменения будут проверять. И это в данном случае и есть правила поведения самой сущности Customer, и никаким образом оно не делегируется объекту Email. Лучше бы про правило идентичности рассказали, по которому у вас в кастомере Id должен быть, и агрегаты, которые и будут собирать пачки объектов, и у которых уже был бы смысл хранить оредера. У меня например это отдельный слой и фасады, так лучше организован код, но суть таже - это все еще агрегаты. Вот уж сколько мнений столько и реализаций DDD и часто корявых )))

  • @alexlo5655
    @alexlo5655 Жыл бұрын

    если бы я не знал аглийский то ничего бы непонял. на пример, Сущность ето Entity? @Vladimir should you publish this to Pluralsight as another DDD course? Something like "DDD in one hour"?

  • @ryazanov13
    @ryazanov13 Жыл бұрын

    36:15 Интересно так получается, т.е. если у вас несколько областей, которые добавляют ордера, то почему они все не используют AddOrder? Ну т.е. в случае с CustomerService мы нарушаем инварианты если в обход CustomerService меняем Customer, а в случае с богатой моделью мы нарушаем инварианты если в обход модели изменяем состояние модели (например через рефлекшны или др. способы доступа к памяти). Это получается больше вопрос договорённости: не используй рефлекшны и др. прямой доступ к памяти/используй только соответствующий сервис. Используй только соответствующий репозиторий и т.д.

  • @DenisMakarovPersonal

    @DenisMakarovPersonal

    Жыл бұрын

    менять поля класса рефлекшеном это конечно сильный пример )))

  • @ryazanov13

    @ryazanov13

    Жыл бұрын

    @@DenisMakarovPersonal я не сторонник использования рефлекшнов, но кто-то же использует. Это просто пример. Можно сделать sql запрос на update в обход любых моделей, без всяких рефлекшнов, можно создать другую модель которая будет мапиться в ту же таблицу, и никакая инкапсуляция не спасёт, кто запрещает? Ну только лишь соглашения.

  • @bfg5244

    @bfg5244

    Жыл бұрын

    @@ryazanov13 более того, бизнес вообще может не использовать софт и всё делать на бумажках. Соглашение двух людей - сделка, нескольких людей - договор, государства - закон, нескольких государств - международные конвенции.

  • @ryazanov13

    @ryazanov13

    Жыл бұрын

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

  • @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 Зачем на информация о заказах для обновления персональных данных? Т.е. почему эти две обязанности живут вместе? Ну и как бы предметная область развивается. Если поначалу что-то было ок, а потом становится как-то не ок - очевидно, нужно перерабатывать модель вслед за развитием предметной области. Короче, я бы сильно не зацикливался на примерах, это ж примеры, они не для работы в проде, а для наглядной демонстрации концепций. Во-вторых, я также же бы сильно не зацикливался на производительности, модель важнее. Вот когда припрет - тогда и надо думать об оптимизации.

  • @ZVA_NOOK
    @ZVA_NOOK2 жыл бұрын

    Хм... Программирование - точная наука. Но, сам процесс - творческий. Любой паттерн - превращает искусство программиста в ширпотреб для масс. Это НЕ плохо, но и не надо безоговорочно следовать правилам. Следовать надо контексту задачи и окружения. Тот же customer в 99% случаев принадлежит "третьей стороне" (каталогу пользователей). И, смысл городить цепочку вызовов "потому, что так в паттерне" вместо прямого обращения к каталогу на проверку дублей e-mail? Да и алгоритмы посика/сравнения в службе наверняка поинтереснее (оптимальнее) самописных. Всё больше убеждаюсь, что со времен изобретения ООП, SOA, витрин данных, "наросла" масса модных трактовок/методик суть которых - Думай прежде чем что-то написать и помни о тех, кто будет править код после тебя.

  • @MrKelebras
    @MrKelebras4 ай бұрын

    жаль что лайк можно поставить только 1 раз))

Келесі