Search
Write a publication
Pull to refresh

Comments 91

Очень много текста конечно, но как по мне вы в кучу скидываете понятия хоть чучуть пересекающиеся и из-за этого качество изложенного страдает (моё мнение). DDD никак не протеворечет/запрещает паттерны ООП или какие либо ещё. Домен не является неизменяемым фундаментом на всем цикле жизни приложения, домен нужен для строгой инверсии зависимости и изоляции кода который отвечает за бизнес логику от кода который помогает этой бизнес логике работать с технической точки зрения.

Подскажите такую вещь - вот я сделал сущность, у нее свойства приватные (чтобы не нарушать ее состояние), и можно либо через конструктор значения передать, либо на каждое свойство реализовать метод UpdateXXX(value).

Далее у нас есть контроллер, там DTO, допустим там UpdateDTO и все те же поля для простоты. Как это все подружить на ООП языке, не добавляя 100500 параметров в конструктор или методов UpdateXXX?

Довольно таки толстенько

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

Допустим, а как тогда делать форму редактирования некой сущности? Заказ например? Там 80% обновлений полей и 20% - это пнуть заказ дальше по процессу (триггер на изменение статуса).

Мне кажется заказ это как раз плохой пример, у вас всетаки продукт это отдельный объект, а корзина это объект который в себя собирает объекты продукта, вы же не в свойства объекта корзины пихаете все продукты? (Так можно делать, если объект корзины содержит поле под массив объектов продукта)

Ну и всеже вы не обновляете объект ради обновления, вы хотите сохранить информацию о заказе и редактируете хранилище свое, а тут можно 1 функцией и 1 sql запросом обойтись, а не делать апдейт на каждое поле.

Мне кажется заказ это как раз плохой пример

Конкретно в моем случае - это автоматическая обработка уже созданных заказов - они скачиваются и запускается обработка, но там есть процессы на обновление, отмену и редактирование через UI на всякий критический (редкий) случай (статус там менять нельзя просто так - только нажать кнопку и запустить процесс). Поля есть - заголовок (адрес, дата, номер) и линии заказа (это отдельная сущность со своими полями), вместе они aggregate root.

тут можно 1 функцией и 1 sql запросом обойтись

В целом, я это понимаю, но не понимаю как это подружить с DDD. На логическом уровне мне получается надо две сущности - одна DDD (чтобы пнуть емкий процесс после изменения статуса, там поля только на чтение, закрытые от изменений) и одна анемичная (active record, все что угодно, чтобы просто поля обновить). Да даже, чтобы просто создать сущность из CreateDTO - надо конструктор у сущности с 100500 полями (мне не нравятся такие конструкторы - в некоторых компаниях, например, code style, говорит что максимум 5 зависимостей / параметров в конструкторе или методе).

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

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

И стало интересно как в реальности это решается.

У вас не должно быть в проекте деление на DDD сущности и сущности базы данных. Система в базу должна сохранять результат выполнения своей логики. Мне например ближе TableModule и не надо никаких объектов городить с огромными конструкторами.

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

Так, то есть вы используете DDD сущность + TableModule? Через первую вы запускаете сложные процессы домена, а через вторую - сохраняете в БД, если просто отредактировали на UI?

Что по вашему значит DDD сущность? Типо у вас половина кода DDD, а половина нет? Это ведь не так работает

Класс, отражающий какой-то объект предметной области, внутри содержит бизнес логику, поля закрыты от изменения. И есть всякие публичные методы, которые позволяют что-то сделать с этой сущностью правильным способом.

А вы где храните table module?

В текущем проекте они лежат в бизнес логике, но они не чистые table module, а с примесью entity

Да даже, чтобы просто создать сущность из CreateDTO - надо конструктор у сущности с 100500 полями

Конструктор в этом случае должен принимать CreateDTO.

На логическом уровне мне получается надо две сущности - одна DDD (там поля только на чтение, закрытые от изменений) и одна анемичная (active record, чтобы просто поля обновить).

