Комментарии 4
Стили изложения - отличный. Спасибо за статью. Добавил в закладки, позже попробую полностью осмыслить.
Я правильно понимаю что Вы предлагаете успешно делаете такое: вместо размазывания БЛ по сервисам с невнятной категоризацией (или без неё вообще как на примере с 50тью кейзами) помещать её в методы БЛ объектов(entity)? И что бы БЛ из объектов не лезла во всякие там репозитории - методы возвращают объекты-команды "обновляторы", которые уже и будут применять обновление в БД через репозиторий? Ну т.е. это один из посылов статьи, так? Я только недавно встал на путь "чистого кода", хехе, вопрос наверно наивный, пока для себя расставляю по полкам всё.
Да, и разве SOLID Мартина заставляет гранулировать? В том смысле у него есть понятия скромного объекта, но оно для вещей которые сложно тестировать (типа отрисовки в UI). А вот в какой момент вдруг все БЛ-сущности предлагается хранить отдельно в виде DTO а логику в отдельном месте я вот не помню, но вроде не у Мартина. Перечитаю. Хотя я скорее всего не до конца понял Ваш замысел, так что наверно вопрос глупый, надо перечитать основательно и в сам кукбук поглядеть.
И да, кстати, спасибо за ссылку на ROP, прочистило мозги.
Добрый день, спасибо за обратную связь!
Да, в целом, вы верно поняли мысль.
Вместо размазывания БЛ мы помещаем ее в объекты бизнес логики Entity, Aggregate. В примере исходных кодов я использую подход функциональной мутации имутабильных объектов (DDD made functional), в результате которого на выходе мы получаем запрос на изменение в Aggregate.
Важно обратить внимание на Type Driven Development при дизайне ValueObject-ов — это основной кирпичик + R.O.P. Строим на этом фундаменте вместе с unit тестами.
SOLID Мартина не заставляет, но единая ответственность может быть воспринята неоднозначно, что приводит к чрезмерной единой ответственности — 1 класс : 1 метод.
Запрос на изменение можно отправить-преобразовать в команду — дальше можно развивать историю и там дальше на пути встретимся с ивентами.
Вместо размазывания БЛ мы помещаем ее в объекты бизнес логики Entity, Aggregate
А это видно в примере? Я вот пытаюсь понять в чём и где профит по сравнению с обычное анемичной моделью и до меня не доходит.
Допустим у меня уже есть единый язык и 50 юскейсов. В чём выгода, если юскейсы превратятся в последовательную мутацию промежуточных ДТО (R.O.P имитируем ифами) по сравнению с простым кодом? Я думал, что может в переиспользовании отдельных шагов, но выглядит так, что каждый юскейс под свой конвеер создаёт кучу промежуточных ДТО и они не переиспользуется.
Хотелось бы видеть реализацию какой-нибудь CRUD задачи, когда нужно обновить некую сущность в соответствии с какими-нибудь бизнес правилами. Например: при создании заказа нужно проверить, что средств хватает, сохранить выбранные строчки корзины в заготовку заказа, поставить в очередь задачу на отправку письма о созданом заказе, поставить в очередь задачу на дальнейшую обработку заготовки заказа, удалить строки из корзины.
Добрый день! Благодарю вас за хороший вопрос.
Простите за долгую реакцию - в связи с высокой загрузкой у меня нет возможности своевременно отвечать на вопросы. Для этого у меня есть утро Субботы или Воскресенья.
А это видно в примере? Я вот пытаюсь понять в чём и где профит по >сравнению с обычное анемичной моделью и до меня не доходит.
Чтобы ответить на ваш вопрос я приведу некоторые недостатки Слабой доменной модели:
- Инкапсуляция нарушена
- Приводит всегда к Дублированию бизнес-логики
- Невозможно гарантировать, что объекты в модели находятся в согласованном состоянии
- всегда способствует разрыву и непониманию между разработкой и бизнесом
- всегда приводит к описанию бизнес-логики в отдельном месте, например сервисе и сливается в этом случае с интеграцией.
чем плохо слияние с интеграцией?
- тем что тестирование бизнес-логики возможно только моками
Также рекомендую прочитать про этот анти-паттерн у Martin Fowler -> https://www.martinfowler.com/bliki/AnemicDomainModel.html
Преимущества Сильной доменной модели по Type Driven:
- бизнес-логика ограничений и поведения собрана в одном месте
- легко поддерживать, развивать, изучать
- Эта логика направляет и контролирует создание, проверку и управление сущностью, предотвращая появление у клиента сущностей с несогласованным состоянием сразу в одном месте
- код превращается в документацию
- по кукбуку - бизнес-логика - отделена от интеграций - ее просто тестировать, а сервисный слой - тупая труба - его тестировать одним интеграционным тестом. Снижаем количество интеграционных тестов - меньше кода и тестовых конфигураций нужно писать.
- в самом ядре бизнес-логика инвариантов описана по паттерну ValueObject's, например: SubscriberId - сразу контролирует свое возникновение и описывает ограничения на свое появление.
- такое ядро максимально удобно тестировать юнит тестами - тестируем выходные данные функции - а это самый эффективный тест
Допустим у меня уже есть единый язык и 50 юскейсов.
50 - много. стоит поработать с ограниченным контекстом и декомпозировать историю
В чём выгода, если юскейсы превратятся в последовательную мутацию промежуточных ДТО (R.O.P имитируем ифами) по сравнению с простым кодом?
пайплайн ориентированный подход нам помогает решать такие проблемы:
- код есть документация - просто читать не только программисту
- это всегда однонаправленный поток, даже с ответвлениями
- упрощает компоновку шагов
- помогает следовать принципам хорошего дизайна, заворачивает нас в создание функций с 1,2 входными параметрами- проще мэйнтэйнить
- проще тестировать
- вот классное видео про П.О.П.
https://www.youtube.com/watch?v=sfYA0HCWgq - в кукбуке я его также оставил.
- в него проще погружать новичков и следить за и тем, как они развивают историю
Я думал, что может в переиспользовании отдельных шагов, но выглядит так, что каждый юскейс под свой конвеер создаёт кучу промежуточных ДТО и они не переиспользуется.
- можно переиспользовать шаги, мы так делаем
Но главная мысль - каждый бизнес-процесс, как флоу - независимая история и мы описываем его здесь и сейчас не думаем о других процессах.
Если у нас в сервисе много разных бизнес-процессов - это сигнал задуматься и разнести бизнес-логику, чтобы упростить систему.
Если в компонентах есть какие-то общие шаги - их можно переиспользовать.
Хотелось бы видеть реализацию какой-нибудь CRUD задачи, когда нужно >обновить некую сущность в соответствии с какими-нибудь бизнес правилами.
Например:
https://git.codemonsters.team/guides/ddd-code-toolkit/src/branch/dev/src/main/kotlin/team/codemonsters/ddd/toolkit/domain/subscriberDataUpdate/SubscriberDataUpdate.kt#L3
мы работает с обновлением абонента и данный класс Aggregate исполняет свою цель - порождает запрос на обновление абонента, который передается по пайпу далее в точку входа изменения абонента.
Точка входа изменения абонента - сама по себе может быть как простой задачей, так и сложной - можно передать в DataBase Adapter или запустить процесс обновления в сервисе subscribers.
Т.е. пример приложения в целом покрывает умную update crUd операцию.
Например: при создании заказа нужно проверить, что средств хватает, сохранить выбранные строчки корзины в заготовку заказа, поставить в очередь задачу на отправку письма о созданом заказе, поставить в очередь задачу на дальнейшую обработку заготовки заказа, удалить строки из корзины.
само по себе обновление сущности абонента уже более сложное:
тут вызов
вызывается сервис subscribers
где запускается процесс обновления абонента по бизнес-правилам и там несколько сущностей обновить нужно, одну добавить.
Что самое важное: код там подобен примеру, просто чуть больше шагов и есть развилки. Я не стал специально усложнять этот пример - показал основные кирпичики.
Если инженер начнет экспериментировать с этой историей - он уже на конкретном примере начнет ощущать, на сколько она хороша.
В дальшейшем я планирую запустить один эксперимент, который наглядно демонстрирует насколько эта идея круто работает от фронта до бэка. Если вам будет интересно следить за обновлениями по теме - я скину линк на телеграм канал.
Надеюсь я ответил на ваши вопросы, если что-то не понятно - пишите.
Как я делал внутренний cookbook по тому, как писать код (и результат можно скачать)