Обновить
2
Андрей Черницов@Dr10s

Backend developer

1
Подписчики
Отправить сообщение

Обычно в монолитах без out of process зависимостях для общения между модулями используют application какраз как ACL над доменом что бы не делать +1 прослойку над командами/кверями. Единственное правило: application input/output должены содержать примитивы яп а не доменные классы

У вас один менеджер но контекст/модуль? Не превратится это в класс на 100500 строк и методов?

Спасибо за статью. Это та идея которую все игнорируют

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

Однозначно лайк, возможно это больше откроет глаза на стратегические паттерны. А слову даже канвас в ддд СНГ сообществах мало кто обсуждает, все остановились на уровне тактики и кода;(

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

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

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

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

Можете развить мысль, что вы имели ввиду?

Разбиение по слоям (анти-паттерн)

Спасибо за статью. Вставлю свои 5 копеек:

CQRS - это про ответственность. Его можно реализовать через два класса, а можно через два сервиса. В статье делается очень сильный упор на две бд как будто это основа CQRS, но нет, это просто удобный способ масштабирования который идеально ложится на CQRS. Это приводит к большим заблуждениям тех кто не читает первоисточник Грег Янга

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

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

Создание папок Entity/ValueObject/Repository/Service/Event не добавляет информации о бизнесе и только заставляет разработчиков думать о паттернах, а не о домене. Это так же увеличивает количество точек входа и “прыжков” по коду

В терминах DDD: это именно рост когнитивной нагрузки, а не её уменьшение. Что противоречит самому подходу на мой взгляд.

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

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

Я говорю про взаимодействие сабдоменов ВНУТРИ БК(Bounded Context).

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

важно не путать концепты интеграции БК такие как partnership, separated ways, conformist, с реализациями типа pub/sub или синхронный вызов/sync API

Здесь чувствуется смешивание единых языков DDD и простых технических вещей :D pub/sub это не про очереди и не про инфраструктурную реализацию в контексте DDD)

publisher/subscriber или customer/supplier - это про то, какой контекст является поставщиком знаний/услуг/фичей а какой контекст является потребителем.

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

Посмотрите на моем примере:

У нас в одном БК есть два домена(продукт и шаблон). Где то там живёт отдельный бк с доменом шаблон который занимается шаблонами и этот БК кормит всех остальных своими данными.

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

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

Выносить кусок контекста(модуля) отдельно я думаю разумно только по каким-то производительным/инфраструктурным причинам.

Здесь у вас произошла ошибка с определением понятиями. Подходы взаимодействия через интерфейсы и ТД(pub/sub, partnership, separated ways, shared, etc) - это какраз все про взаимодействие контекстов, а не доменов.

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

Репозиторий внедомена (как и любые другие сетевые взаимодействия) - это класика чистого домена. Жаль из-за трейдофов с производительностью не всегда получается этого придерживаться.

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

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

Возможно, более базово погрузится в этот вопрос может помочь книга по UML от Ивара Якобсона, а точнее её раздел про варианты использования. По слухам бородатых дядек - это можно назвать первоисточником определения use case.

Так же про минусы - на моей практике внедрения данной структуры минус понимания типов (какие сущности у нас есть) существует только первый месяц +- пока команда не перестраивает своё мышление. Это нормально для всего чего-то нового и отличного от того как мы привыкли делать. Мозг лентяй и он часто сопротивляется.

С практикой применения данной структуры данные вопросы так же легко закрываются. Мы видим существительное и понимаем что это ентити или часть ентити. А solution architect обычно вообще не прибегает к коду и делегирует эти задачи команде разработки, он больше манипулирует другими вещами - такими как ендпоинты/схема бд и тд. А т.к. наши агрегаты/ентити это != схема бд здесь тоже можно начать заблуждаться в полученных выводах.

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

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

/domain
    /product
        /entity
        /service
        /value_object
        /event
    /another module/subdomain

Представьте, что product состоит из нескольких агрегатов и множества ентити, мы получим в папке entity много файлов и много подпапок. и это повториться в других папках: enity, value_object, event, service, exception и тд. И что бы понять какие у нас есть сущности и какие ивенты например эти сущности создают - нам придется пробежаться по каждой вложенной папке. На практике это зачастую приводило к тому что уже сделаны какие-то выводы по инвестигейту будущей работы и потом оказалось, что разработчик забыл посмотреть в какую-нибудь fooBar папку/подпапку и выбранное решение уже не подходит т.к. мы незаметили часть картины домена.

И чем больше контекст/домен - то болше будет вложенных папок/подпапок и собрать какое-то понимание того что происходит в домене становится затруднительно. Нам приходится закрывать папку domain и открывать папку application и уже изучать юзкейсы которых обычно еще больше и пропустить что-то становится еще более просто.

Так же про сабдомены:

/domain
    /product        
    /another module/subdomain

В данной картине очень сложно понять кто рут домен а кто сапортящий. Приходится так же открывать каждый из них и изучать, а иногда становится не очевидно кто же первее "курица или яйцо". product или template.

Данный подход очень удобен и полезен для маленьких проктов/bounded context. Где нет много сущностей, сложной логики, больших связей между сущностями и реакций на действия сущностей. Т.к. основная проблема данного подхода - чем больше проект - тем сложнее в нем ориентироваться. в папке Entity появляются подпапки в подпапках еще подпапки и мы получаем набор классов которые непонятно как живут друг с другом.

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

Не знаю хорошо это или плохо но уже произошла какая-то "проф деформация" и уже даже мелкие поддерживающие проекты реализую с помощью packet by feature в domain

Когда стоит вопрос "положить в прикладной или доменный слой" - я прибегаю абстрагированию от ИТ. Переношу сценарий на 100500 лет назад где не было компьютеров а люди жили в пещерах. И все те вещи которые есть как и в пещерное время так и сегодня независимо от технологий - 100% кладу в domain.

Но такое тоже не всегда можно провернуть. Если у нас есть несколько разных use case что бы создать продукт, то скорее всего различия между этими use case будут аркестрироваться в прикладном слое.

Например если продукт создаёт главный админ мы его просто создаём.

А если продукт создаёт саппорт-менеджер - нам нужно проверить несколько внешний условий и при их успехе создать продукт - саму логику условий будет в домене а ее использование в прикладном слое.

В моем варианте будет папка Domain/Create product/ и в ней будут сервисы/интерфейсы/политики отвечающие за создание продукта которые будут вызываться в разных use case в разной вариации.

И тем и тем, например для VO скидка можно сделать VO и указать там правило что скидка не может быть 0 и меньше 0, теже правила скорее всего будут у цены, цена продукта не может быть 0 и ниже 0. Такие вещи объединяются в shared VO что бы не плодить слишком много однотипных VO ради повторяющихся инвариантов

1

Информация

В рейтинге
Не участвует
Откуда
Беларусь
Зарегистрирован
Активность