Вторая модель вам нужна только если у вас ORM так работает, и по-другому никак не сделать. Многие ORM нормально умеют работать с произвольными классами, где есть геттеры. А где нет, могут читать свойства через рефлексию. Если у вас есть свой класс репозитория, можно там формировать сразу SQL-запрос без ORM, в виде текста или через query builder.
Если вы хотите строго следовать DDD, то вы не должны использовать active record, как раз потому что там можно обновлять поля произвольным образом.

У меня проблема не с orm, а с DTO, которое должно быть доступно и для уровня сервисов и для уровня домена. У меня это две разные DLL.

обычно это должно быть реакцией на что либо самого объекта

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

Объект в коде решает только задачу объекта в коде, есть процесс и вы его объясняете компьютеру (и себе) на объектах.

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

Функциональные программисты тоже могут решить бизнес задачу, и без объектов. Я маленько не об этом. Все же вы не сможете прямо на кодовых объектах общаться с бизнесом)

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

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

идет разговор про реализацию объектов в коде, это никак не зависит от бизнеса

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

Со стороны внешнего наблюдателя, за бизнес-логику отвечают Aggregation Roots, с которыми он взаимодействует. Отсюда она может делегироваться дальше по цепочке вниз: в доменные сервисы, entities и т.п. - но это уже нюансы выбранной декомпозиции. Выбор между анемичными и rich models это чисто локальные заморочки дизайна.

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

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

отвечают Aggregation Roots
Отсюда она может делегироваться дальше по цепочке вниз: в доменные сервисы, entities

Aggregation Root это и есть entity.

допустим там UpdateDTO и все те же поля

Если у вас есть именно такое бизнес-действие (например форма в админке, которую бизнес попросил сделать), то надо делать так. Метод контроллера принимает Request, конвертирует его в UpdateDTO, передает его в аналогичный метод сервиса, конвертирует результат в Response. Метод сервиса принимает на входе UpdateDTO и сущность, с которой нужно сделать действие, возвращает какое-то DTO или сущность. По DDD бизнес-логика должна быть в сущности, поэтому в ней будет такой же метод, который принимает UpdateDTO и переносит значения из него в поля this. Сервис в этом случае содержит технические действия - сохранение в базу, работу с кэшем и т.д.
Я так делать не рекомендую, на практике бизнес-логика в сущности создает проблемы, в основном из-за сложностей проброса зависимостей. Пишите логику в сервисах, в данном случае у вас будут вызовы сеттеров. Можно вынести их в приватный метод сервиса.

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

DLL это детали реализации, в языках с которыми я работаю нет никаких DLL.
Да, DTO могут быть частью домена. Это более высокоуровневый слой, чем контроллер, поэтому не проблема, если контроллер от них зависит. Вы же сущности как-то используете в более низкоуровневых слоях.
Я обычно делаю DTO для входных и выходных данных сервиса в одном слое с сервисами. Сущности обычно используются в разных сервисах, поэтому они у меня в другом неймспейсе, но логически это тоже слой бизнес-логики.

Понял, если неймспейсы физически не разделяются - тогда проще.

Бардак! Все сошли с ума и мир перевернулся вверх тормашками 🙃 Всех бросает из крайности в крайность. Доярки возамнили себя принцессами, программисты элитой умственного труда, — но никто не хочет работать, согласовывать взаимодействие, — и всё это под прессом бизнесс-процессов, дедлайнов, да еще и котировок на фондовых рынках. Еще эти дизайнеры с маркетолагами бессятся, и хомяки туда же.

Ща, немного перебесимся, отрасль взрослеет , авось прорвемся.

Честно прочитал треть статьи. Статья не интересная, потому что ничего не объясняет.

Проблема в том, что стиль статьи псевдохудожественный, - с чувствами и лирикой, - а не публицистический. Чётко ощущается "мысль-по-древу".

Видимо в этом и состоит суть DDD - софистические рассуждения об абстрактных материях...

Комментарий пишу для того, чтобы дать возможность автору переосмыслить "предметную область" и задействовать немного Дискретной Математики. Это может в корне поменять результат труда (**если это был труд, а не просто эссе о том "Как я провёл лето с ддд")

В общем, мне лично не понравилась статья и я решил написать этот комментарий.

