НЕ ООП ЕДИНЫ! Domain Driven Design на примере ХОЛОДИЛЬНИКА / Tech Lead Борис Беньковский
Вставка
- Опубліковано 10 чер 2024
- Станьте универсальным разработчиком с помощью курса Нетологии «Fullstack-разработчик на Python»: netolo.gy/hsa
По промокоду ITBORODA действует скидка 45% на обучение в Нетологии
Сегодня мы поговорим про Domain Driven Design aka Domain Driven Development aka DDD aka Предметно-ориентированное программирование на примере ХОЛОДИЛЬНИКА! Гость выпуска мой старинный друг и Tech Lead - Борис Беньковский. Боря вырос в маленькой деревне, был помощником комбайнера, а сегодня на примере холодильника рассказывает как работают луковичные архитектуры, что такое доменные модели, агрегаты и всё вот это вот из DDD.
Так что, заваривайте чаинский/кофеинский и погнали, будет полезно! 😉
ДОП. МАТЕРИАЛЫ:
- Боря в Linkedin: / boris-biankouski-006a1866
- Материалы из выпуска: t.me/itbeard/769
- Аудио-версия выпуска: itbeard.mave.digital/ep-166
- Выпуск без рекламы: • [noadv] НЕ ООП ЕДИНЫ! ...
- Станьте спонсором канала:
/ @itbeard
НАВИГАЦИЯ:
0:00 Начало
0:50 Представление
1:55 Детство в деревне
6:29 Интеграция
8:30 Лицей БГУ
13:00 В PHP через комбайнёра
21:45 Армия
30:50 Работа после армии бэкендером
38:40 Про php и Symfony
47:10 DDD на примере холодильника
53:25 Терминология
58:45 Модели
1:26:55 Репозитории
1:35:55 Сервисы
1:39:40 Контексты и модули
1:43:20 Агрегаты
1:48:06 Луковичные архитектуры (onion architecture)
1:59:35 Что почитать
2:01:57 РАНДОМ
2:09:17 КОНКУРС
2:12:58 Послешоу
МОИ КОНТАКТЫ:
- UA-cam: / itbeard
- Telegram: t.me/itbeard
- Instagram: / itbeard
- Twitter: / iamitbeard
- Discord: / discord
- Сайт: itbeard.com
#айтиборода #ityoutubersru #ddd - Наука та технологія
НАВИГАЦИЯ:
0:00 Начало
0:50 Представление
1:55 Детство в деревне
6:29 Интеграция
8:30 Лицей БГУ
13:00 В PHP через комбайнёра
21:45 Армия
30:50 Работа после армии бэкендером
38:40 Про php и Symfony
47:10 DDD на примере холодильника
53:25 Терминология
58:45 Модели
1:26:55 Репозитории
1:35:55 Сервисы
1:39:40 Контексты и модули
1:43:20 Агрегаты
1:48:06 Луковичные архитектуры (onion architecture)
1:59:35 Что почитать
2:01:57 РАНДОМ
2:09:17 КОНКУРС
2:12:58 Послешоу
Ну какое нафиг Symphony?
Symfony, SYMFONYYYYYYYYYYYYYYYYYYYY
@@devracoon да всем похер на пыху)
@@itbeardобидно, но нет, я пхпшник 7 лет, симфони 5 из них, еще с 1 версией работал... В жопу пхп, сейчас на голанг и котлин 👍
A
SSSSSS
S
SSSSSSSS
SSSSSSSSSSSSSSESSIONSSSSSSSSSSSSßßSSSSSSSSßSSSSSSSSSSSßSSSSSSSSSßSßSßßSSSSSSSSßSSSßSSßSSS
SSSßSßSßSßS
S
А Поперечный в Айтишечке оказывается шарит
ахахах, весь выпуск думал, кого же он мне напоминает
Зашёл посмотреть на такой комментарий
Поперечный XL
Пригожин отрастил бороду и тоже начал вникать
Чуть чуть похож реально
Было бы круто, если бы такие вещи обсуждались с доской, на которой можно порисовать свои мысли)))
Так я ДДД. Каждый день делаю запросы в холодильник!
У него чёрный пояс по гастрономическим метафорам
Судя по пузику Лекса, он тоже не отстает
@@smookkee1 самое лучшее пузико на этой планете!
Ты Service)
Спасибо, интеревью интересное, спикер интересный, но объяснение хромает
56:00 про пиццерию пример - есть пиццерия, у неё есть разные "отделы": кухня, продажи, склад - это домены.
Когда ты реализуешь домен кухни, ты должен иметь "общий язык" с поварами, они говорят пицца - ты понимаешь что это тесто с сыром, томатной пастой и далее по списку.
Пицца для продажников - это другое, для них пицца - это готовое кулинарное изделие, в коробке, готовое к транспортировке, соответственно продажи это другой домен и там у Вас свой "общий язык".
DTO нужны чтобы допустим перенести пиццу из домена "кухни" в домен "продаж", скорее всего с участием домена "склада". Со склада Вам нужна коробка, с кухни само изделие, а затем в продажах Вы вешаете цену.
вот вы объяснили лучше, чем спикер за все видео
Вот. Сразу чувствуется структурное мышление
Домен - это вся пиццерия. Отделы - это bounded context.
@@timur43378 bounded context это бухгалтерия, рецепты, табель, меню. Для начала в терминах разберись
Люблю программистов из деревни - умеют простыми и понятными словами объяснять сложные вещи
Это индикатор понимания, причина почему полезно не только учится но и учить.
Всегда забавляет то, как люди поясняют сложную тему на казалось бы простом примере, но из-за простого примера(очевидно не подходящего) становиться всегда ещё только хуже
А все потому что эта сложная тема еле натягивается даже на простой пример. А на реальном сложном бизнесе придется в эти доменные сущности инжектить по 50 сервисов со всеми вытекающими проблемами с производительностью общения с базой.
@@valeravalera6201 поверьте, когда идут реальные примеры, все в разы проще, это в 100 раз проще понять когда у тебя просто микросервисы есть, а не какой-то монолит с одинаковым классами "Холодильник" которые лежат в разных модулях/неймпейсах.
Любая ссылка про ДДД в гугле, намного понятнее это все поясняет, уверен гость понимает о чем говорит, но выбор "Холодильник + Монолит" объективно неудачный.
Открываешь холодильник, а оттуда exception вылетает. Люблю DDD!
Call to a member function getKolbasa() on null
@@vesh95 В голос 🤣🤣🤣
Лекс, классный и позитивный выпуск! Спасибо вашей команде!
Нравятся твои видео, не напряжные и хорошо поставленные, хорошая атмосфера без всякого пафоса.
Всем хорошего просмотра)
Лекс, майка - огонь!)
спасибо!
в тему выпуск! Книгу можно еще почитать - Вернон В. - Реализация методов предметно-ориентированного проектирования
Ее лучше на английском читать, перевод там ужасен
Лекс и Борис, ну это пушка, посмотрел на одном дыхании))
Борис, не задумывался над собственным каналом?
Наверное самый позитивный гость из всех, кто были на этом канале. Ждём ещё Макса True
Ещё был про с# и релокейт в Чехию позитивный гость)
По поводу ответов на рандомные вопросы.
Как сказал Егор Малкевич (с которым есть охрененное интервью на этом канале)
На вопрос, какой язык программирования учить в предстоящем году, я наконец то знаю правильный ответ - английский!
Такое ощущение что когда строил большой проект - мыслил 50/50 моделями как в DDD; Но вот на тесты не обращал внимания совсем :(; Но теперь захотелось больше!); Вы мои герои 💖💖💖
Это вышка! Спасибо за выпуск, я как раз изучаю DDD. Борис очень помог понять простыми словами
Ого! Огромное спасибо!!! Это архиполезный выпуск в разрезе ВЗАИМО понимания конечного заказчика и конечного исполнителя, которые, как зачастую бывает, живут в разных мирах! Класс!!!
2:03:35 S. в single responsible это не про то что один класс\сущность - одна задача. Класс отвечает принципу единой ответственности если есть только одна причина для его изменений.
Именно поэтому кухонный холодильник не может иметь метод взятьИнгридиенты и отремонтировать. Потому что тогда класс придется менять если меняется логика получения ингредиентов или логика ремонта.
"The single-responsibility principle (SRP) is a computer-programming principle that states that every module, class or function in a computer program should have responsibility over a single part of that program's functionality, and it should encapsulate that part." (c) Wiki
Согласен, что "single part of that program's functionality" понятие не очень конкретное - границы part весьма условны, нет единого стандарта.
Принцип помогает определить при проектировании сущности её будущую зону ответственности и при необходимости снижать функциональную "нагрузку".
Я к тому, что принцип желательно использовать уже на этапе проектирования, иначе на этапе изменений могут возникнуть трудности 🙂
собственно Ваш ответ и иллюстрирует озвученную проблему с S - можно бесконечно спорить отвечает ли класс этому принципу, и при этом каждая из сторон спора будет по-своему права. "Одна причина для изменений" согласно теории - правильное определение, только в реальности, применительно к реальному классу написанному без какого-либо DDD и с соблюдением священного SOLIDа это можно трактовать по-разному. Кончается спор на code review как правило на том, что одна из сторон просто понимает, что продуктивнее будет просто перестать тратить время на бесполезный спор, согласиться с собеседником и идти дальше.
@@AlexS-gn9tq алюминь, брат. Постоянно с этим сталкиваюсь. И в плане споров это вообще топ. Самая боль когда приходится доказывать такому же синьёру-сениору что пихать валидацию, нотификацию, сбору объекта, логирование и созание платежа в сервис CreatePayment не есть гуд. Потому что с его точки зрения все эти процессы часть одной бизнес-логики - созания платежа.
По своему опыту заметил что обычно таких вопросов будет меньше если начинать писать сервис с тестов, интефейсов и по принципу минимальной необходимости. То есть, если нужен валидный объект в сервисе то ты можешь либо сразу передать его (или получить) в сервис. И тогда никакой валидации не будет в принципе. Либо писать метод (возможно приватный) который будет собирать этот обьект и не дай бог там будет логика и значит тратишь время на тест и тут же можешь себя отрефлексировать что возможно это ответственность другого сервиса.
@@kinvain Я сейчас как раз на этапе, когда логика лежит в классе сервиса - как вы и описали на примере создания платежа. Я ментально понимаю, что здесь идет перемешивание, но пока это проще поддерживать, чем держать в контроллерах, но вы могли бы привести пример, как это концептуально должно быть?
Например, сейчас это так
PaymentService {
create(creatorId, amount):Payment {
this->transaction->start();
user = this->userStore->getExistent(creatorId)
this->validator->validate(form = new CreatePaymentForm(creatorId, amount))
payment = Payment::new(form->creatorId, form->amount, user->id);
this->paymentStore->save(payment)
this->logger->createPayment(payment)
this->notification->notifyCreatePayment(payment)
this->transaction->end();
return payment;
}
}
Логирование и нотификация должны срабатывать через события? Как это разносить.
В данном случае, store - он просто сохраняет в бд модель activeRecord.
@@artemvolt4600 чисто интуитивно я бы предложил следующее
PaymentService::create получает только те данные, которые нужны для созднаия платежа. А именно не creatorID и amount, а сразу объект типа Payment. И объект этот сразу должен быть валидным. То есть вы сначала собираете форму, в контроллере, например, валидируете её, создаёте объект платежа и дальше передаёте его в сервис создания. Выигрыш будет в том что когда вы захотите создавать платежи не только через web-страницу, но ещё и через API, а потом ещё напишете консольную команду, то единственное что будет отличаться - как собираются объекты Payment. Создание же будет всегда одинаковое PaymentService::create()
Сделать интерфейс PaymentCreator с одним методом - create(Payment) и реализовать его для 1) непосредственно сервис создания платежа 2) логирование 3) нотификация. Дальше вы можете сделать стэк из этих сервисов (паттерн Декоратор) и каждый сервис будет заниматься только своим и вызывать следующий сервис. Например, PaymentCreateLoggerService будет логировать начало обработки, вызывать сервис создания, логировать результа (например, если было брошено исключение). Но логирование это вообще отдельная боль... Особенно когда приходится раскуривать логи и искать нужное.
Нотификацию я бы предложил сделать через событие. PaymentService сохраняет платёж и делает какой-нибудь dispatch(new PaymentCreated($payment)). И добавить в систему слушатели этого сыбития для желаемого поведения.
Я понимаю что это больше псевдо-код, но предложил бы делать конекретные сервисы. PaymentService - не понятно что он будет делать. Созадавать? Обноволять? Удалять? PaymentDeleteService - сразу понятно. И если кто-то захочете добавить в него метод по обновлению платежа то как минимум задумается.
Моя идея в том что бы сервисы работали только с бизнес-объектами. Payment, к примеру, это бизнес-объект. А вот форма - нет. Потому что сегодня вы используете Symfony, а завтра решите переехать на Laravel реквесты. Такого, конечно, не будет, но смысл в том что бы вы могли написать свервис не думая о фреймворке и базе,
О, Поперечный стал хорошо питаться.
Аааааа, Алексей, что ты делаешь?!!!! :)
Последнее время каждый новый гость, это просто праздник для сердца и ушей!
Столько дел в воскресенье не переделаю из за твоего выпуска :)
Спасибо огромное!!!
1:08:55. Gherkin, это язык. А cucumber это фреймворк который использует этот язык
Интересно! Здесь суть концепции даже не в ПО, а в организации работы с заказчиком и бизнесом...
Так в разработке ПО большая доля работы заключается в правильной комминикации с заказчиком. DDD просто упрощает жизнь разработчикам на больших длительных проектах с изменяющимися условиями. Для стартапов очень хорошо подходит.
Я из Mobile разработки, мне было очень интересно послушать! В реальности TDD один раз за 8 лет использовали. Тогда давно не понял, а это прям тема. Спасибо за выпуск!
Рад что в РБ есть бурления на тему DDD, я тоже из РБ и тоже интересуюсь этой темой, было бы неплохо замутить какое нить комьюнити )
Человек целый час рассказывает про 1С и почему-то называет его DDD
Тоже ловил себя на - да он же про 1с рассказывает :)
вообще не 1С. до 1С надо еще кучу абстракций сделать. и понять, что продукт не лажит в домене холодильника, а лежит в отдельном домене остатков по местам хранения. И нет у домена метода или контекста - взять продукт, или ремонт, а есть два домена `взять продукты из холодильника`, `ремонт холодильника`
Офигенный гость!! Очень приятно слушать
НУ наконец то! Что-то годное в плане архитектур! А то надоели эти все ваши ООП и т.д
Лучше видео по ддд что я видел в жизни. Респектище гостю и автору
Как раз на новом проекте столкнулся с ДДД, сейчас в процессе изучения этого подхода, видос вышел прям в тему и вовремя для меня) спасибо!
Какой ламповый и трушный гость, прям вспомнил молодость )
К вопросу "Зачем нужен сервис, почему бы сразу с контроллера не управлять моделью?". Точек входа для выполнения одного и того же действия может быть несколько. Это может быть HTTP запрос, крон задача или ивент на который подписано приложение. Здесь очень важно, чтобы все эти точки входа оперировали моделью одинаково. То есть они должны вызывать один и тот же сервис, часто ещё применяют термин "use case". Отсюда получается, что задача контроллера и слушателя, который подписан на ивент, это преобразовать входящие параметры в параметры сервиса и вызвать его. Так сохраняется общая логика оперирования моделью. Именно по этому, такие сервисы ещё называют операционными и они размещаются в операционном слое (Application layer).
Досмотрел до этой точки ua-cam.com/video/rkQ3-T82pkU/v-deo.html , главную ответственность сервиса упомянули.
Лекс, проведи, пожалуйста, интервью с экспертами в ДДД. Парень молодец, но он совсем не эксперт в данной теме. Из экспертов, например, Женя Пешков, Влад Хориков, Влад Хононов и т.д.
Согласен. Борис совсем не про DDD
Влад Хориков норм, смотрел его курс по DDD на pluralsight
Есть ещё Максим Аршинов
Зачем нужен сервис в DDD: сервис нужен для того чтобы 'спаять' два и более агрегата в одну транзакцию. Например, агрегатСклад.вывезти(уголь, 3тонны) и агрегатСчетПользователя.списать(КоммунальныеКслуги, 3 тонны * 1000руб/за тонну)
И вот эти две операции должны быть в транзакции. Иначе консистентность данных в базе нарушится.
Но по хорошему два агрегата обновлять два агрегата в одном сервиса эта идея уже с запашком. Так как в первую очередь она не масштабируема, сложно переносима между между типами баз данных, например на реляционной базе данных этот пример будет работать, а в MongoDB уже его придётся переписывать, так как там нет транзакций между коллекциями документов. Вопрос как же быть в таком случае. Нужно определиться с какие у нас есть возможности баз данных, вот например, в MongoDB всё операции модификации атомарны на уровне документа. В реляционках есть транзакции. Теперь проводим черту между ними. Черта проходит ровненько через агрегат. Единственное что мы можем гарантировать для того чтобы система была консистента и масштабируема в одно и тоже время, так это атомарность агрегата на уровне апликешен логики. И тогда получается сервис как бы становится антипаттерном в данном случае. То есть проще как сказано выше просто из фабрики или репозитория дёрнуть агрегатСклад.вывезти() и сохранить агрегат в базу через репозиторий: репозиторийСклад.сохранить(агрегат склад). В методе сохранить будет конкретная имплементация под базу данных в MongoDB документ атомарен, а в SQL нужно будет создать транзакцию, если потребуется модифицировать записи из нескольких таблиц.
В данном кейсе мы как пока решили ровно половину задачи выше касательно склада, назовем её левой ногой). Теперь нам нужно что-то решить с правой ногой то есть со списывание денег со счета пользователя. Пока без деталей применяем тот же подход что и для склада, ровно точно также. То есть у нас появляется правая нога. Обе эти ноги по отдельности они абсолютно масштабируемы, не зависисмы ни от базы данных, ни от фрейворков, чистая бизнес логика, которую можно и в браузере на JS запустить с in memory базой и на Lambda выполнить с бесконечным масштабированием, и протестировать, геркен тесты написать. Теперь есть выбор, можно раскидать эту логику в микросервисы, наносервисы, или оставить в монолите без изменения бизнес логики.
Теперь остаётся самый важный этап как прикрутить две ноги к телу. Тут есть несколько вариантов, как по мне так мне ни один не нравится. Пример напишу в следующем коменте:
Варианты связки агрегатов, есть условие система должна быть масштабируема, но при этом есть другое условие, что атомарность мы гарантируем на уровне агрегата. В этом случае нам точно не подходят транзакции SQL, так как это привязка к типу базы, а так же это сразу блокирует масштабируемость. Нам не подходят по тойже причине распределеннные транзакции, то есть 2-3 фазные комиты.
Единственный вариант на текущий момент, который можно прикрутить с довольно высокой степенью сложности реализации, так это асинхронное взаимодействие, тот самый event-driven development. Реализация вроде как проста, обычно виду два варианта, первый: пуляем ивенты в момент сохранения агрегата в базу или в очередь ивентов, а с другой стороны их обрабатываем.
При такой асинхронной работе обычно нужно решать подзадачу, которая звучит так: "если уголь со склада вывезли (кинули ивент), но денег на счёте пользователя не хватило для оплаты, то верните (кинули ивент) пожалуйста уголь на склад". (То что в кавычках это и есть тот самый ubiquitous language, мы уже на нем общаемся если что 😀). Можно перефразировать: "отложите на складе 3 тонны угля для пользователя и когда пройдет оплата, то вывезите уголь со склада для пользователя." Вы поняли что у нас появились пара новых слов в нашем глобальном языке для агрегата склад: "отложить" и "вернуть". Как вы выберете будет зависеть от вашего бизнеса и требований.
Теперь получается задача решена, но сложность системы повышена раза в 3. За счёт асинхронных компенсирующих операций.
В этом примере есть на самом деле очень низкоуровневая проблема с самим процессом кидания ивента. Что если агрегат сохранился в базу, но сообщение не отправилось в очередь так как не было связи. Ну это уже отдельная тема.
Related to SOLID and single responsibility. Robert Martin in book "Clean Architecture" specifying that this principle relies to single actor, doesn't tell that a class shall be responsible for single action or thing to do, but relies to reason why you have to change this class. I guess a good example refrigerator, two models for two actors, cook and mechanic.
Несколько месяцев назад начал погружаться в DDD. Как же знакомы все эти чувства когда впервые написал модель с поведением!
Лекс, привет! Очень классный выпуск). Как тебе идея в следующий раз принести планшет или ноут со стилусом, чтобы гость рисовал схемки или схематично писал код для большего понимания и удержания в голове всех мелочей? И вывести все это где-нибудь на экран.
Ку! Идея гуд, думали доску поставить. Но! Монтаж тогда будет совсем не очень, плюс ребята, которые в аудио слушают очень расстроится, а таких много.
Так что для старта пойдет, а дальше уже можно искать целенаправленно курсы😊
Скажите, Борис, а где можно ознакомиться с примерами вашего кода, в котором применен DDD, не обязательно реальный, вполне сгодится чтото вроде пиццерии с холодильниками.
Классный и такой позитивный гость! Интересно про пиццу рассказывает.
Ооо, это залет. Scott Wlaschin - Domain Modeling Made Functional - есть DDD в мире функциональщины.
DDD, как я понимаю, не обязательно про ООП. Стратегическая составляющая вообще про бизнес, аналитику и т.д. а тактические паттерны ничего не мешает и в процедурном стиле реализовать (к примеру)
И какого же размера модели в DDD, в сколько хоть нибудь сложном проекте? Rich Domain Model очень сложно поддерживать, имхо.
Весело было :) Классное интервью! Отличный собеседник!
Лекс, привет! Сложно кратко описать словами, как мне нравятся твои интервью. Сколько уже посмотрел, и ни одного неинтересного собеседника встретил. Особо радует твой простой и свойский, "без понтов", подход ко всему.
Лично я сейчас занят изменением своих подходов к работе, и твои видео о DDD в частности и о новых технологиях вцелом очень помогают мне понять, где мои рассуждения верны, а где нет. Особо приятно замечать тот же, что и у самого себя, блеск в глазах собеседников, когда они рассказывают о своих первых шагах в IT. Удивительно, мой путь и путь твоих гостей во многом похожи.
В общем, так держать!
Спасибо и удачи!))
Davay Davay Deploy
Вот это контент подъехал! то что нужно!
Пушка. Соскучился по твоим интервью, и тема как раз актуальная. У меня сейчас процесс трансформации в DDD как раз :D
чувак реально любит пиццу
Похоже на воплощение Закона Конвея: "Организации проектируют системы, которые копируют структуру коммуникаций в этой организации."
Хорошо. Это работает с 1 доменом. Допустим, с теми-же лифтами. Что делать, если доменов много и модель лифта необходима в 5 вариациях?
Если я сделаю 1 модель для 5 доменов, то она будет устрашающе огромной. Но необходимы данные для лифта всех пяти доменов. Какой может быть стратегия построения моделей/классов в таком случае?
Например (наброски):
1. Доставка (комплектация запчастей, квалификация персонала, который допущен к работам);
2. Монтаж/демонтаж (конфигурация места установки, совместимая с лифтом, дополнительные работы по подготовке к лифту);
3. Установка ПО;
4. Сигнализация планового тех обслуживания, система охраны, health check;
5. Система камер видеонаблюдения за лифтом.
Супер! Это просто топ! Я долго не мог въехать в DDD, а этот парень так просто и интересно об этом рассказал, разложил по полочкам!
Как по мне, один из самых полезных роликов на канале! Давай ещё в таком же духе!
добрый день, скажите плиз а про какие платные видосы из космоса говорит автор упоминая совершенный код? 1:58:58? заранее спасибо
Шикарное интервью. Я прям чувствую как прокачиваюсь.
спасибо за видео ребят, один вопрос.
1:41:01 тут получается что все равно у нас будет достаточное количество логики в сервисах, немного размазываем логику по слоям.
нет ли способов это запихнуть в модели? хз правда в какую в вашем примере, cookRefrigerator или cleanRefrigerator. мб базовый Refrigerator для таких вещей создавать?
> тут получается что все равно у нас будет достаточное количество логики в сервисах
Все верно заметили. Да, я ошибся в том моменте, и чуть позже (в следующих фразах) постарался исправиться.
Из RepairingService нужно вызывать ровно одну строку (без всяких дополнительных проверок - считайте нет логики) `KitchenService->cleanRefrigerator(Identity $id)`.
Таким образом мы оказываемся в модуле кухни. Дальше уже в модуле кухни идем по стандартному пути (в зависимости от бизнеса) загружаем модельку (уже кухонную) и вызываем у этой модельки метод с бизнес логикой
> мб базовый Refrigerator для таких вещей создавать?
Если речь про abstract class то не стоит. Это нарушит разделение Bounded Context.
@@Biankouski Насколько ошибочно делать в модели холодильника вызов модели сыра? Условно "получить сыр, который находится в этом холодильнике".
@@hysapod Спросите у Бизнес Овнера. ДДД это про "записать код как в голове у людей, кто платит вам за этот код". Если в каком-то бизнес процессе нужно "получить сыр, который находится в этом холодильнике" - значит нужно получить сыр, который находится в этом холодильнике
@@hysapod крайне ошибочно. у модели (домена) холодильник не должно быть методов.
в правильной вселенной:
домен холодильник имеет свойства: режимы охлаждения, объем загрузки.
домен сыр(продукт) имеет свойство объем упаковки
домен остатков в холодильнике имеет свойства: ссылка на домен холодильник, ссылка на домен продукт, количество занятого объема, количество упаковок продукта
домен действия `взять продукт из холодильника` имеет свойства: ссылка на домен холодильника, ссылка на домен продукта, количество упаковок продукта
поддерживаю идею приходить в универы послушать лекции! вот это реально было бы круть! хотя бы пусть бы онлайн трансляции сделали, можно платно. огонь тема!
Уже года как 2 есть трансляции
Спасибо за видео!
Будет ли видео о Salesforce? Довольно узкое направление, но мне кажется было бы интересно
Когда-то точно будет, раз 1с был) и сап ещё надо бы..
@@itbeard SAP koniecznie! :)
@@itbeard дааа Salesforce надо! говорят в Буларуси это самые "зажравшиеся" аутсорсеры, которые легко делают 3х-5х от среднего с девбай по стажу.
2:12:58 я знал что будет полезным до самого конца досмотреть :)
Борька красава!!! Привет из Минска!)
Ох, все на самом деле куда сложнее, чем тут рассказывается))
А знаете, почему канал называется АйТиБорода? Не каждый догадается, но я готов прийти на помощь всем интересующимся! Итак, во-первых, канал об информационных технологиях. А во-вторых, у ведущего есть вполне заметная борода! Всё гениальное просто! Главное быть любопытным, наблюдательным и верить в себя!
пора бы переименовывать канал в АйТиПузико
Супер интересно, Спасибо за интервью
01:32:35 не согласен с определением Unit Of Work, тут нам чувак рассказывает про кэш) Идея Unit Of Work заключается в том, что когда мы хотим использовать 2 и более репозитория для выполненения одной задачи - они будутиспользовать один контекст подключения к бд, или же конкретные типы в generic репозиториях.
Берг Джонсон, Деоган, Савано «Безопасно by design» - все основные тезисы применимости DDD, но через призму безопасности кода.
Полностью согласен с тем что тут обсуждаете по DDD)
Инварианты и программирование по контракту пришли от Бертрана Майера
Bounded Coxtext DDD = SRP Дяди Боба
Рано или поздно начинаешь замечать где и какие принципы заложены)
Интересный дискус, спасибо!
По ТДД есть мысль, что юниты будут выходить на сцену на конечных стадиях разработки сценариев. Так сказать для "шлифовки". А начальные ТДД должны начинаться с интеграционных, получается. Где более одного сервиса-сущности-модели-класса-юнита, захватывая и "инициализацию холодильника" и "выдачу ингредиентов". Таким образом на старте у нас тесты совсем не SRP, но потом "расслаиваются" 🤔
Прекрасное интервью! Мне очень понравилось, как Борис рассказал про DDD.
Но не могу согласиться с тем, что 15 лет в разработке - это очень много... Всё, что мы используем в разработке сейчас (2021), придумано в 1960х: процедурное, функциональное, ООП, юнит-тестирование и ТДД - придумано и опробовано тогда.
Полностью согласен
Не надо все грести под одну гребёнку, ТДД гораздо позже появился
в 2003 DDD примерно появился и TDD примерно тогда же.
@@bellmoon2754 "Автор" ТДД Кент Бек сам писал, что он переоткрыл эту идею, а не изобрёл её заново. И он ссылается на идею с перфокартами, которая описывает процесс ТДД.
@@ivan_lebedev DDD - это чистое объектно-ориентированное программирование. В нём новым оказывается позабытое старое, когда в 60х программисты знали предметную область и писали программы от неё отталкиваясь. В современном мире программисты абстрактные - они могут запрограммировать всё, но мало в каких предметных областях разбираются. И DDD напоминает, что вообще-то мы моделируем реальный мир и его конкретную часть, используя ООП.
Говорим Беларусь, подразумеваем холодильники, говорим холодильники, подразумеваем Беларусь. Никак не могу избавиться от этой ассоциации.
Очень крутой гость! Читал 45 татуировок менеджера, и надеюсь что будущему владельцу этой книги она очень понравится и поможет развиться :)
Борис, а можете подсказать? Интернет магазин, продажа услуг. У услуг есть описания-статьи, категории, хеш-тэги. Хеш-тэги считать value object-ом или все-таки entity?
Без задачи (цели\бизнеса) сложно сказать. Если задача - это редактировать теги в админке и навешивать по категориям\статьям, то Entity. Все всегда зависит от BoundedContext и решаемой бизнесовой задачи
*_Надеюсь доживу до того дня, когда увижу в названии нового видоса "Язык ассемблера....."._*
*_Ну и по классике вопрос: -Айтиборода, где ассемблер?_* 😂
Всем очень рекомендую так же посмотреть вот это видео про DDD
Объясняют очень доходчиво.
ua-cam.com/video/CR9mLGN9jh0/v-deo.html
Рассказал про 1с и предметно-ориентированное программирование)
На все 100% согласен с утверждением "У меня было программирование до DDD и после". Я всем знакомым говорю так: "Я как разработчик до DDD и после это два разных разработчика". Эти принципы кардинально поменяли мой взгляд на программирование.
Правда - ДДД непонятно, но очень интересно)) спасиб за выпуск!
респект за PHP
Обычно под моделью в ддд понимают не класс бизнес объекта, а модель предметной области (та самая имплементация домена).
Крайне рекомендую книгу Вон Вернона
Мне 36 лет я инженер-конструктор на 1:22:00 я подумал "да ну нахрен, я пошел" но все же досмотрел! Правда у меня есть образование программиста, но в 2007-2011 году у меня с этим не задалось! Спасибо за видосы
Борис немного напутал с unit of work (UoW), от того он и сказал что "не знаю почему его так назвали"
UoW отвечает за то чтобы изменения сохранялись атомарно, от того он так и называется
а то о чём говорил Борис (холодильники с одним id будут одним и тем-же холодильником) -- это Identity map
Спасибо!
оч крутой ролик, но рекомендую промотать половину)
Борода, спасибо за видео. Теперь смогу с легкостью Эванса дочитать ) Не хватало общего понимания без кучи деталей, из которых и состоит книга. level up )
А еще придется рассказать команде, что у нас личинка DDD, но никак не DDD )
На мой взгляд, можно читать только bounded context. Сам Эванс через цать лет после первой книги сказал, что это ключевая идея. И если писать вторую редакцию, то именно это будет центральной частью.
@@evgenyamorozov И Вон Вернон написал книгу именно с учетом этих мыслей)
Привет! У тебя очень крутые интервью! Очень прошу, может найдешь на интервью человека, который занимается VR? Мне кажется очень интересное направление, многим зайдёт
Плюсую, тоже было бы очень интересно послушать)
Народ, очень важный вопрос. Есть смысл изучать программирование, если я в принципе понимаю теорию и понимаю будущую логику( которую предстоит написать) , но не могу ничего написать. начал изучать программирования 2 месяца назад и пока очень тяжело писать код ( хотя задачки очень детские и простые). Я зык C#. С математикой очень туго у меня.
Смысл, конечно есть, но в долгую имхо ветка Product Owner -> Product Manager в сочетании с английским уровня от C1 намного более перспективна.
1:23:00 может дальше будет объясняться. По идее сервис нужен для того, чтобы не привязываться к инфраструктуре. То есть может быть веб контроллер (с гетом), консоль контроллер (с параметрами) и дальше уже на что фантазии хватит
Непонятно. в случае ремонта холодильника нужно вызвать на уровне контроллера пустойХолодильник = кухонныйСервис.очистиХолодильник(), затем сервисРемонта.произведиРемонт(пустойХолодильник). Получается, что контроллер должен знать что перед ремонтом его нужно очистить, а это разве не часть бизнес-логики?
Верно подмечено что DDD это не "правила", а "пожелания".
Помогал знакомому переписывать MVP`шку на новый рельсы - и подсунул ему легкий уровень DDD...
Ему было крайне тяжело, всегда хотелось писать сразу в контроллере, но я его тормозил и заставлял все расписывать по доменам, агрегаторам, моделям и т.д.
Времени было заложено на "реврайт" 4 месяца, сроки из-за сложности первичного входа растянулись до 5 месяцев.
И через неделю после старта новой версии, заказчик прибежал с новой идеей - сколько было счастья в его голосе, когда он рассказывал что в MVP ему пришлось бы треть кода переписывать, а тут сделал новый домен, сформировал агрегатор и настроил роуты - готово. При этом 99.99[9]% гарантии что ничего ранее написанного не сломалось.
----
Полностью согласен с Борисом - главное начать, будет тяжело, будет "ломать" писать каждую новую "фишку" в пяти-семи местах, вместо одного куска кода в контроллере - зато потом начнешь пожимать плоды своих трудов.
===
Теперь дам ему ссылочку на данное видео - а то ведь даже не знает что это было DDD (хоть и маленькое, но все же) 😀
Александр, а вы могли бы привести пример домена? Например, как ваш колета сделал новый домен, сформировал агрегат?
Может от себя что-нибудь посоветуете, с чего начать для изучения этой темы?
История со стеклянной дверью и кофе очень знакома))
Спасибо! Ещё один случай, когда не подойдёт. Если сайдэффект должен быть вызван до оеончания бизнеслогики. Например сохранять статус операции.
Здорово.
DDD очень сладко звучит, но я для себя так до конца и не понял как происходит синхронизация работы с базой? (в особенности когда много серверов, юзеров и т.д., ведь модель - это по сути InMemory объект, который зачастую имеет очень много зависимостей, даже на очень простых бизнес моделях)
Можно конечно запилить exclusive lock, но в таком случае с перфомансом можно прощаться на веки (даже для небольших моделей, про средние и выше - промолчим).
Да и не очень понятно как это всё ложиться на REST API (где мы фокусируемся не на бизнесе модели, а на ресурсах, читай данных).
Очень интересен DDD, очень ждал ответа на эти вопросы, но не дождался (как и во многих других выступлениях про DDD)
> который зачастую имеет очень много зависимостей, даже на очень простых бизнес моделях)
скорее всего у вас нарушается разделение Bounded Context. "зачастую" должно быть, что один агрегат (энтити с зависимостями другими энтитями) для одной задачи. Да, бывает что какая-то лишняя зависимость читается из БД, и при этом в бизнес логике на конкретном запросе не участвует (но и вызов в БД на сохранение не идет благодаря UnitOfWork), но единицы, а не "зачастую".
> Можно конечно запилить exclusive lock
То-ли я не понял вашу проблему, то-ли вы все проблемы смешали в кучу. Плюсы\минусы работы с транзакциями (и их типами) не отличаются от классической слоеной архитектуры. DDD это про то, как держать сложную бизнеслогику чистой (и от того понятной), в БД вроде как сложностей не добавляется.
> Да и не очень понятно как это всё ложиться на REST API (где мы фокусируемся не на бизнесе модели, а на ресурсах, читай данных).
1. Если ваше API отлично ложится на RESTful (бекенд для SinglePageApplication админки) то скорее всего логики там и нет. Чекнул ACL да сохранил. Вам не нужен DDD.
2. Если ваше API маскируется под REST, при этом, например, за `PATCH /order/25 {orderStatus:processed}` скрывается туча логики, типо
- заказ был в состоянии "в корзине",
- теперь прилетело состояние "процессед"
- значит это пользователь нажал кнопку "checkout" на корзине,
- и т.д.
то я могу предложить 3 опции (не зная всей вашей доменной области это будут "так-себе" советы, но попробую, в порядке приоритета):
- для простых (crud) задач оставить RESTful и без ДДД, для задач "посложнее" обычный REST `POST /order/25/process` + DDD логика
- вам не нужен RESTful вообще. Все технологии (и ДДД и Rest и PHP и Java) должны использоваться для упрощения жизни. Не упрощает - выбрасывайте.
- добавлять какую-то прослойку\роутер маппинга RESTful запроса на ресурс на бизнес сервис. Условно пример выше " если пришел PATH с полем orderStatus значит CheckoutService->processOrder(25)"
- RESTful бизнес моделей это "и есть ваш домен". Принять это как факт, и .. тогда вызывать сервисы вроде "OrderCrudService->patch(25)" ...
выглядит, как первая опция самая адекватная :)
@@Biankouski спасибо большое, по REST API согласен, скорее его нужно использовать для внешних интеграций, в дополнение к DDD. По поводу работы с базой я имел ввиду следующее: вот есть холодильник, чтобы забрать продукт нужно чтобы его количество было больше нуля. Но мы ведь работаем со снэпшотом холодильника в какой то момент времени и к моменту сохранения его состояния в базу - кто то другой его уже проапдэйтит (забрав все продукты) и наша операция сохранения упадёт (если написана верно). Как обычно подобные кейсы хэндляться?
@@sergeymachel2278 по моему это головная боль менеджера модели, а не самой модели. Менеджер модели маппит данные из БД на модель. Пока вы что-то со своей моделью делали, кто-то изменил состояние данных в БД, теперь, перед обновлением этой записи, ModelManager должен об этом позаботится.
@@Zlobusz Окей, мы взяли снэпшот холодильника, отобразили на юае. Юзер видит что нужные ему продукты в наличие, накидывает рецепт, сабмитает - и получает обратно "сори, на самом деле ваши продукту уже утащили". Ведь наш ModelManager будет заботиться о синхронизации перед непосредственным сохранением в базу (когда юзер уже сделал много стэпов). Это классический кейс конкуренции за общий ресурс (в нашем случае холодильник). Единственный выход что я вижу - это временное "бронирование" продукта, т.е. при любом обновлении модели (которое могут обновить другие клиенты) нужно делать колл в базу и лочить какой-то ресурс на определённый промежуток времени.
Я вот всё хочу попробовать в продакшене, но боюсь что на нашем энтэрпрайзе это рано или поздно вылезет боком (с ростом сложности модели(ей) и агрегаций)
Посмотрел, чтобы подтвердить свое мнение. DDD - отличный подход, что-бы быть ближе к бизнесу. Формировать архитектуру и сущности проекта в соответствие с требованиями/задачами бизнеса. Работаю по DDD последние пару лет. Рекомендую попробовать, тем кто еще не использует
Красавчик! Интервью гонь!
Можно упороться еще дальше и отказаться вобще от сервисов и заюзать CQRS, где команды будут представлять конкретный use-case и больше не будет необходимости в сервисе-проксе к репозиторию.
Я не могу отделаться от мысли, что всё это сводится к идеям из Grokking Simplicity, точнее к трём вещам:
1. Данные (Data): факты, которые могут использоваться как угодно.
2. Функции-расчёты (Calculations): когда на любой вход, у нас одинаковый выход. В видео это называли без side-effect'ов.
3. Функции-Действия (Actions): что угодно зависящее от того, когда было вызвано или сколько раз.
Любое действие "заражает" всё что выше. В примерах это было ActiveRecord, вызов функции now () и т.п.
TDD подход ваш очень хорош, мне тоже не зашёл красный зелёный красный
Я бы в 1с эту пиццерию сделал))
Боря, привет!
Еху
довольно давно пишу на пхп, но такое чувство, что разговор был про что-то другое... ;) очень интересно, но мало что понятно... в плане практического применения. нужно будет на досуге покопать тему...
Про экзамен в лицей, и единицы измерения, уже там Борис использовал приведение типов ;).
А проектирование и разработку на 1С-ке, получается, можно назвать DDD? Предметметно-ориентированный подход этоже оно и есть, или всё не так?
ну концепции ддд до 1С не дорасти, т.к. есть священое писание ддд и развития не предполагает. мешает наложение ооп. то что они считают методом модели (домена) является само по себе моделью (доменом)
Классный выпуск, лойс!
Одно НО: гость больно часто прыгал по темам туда и обратно :)
Даня Поперечный отжигает про ДДД😀
Сильная связность и слабое сцепление, а не "зацепление", от слова цепь.
Я ж правильно понимаю, холодильник для ремонта и холодильник в контексте готовки физически, если говорить про базу, будут храниться в РАЗНЫХ таблицах, базах, хранилищах и т.д. А объединять их будет Identity, например, поле externalId?
В 99% случаев - да. Готовые датамапперы не позволят сделать наоборот. Но надо понимать, что DDD это про бизнесс, а не про хранение данных.
Например, в виде исключения (а точнее, если Вы взвесили все плюсы и минусы) можно сделать и так:
Вы пилите легас, и у вас уже случилась одна жирная таблица, содержащая два различных BoundedContext, и разделить данные сложно, то можете попробовать запилить такое сохранение сущностей (такой UnitOfWork), чтобы разные бизнес сущности (Entity\Aggergates) сохранялись в одну табличку.
В одной. Дтошки разные