А как по мне - статья интересная. Она не предназначена для того, чтобы дать готовый рецепт "делай только так и будет тебе счастье". Да, автор пропагандирует DDD, но без фанатизма. Мне кажется, это не манифест, а попытка автора самому себе объяснить что не так в разработке и какие есть способы если не избавиться от боли (таких нет, как нет универсальной пилюли в медицине), то хотя бы сделать жизнь более-менее сносной, а проекты, пусть даже они и не будут идеальными, доводить до внедрения и - главное - оставлять резервы в архитектуре для дальнейшего развития. Ибо ничто не вечно - это банально, но часто (в стремлении вывести в прод сегодня, в крайнем случае - завтра) намеренно игнорируется.

Эванса читать нелегко. Я сделал несколько подходов на протяжении минимум лет пяти. И знаю, что вернусь опять. Там много такого, что раскрывается постепенно (для меня по крайней мере).

Автору, к слову, респект и уважуха. Такое ощущение, что мы знакомы - много деталей и ситуаций с которыми доводилось сталкиваться и мне :)

Отличная статья про DDD, продолжайте. Некоторые цитаты, пожалуй, умыкну себе на тренинги. Не объясните почему Адрес ужасен в VO? Инвариантами?

Спасибо за высокую оценку.

Адрес плох в качестве примера Value Object, так как его выделение в отдельную сущность слишком очевидно по не относящимся к делу причинам (много свойств + повторное использование). Поэтому он ничему толком не учит.

Хорошие примеры это Distance и BirthDay. Первый демонстрирует силу предотвращения ошибок за счёт грамотной структуры, второй - возможность разгрузить Entity.

А в целом - тактические паттерны обросли таким количеством совершенно диких предрассудков и общепринятых плохих практик, что на эту тему впору писать отдельную публикацию.

Не понял критерии "учебу" и "силы". Вероятно, речь о невозможности валидации Address без внешних зависимостей и вырождении VO в DTO? Пишите, почитаем.

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

Value Object позволяет создавать wrapper-ы над простыми типами данных, которые помогают не нарушать инварианты.

Address оттягивает внимания от этих важных и часто полезных концепций создавая ложное впечатление, что Value Object это что-то про повторное использование или, на крайний случай, явное выделение доменных концепций.

И то и другое хорошо и важно, но акцентировать внимание всё равно следует на первых двух пунктах, как не менее полезных, но менее очевидных, чему Address ни разу не способствует.

Разбиение системы на микросервисы без учёта всего вышесказанного – прямая дорога в ад распределённого монолита, который объединяет все худшие качества монолита со всеми худшими качествами микросервисов

Категорически не согласен. Недостатки микросервисов - в мокром коде (not DRY), катастрофических потерях на сетевое взаимодействие, сериализация/десериализация сообщений с потерей типизации аргументов, ловля ошибок через сеть и веселье с деплоем/оркерстрацией всего этого праздника.

Да, DDD - это инструмент управления сложностью. Эта мысль верная и только за это я поставил плюсик статье. Эту мысль нужно озвучивать.

Вот только DDD управляет сложностью не микросервисами. Ему всё равно, на чём вы сделаете разделение обязанностей. Главное, чтобы у вас части были логически отделены друг от друга, чтобы у них были чёткие обязанности. Это прекрасно делается в монолите, если руки не из жопы.

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

Они (микросервисы) вроде как должны бать stateless. Иначе вы просто пытаетесь по отдельному микросервису на запрос к базе данных

по-моему, Ваш комментарий нисколько не противоречит сказанному автором. Автор никак не касается обозначенных Вами проблем. ( Разве что "мокрый код" - спорная территория ).
Другими словами: к видимым проблемам ( сетевое взаимодействие, сериализация, оркестрация ) может добавиться ещё и то, что у Вас - монолит, внешне оформленный как микросервисы. И каждый чих в одном микросервисе может вызвать непредсказуемые судороги в других.

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

Классно что есть люди кто думает своей головой и не ведётся на хайп

То, что вы хвалите, это, похоже, и есть модульный монолит. Ну или микросервисы, построенные на концепции bounded context, я не вполне уверен, что вы имеете ввиду.

А плохо организованную кашу из микросервисов, которую вы ругаете, как раз и называют "распределённым монолитом".

ммм... нет.

Монолит - это одно приложение со связанным контекстом и типами.

Микросервисы - это отдельные приложения, не связанные ничем, кроме сетевого апи.

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

Микросервисы проще писать, потому что они ни от кого не зависят. Зато потом вскрывается это "не зависит". Оказывается, что зависит, и ещё как. Но уже в рантайме.

Что для вас «распределенный монолит»? Кажется у вас какое-то свое понимание этого термина, потому что ни один инженер кто сталкивался с ним в реальности не назовет это «нормальной архитектурой»

Ну как монолит, только распределённый. Когда пишется большая система, обычно делается монолит, это просто следствие yagni.

Потом, когда (и если) возникает необходимость масштабировать (упирается в rps/cpu/mem), то возникает идея распределить нагрузки на несколько узлов. Самый простой вариант - отделить ту часть, которую можно распараллелить. Тут даже можно запускать один и тот же разный монолит, но с разными ключами, назначив мастер-ноду. Много разных способов существует. Может быть даже каждый монолит со своей БД, завёрнутый в докер. Может они равноправны и ходят в одну БД. Это всё зависит от типа приложения и характера нагрузки, потому что распараллеливание нужно для оптимизации нагрузки.

Тут скорее под "распределенным монолитом" имеется в виду микросервисная архитектура, которая на первый взгляд только такой выглядит, но из-за связности между сервисами по сути является монолитом.
У меня в практике был пример, когда мне надо было написать сервис на буквально 5-6 эндпоинтов, но просто чтобы этот сервис запустить мне надо было в docker compose завернуть еще сервиса 3-4, просто чтобы они накатили нужные миграции. Это был ад.
А еще был момент, когда над монолитом работали 800+ разработчиков и деплой был раз в 45 минут, что привело к тому что от момента аппрува на ревью до попадания кода в мастер проходило несколько дней при активном мониторинге со стороны разработчика. Это тоже было то еще мероприятие.

А, знаю этот прикол. Когда делают микросервисы часто упираются в связность взаимодействия. Получается как-бы монолит по связности, но на обслуживание сериализации/десериализации уходит 60% cpu. И плюшки вроде падения в рантайме из-за рассинхрона апишечки.

Про ваш монолит. Поверьте, несколько дней от аппрува до мастера - это ещё очень лайтово. Учитывая количество разрабов кодобазы. Когда количество разрабов растёт, ломаются нахер все ранее работавшие процессы. Лиды не успевают всех ревьюить. Пуш гита прокатывает с 3й или 4й попытки мержа. Репозиторишна опухла или как. У нас была поменьше репа (наверное) в 34гб, но был hg, потому что гиту было с ней ой как плохо.

Ну тут реально пилить надо, Шура. Причём скорее не на сервисы, а на команды, тут больше административных проблем. И решать их сложно. Микросервисы даже тут очень плохая идея. Микросервисы просто перенесут сложность взаимодействия на этап интеграции, по факту ничего не решив и только добавив своей "специфики".

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

Я даже знаю, где их применение удачно. В каком-нибудь суперуспешном и супернагруженном проекте. Там где много разрабов, много денег, отлажены процессы и очень много rps. Миллионы. Но при этом от сервисов не требуется рокет саенс. Один микросервис котиков отдаёт, второй сиськи. А мы их масштабируем в зависимости от нагрузки. Ну я так, очень утрировано.

В статье говориться:

наш главный враг – сложность

и каждый раз при прочтении очередной статьи возникает когнитивный диссонанс - а где собственно простой инструмент борьбы со сложностью? Почему пишут такое огромное количество статей, где практически никогда ничего не уходит дальше бесконечного теоретизирования? Почему хоть кто-то из DDDшников не может написать проект, который читатели могут посмотреть и ответить для себя: да оно работает или нет, оно приносит больше сложностей чем решает и нежизнеспособно?

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

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

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

Потому что DDD - это не фреймворк. Это принцип. И проект, который сделан по принципу DDD будет снижать сложность конкретной области и не применим в другой. Причём если вы посмотрите на проект, вы не увидите снижения сложности. Для того, чтобы её увидеть, нужно взять два проекта: один в бардаке, второй после рефакторинга по DDD.

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

Просто замечательно. Видимо, как говориться, нужно просто верить.

Для того, чтобы её увидеть, нужно взять два проекта: один в бардаке, второй после рефакторинга по DDD.

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

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

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

А потом покажете людям и скажете: смотрите, я навёл порядок не используя DDD!

Мне останется только усмехнуться тихонечко в стороне. Я же уже это проходил. Конечно, вы не использовали DDD. Вы его породили.

Занимательно что с Ваших же слов, DDD это что-то само собой разумеющееся, которое само собой изобретается и все до этого сами доходят. Я позволю себе усомниться и поверить что все вокруг настолько идиоты что нужно написать сотни статей на эту тему и целые книги о том что Документ нужно называть Document в коде и продолжать это делать годами. Сдается мне вопрос тут не только в отделении и именовании.

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

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

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

Кстати, "документ" - это плохое название для сущности. Это могут быть счета, накладные, акты, договоры или приложения к ним. Да много чего. У каждого документа - своё прикладное значение. И чаще всего он появляется не сам по себе, а как фиксирующая какую-либо информацию сущность у другой сущности, уже из предметной области.

Для того, чтобы её увидеть, нужно взять два проекта: один в бардаке, второй после рефакторинга по DDD.

У меня есть проект с логикой в сервисах, там 6 небольших действий. Сможете написать хотя бы 2 в стиле DDD с логикой в сущностях? Сравним результат, уменьшилась сложность или нет.

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

Ну так можно же представить в каких ситуациях будет улучшение, а в каких нет, даже если в самом коде их нет :)

Так вы и сейчас можете представить. Просто если пихать DDD в простой сервис, где он не нужен - вы ничего не увидите. А вот когда у вас сложная предметная область, и когда быстро меняется логика взаимодействия между объектами предметной области, тогда DDD хорош. Там нет ничего космического. Ничего, что бы противоречило здравому смыслу.

Просто я не возьмусь бесплатно ваш проект выправлять, а сумма вам не понравится. А просто чтобы показать, чем DDD хорош - ну у меня мотивации нет.

Так вы и сейчас можете представить.

Сейчас я не могу, потому что нет примера кода, как эта функциональность может быть написана с DDD.

если пихать DDD в простой сервис, где он не нужен - вы ничего не увидите

Ну так можно же представить в каких ситуациях будет улучшение, а в каких нет, даже если в самом коде их нет. Только сначала нужен этот сам код.

Ничего, что бы противоречило здравому смыслу.

Там есть логика в сущностях, от этого идут основные сложности. Это я и хочу показать.

Просто я не возьмусь бесплатно ваш проект выправлять

Если с вашим подходом на 2 простых действия нужно много времени и усилий, то это говорит плохо об этом подходе. В реальном приложении вместо 2 действий будет 2000, соответственно возрастут и затраты усилий. Их потому и много, что они делают разные независимые действия, есть много групп по 2-10 связанных действий. Поэтому реализация одной такой группы покажет хороший пример.

Это не мой проект, а тестовый, выправлять его не надо. Но он основан на реальном приложении. Он описан тут. Вы сказали чтобы сравнить нужно 2 версии одного проекта, я предлагаю версию без DDD, покажите свою с DDD. Я его специально для таких обсуждений и сделал. Сколько предлагаю, еще ни один сторонник DDD не согласился показать свой код. Хотя время на это нужно меньше, чем писать десятки комментов про то, как будет хорошо с DDD.

покажите свою с DDD

Не хочу. Вы кажется проигнорировали, где я объяснял, почему.

Давайте ещё одно объяснение дам. Мне вообще нахер не впилось себе конкуренцию создавать. Ну не работает DDD и ладно, я соглашусь. Оно мне надо что-то вам доказывать?

Чтобы в вашем проекте мне сделать DDD, мне нужно досконально разобраться с вашей же предметной областью. Вопрос. Мне за потраченное время кто-нибудь заплатит?

Не проигнорировал, а попытался исправить ситуацию, чтобы это не выглядело очередным бла-бла-бла от сторонника DDD. Видимо не получилось.

Мне вообще нахер не впилось себе конкуренцию создавать.

А рассказы о преимуществах DDD не создают вам конкуренцию?) А то ведь кто-то решит попробовать.
Но если вас это волнует, то я хотел показать, что с DDD будет больше сложностей, и увеличение размера приложения это не изменит. Но конструктивного обсуждения не получилось.

Мне за потраченное время кто-нибудь заплатит?

А за время, потраченное на комментарии, вам кто-нибудь платит?

Дорогой Майкл. Не надо брать случайных пользователей интернета на слабо.

Одно дело, когда рассказываешь свой опыт и свою точку зрения, другое дело идти и делать работу. Которой у каждого хватает.

Кстати, если не заметили, статью писал не я.

Я беру не случайных, а тех, кто сам говорит "ну надо две версии, чтобы сравнить до и после". Специально на такой случай я подготовил пример с минимальными требованиями, которого достаточно, чтобы экстраполировать на реальное приложение.

Я не говорил, что статью писали вы.

Ну так берите и сделайте. Я же не обещал вам. В чём проблема? За вас кто-то работу будет делать бесплатно и бесплатно вас учить? Может быть, но это не я.

Я не говорил, что вы обещали. Я предложил проверить ваши утверждения на практике. Не хотите, как хотите, это тоже о многом говорит.

Как я уже сказал, учить меня не надо, это я хотел кое-что показать. Я уже сделал и видел результат. Он не соответствует вашим утверждениям.

Ну и отлично. На этом и разойдёмся. Меня всё устраивает.

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

А если у вас не DDD, а ООП

Это выражение не имеет смысла, это не взаимоисключающие понятия.

DDD это концепция бизнес разработки, когда все в контексте

Нет, это не является определением DDD.

Что значит с логикой в сущностях?

Один из ключевых принципов DDD это то, что бизнес-логика должна быть в классах сущностей.

Вам не говорят, что это взаимоисключающие параграфы. Вам говорят, что логика в сущностях это не маркер DDD, а используется в простом советском ООП.

Фраза "Не A, а B" именно это и говорит.
DDD и ООП могут прекрасно существовать вместе, и более того, так рекомендуется делать.

Логика в сущностях это именно маркер DDD.
Все авторы известных книг по DDD советуют использовать Rich Domain Model.

Фраза "Не A, а B" именно это и говорит.

Не говорит. Вас прямо спросили, как вы ООП от DDD отличать будете со своими критериями.

Я прямо и ответил - никак, DDD предполагает использование ООП. Примеры в книгах известных авторов про DDD используют ООП.
Как отличить код с DDD от кода без DDD написано в тех же книгах, при этом в обоих может быть ООП.

Наверное потому что это в какой-то степени как картина, DDD у всех одно (условно простые фигуры/примитивы из рисования) но результат у всех разный, который зависит от компетенции архитектора.

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

Например в текущем проекте я взял что-то из MVC (контроллеры) и паттерн ООП - команда. Пользователь через точку входа (контроллер) отправляет запрос, формируется пул команд (от 1 до бесконечности) выполняется, обрабатывается и возвращается пользователю результат. Это все очень хорошо ложится друг с другом, и вникнуть в проект проще когда каждая его часть формализована, а не просто работает.

Наверное потому что это в какой-то степени как картина, DDD у всех одно (условно простые фигуры/примитивы из рисования) но результат у всех разный, который зависит от компетенции архитектора.

Да я не против разного резултата. Есть утверждение что - "DDD снижает сложность". Я хочу увидеть доказательства данного утверждения. Потому как часто бывает, снижение сложности на словах выливается в оверинжиниринг и реальное увеличение сложности на практике.

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

А как по факту там ООП или еще что-то, это маленько про другое. По поводу слоистости и чистоты (поддерживаемости кода), как мне кажется, разработчик рано или поздно сам приходит к этому, поэтому она, наверное, как некий факт воспринимается в контексте DDD.

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

Я никуда не смотрю, у меня простой вопрос - где примеры и доказательства того что это действительно упрощает разработку. И вроде б у нас деятельность практического - "Talk is cheap. Show me the code.". Но нет, все сводиться в словесную демагогию.

DDD это не только про код, тут надо брать 2 команды и сравнивать если вы хотите каких-то цифр.

А так, я в процесе работы сам пришел к чему-то похожему, все же мы одно дело делаем (стараемся).

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

Я рассуждаю проще. Есть проблема и есть решения проблемы.
Решение должно быть настолько простым и понятным насколько это возможно и не должно порождать еще больше вопросов, проблем и сложностей чем изначальная проблема. Думаю это логично, иначе какой смысл данного решения?

Что нужно разработке? Простой, понятный и эффективный механизм, доказавший свою целесообразность и эффективность.

Что лично я вижу. Вал статей про одно и тоже с околонулевой прикладной составляющей из года в год. Кучу теоретики. Отсутствие хоть каких то доказательств эффективности, кроме "нужно просто верить" и "на работе пишу и там триумф но показать не могу".

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

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

Есть проблема и есть решения проблемы.

К слову, это называется сабдомен и ограниченный контекст - в терминах стратегического DDD.

Если вы уже сделали первое упражнение, правильно разбив домен (предметную область, aka пространство проблем) на сабдомены (изолированные проблемы), то команды разработчиков будут воспринимать такую декомпозицию не как способ борьбы со сложностью, а как нечто само собой разумеющееся. Часто будет так, что за каждый сабдомен отвечает отдельная команда и они не видят картинки в целом, взаимодействуя лишь со своими непосредственными зависимостями.

Рекомендации по реализации (aka тактическое DDD) на самом деле не про классы - это скорее вотчина Clean Code, Hexagonal Architecture, Design Patterns т.п. Основная же мысль в том, чтобы не терять связь между имплемениацией и решаемой проблемой.

Будет удобно если терминология, которой оперирует реализованное API, в достаточной степени соответствует терминологии сабдомена. Бизнесовые сущности обычно моделируются в терминах Entity-Relation, поэтому в примерах DDD часто используют Entity/Value Objects. Но это вторично. Если вы пишете научный софт, здесь может быть хоть квантовая физика. Просто аудитория квантовых физиков гораздо меньше, чем нас - перекладывателей джейсонов.

По существу, главные игроки в тактическом DDD это Aggregation Roots и оформившиеся чуть позже Enterprise Integration Patterns. Первые являются фасадами, выставляющими язык сабдомена/API наружу и скрывающими внутреннюю сложность ограниченного контекста от внешнего мира. Вторые отвечают за способы интеграции между собой.

Я сильно рекомендую читать Вернона - он классно структурировал описание всей этой концепции. Вторичные трактователи часто описывают лишь какие-то кусочки, нередко фокусируясь на второстепенных деталях, что в итоге только путает.

Дело в том, что с вынужденной сложностью (сложностью домена) бороться бессмысленно, она просто есть, от неё нельзя избавиться, её можно только перераспределить - так или иначе.

Соответственно DDD это история про то, как сложность предметной области перераспределять так, чтобы с ней было проще работать.

Что до конкретных примеров - устройтесь на работу в FAANG и увидите, как это делается на практике. Они там, правда, как правило называют это по другому, но смысла это не меняет. В конце концов сам Эванс признавал, что он не придумал DDD, а оформил в единую систему те приёмы, которые, по его мнению, использовали лучшие архитекторы, с которыми ему доводилось работать над сложными проектами.

Проще говоря - DDD в полную силу оправдывает себя в тех проектах, которые обычно в Open Source не попадают. Большие проекты, над которыми несколько высокопрофессиональных команд согласованно работают на протяжении нескольких лет.

Так смысл перераспределения именно в этом. Базовый закон сложности - это когда сложность одной задачи умножается на сложность другой. При N задачах это всё вырождается в O^N сложность, то есть невозможную.

Смысл управления сложностью как раз в том, чтобы по максимуму оградить каждую задачу от сложностей другой. То есть приблизиться к линейной. К O = (N).

С самой сложностью бороться бесполезно, но её можно сократить до известных пределов.

Что до конкретных примеров - устройтесь на работу в FAANG и увидите, как это делается на практике.

Проще говоря - DDD в полную силу оправдывает себя в тех проектах, которые обычно в Open Source не попадают. Большие проекты, над которыми несколько высокопрофессиональных команд согласованно работают на протяжении нескольких лет.

Браво. Ответ который мы заслужили. Зачем доказывать и показывать идеи, пусть лучше кому интересно идут лесом в FAANG и сами проверяют да и вообще это нельзя показать - это все в закрытых репозиториях, где исключительно профессиональные команды над этим работают, главное просто верить что все это работает. Инженерный подход 10 из 10.

PS мне это один в один напоминает подход школ восточных боевых искусств, которые на словах рассказываются про свою невероятную эффективность но при попытке вызвать на спарринг для практического эксперимента сразу идут в ход рассказы что в школе спарринги запрещены потому что школа настолько смертоносная что бьются они только насмерть и только когда другого выхода нет. Удобно.

Браво. Ответ который мы заслужили

Чтобы что-то заслужить, нужно предпринять какие-то конкретные действия.

В данном случае вы просто усиленно делаете вид, что вам кто-то что-то навязывает.
Это не просто не так - это бесконечно далеко от реальности. Как это обычно и бывает - вы просто часть аудитории, а я просто автор, который решил поделиться с этой аудиторией своим опытом и своими соображениями. Не больше, не меньше.

В моих руках изложенные принципы и подходы - работают и я это знаю. И таких людей в индустрии - немало. Не хотите верить, не хотите слушать, не хотите вдумываться? Да на здоровье, идите своим путём, используйте то, что работает для вас и, если хотите, делитесь своим опытом с другими. Никто никого не неволит.

Проблема поиска универсального инструмента в том, что это не конкретные правила, а схема того, как подбирать правила. (и эти схемы давно известны)

Потому что сложность бывает разных видов:
структурная (много элементов),
синергетическая (много связей между элементами),
временнАя (много состояний системы, которые меняются в рантайме),
историческая (некоторые решения принимались в разное время в разных условиях и некоторые уже устарели),
функциональная (на один домен возложено сразу много функций и разносить их по разным частям = увеличивать структурную и временнУю сложность),
и так далее.

Сооветственно, каждый из критериев - одна из осей = степеней свободы. И число возможных решений - комбинаторная сложность от количества степеней свободы (что содержит некоторое кол-во факториалов в формуле).

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

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

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

Автор очень верно заметил, что в DDD нет ничего нового, кроме самого DDD, то есть подхода "опираемся на реальность". Это действительно так. Все остальное - паттерны, приемы - от лукавого.

Реальность такова, что даже такая, казалось бы, консервативная предметная область как платежи - живет невероятно бурной жизнью. Тут и непрерывные регуляторные изменения-ужесточения, тут и новые технологии, и новые подходы (и жесточайшая конкурентная гонка со временем!).

В подходе DDD самое важное - это именно ЗНАТЬ предметную область и ПОНИМАТЬ законы ее развития. Чем лучше ты ее понимаешь - тем больше твое конкурентное преимущество.

И позвольте мне, как человеку сделавшему немало в сфере платежей, сообщить одну пренеприятнейшую новость: как только вы начинаете бороться со сложностью предметной области путем выделения поддоменов - вы теряете все потенциальные конкурентные преимущества.

Вам, поверьте на слово, НУЖЕН единый сложный контекст, со всеми деталями и нюансами. Именно там вы найдете неожиданные ходы, приводящие к прорывным решениям и новым продуктам. Хотите в "голубой океан" - идите в предметную сложность.

Продукты, до которых ваши конкуренты не додумались раньше вас - это продукты, основанные на неочевидных связях в предметной области. Знание о наличии какого-нибудь "общеизвестного" определенного поля в ISO 8583 и понимание имеющейся правовой базы (которая вообще вся доступна в консультант+) - могут привести к идее продукта с миллиардными годовыми обротами. Вот что такое DDD, и вот для чего на самом деле он нужен.

Еще раз: ни одна предметная область не является "фиксированной". Более того, люди постоянно развивают любую область, создавая новые продукты на базе связей, объективно имеющихся, но до сих пор скрытых. После чего все остальные понимают, что предметная область трансформировалась, и должны начинать учитывать новые реалии.

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

Еще раз: ни одна предметная область не является "фиксированной"

Ни одно приложение не является "фиксированным". Более того, люди постоянно развивают свои приложения, обрабатывая новые процессы, объективно имеющиеся в предметной области, но до сих пор скрытых.

Sign up to leave a comment.

Articles