Как стать автором
Обновить
13
0
Максим Морев @maxmorev

Software Craftsmanship энтузиаст

Отправить сообщение

Кайф, Ваня. Спасибо!

Умеешь ты развлекаться!

Хотел все Linux поставить на планш, ты напомнил. +1 к моим развлечениям )

Спасибо за статью, хорошо и понятно описывает базовые принципы!

Буду рекомендовать падаванам!

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

А это видно в примере? Я вот пытаюсь понять в чём и где профит по >сравнению с обычное анемичной моделью и до меня не доходит.

Чтобы ответить на ваш вопрос я приведу некоторые недостатки Слабой доменной модели:
- Инкапсуляция нарушена
- Приводит всегда к Дублированию бизнес-логики
- Невозможно гарантировать, что объекты в модели находятся в согласованном состоянии
- всегда способствует разрыву и непониманию между разработкой и бизнесом

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

чем плохо слияние с интеграцией?

- тем что тестирование бизнес-логики возможно только моками

Также рекомендую прочитать про этот анти-паттерн у Martin Fowler -> https://www.martinfowler.com/bliki/AnemicDomainModel.html

Преимущества Сильной доменной модели по Type Driven:

- бизнес-логика ограничений и поведения собрана в одном месте 

   - легко поддерживать, развивать, изучать

- Эта логика направляет и контролирует создание, проверку и управление сущностью, предотвращая появление у клиента сущностей с несогласованным состоянием сразу в одном месте

- код превращается в документацию

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

- в самом ядре бизнес-логика инвариантов описана по паттерну ValueObject's, например: SubscriberId - сразу контролирует свое возникновение и описывает ограничения на свое появление.

https://git.codemonsters.team/guides/ddd-code-toolkit/src/branch/dev/src/main/kotlin/team/codemonsters/ddd/toolkit/domain/subscriberDataUpdate/SubscriberId.kt

https://git.codemonsters.team/guides/ddd-code-toolkit/src/branch/dev/src/test/kotlin/team/codemonsters/ddd/toolkit/domain/subscriberDataUpdate/SubscriberIdTest.kt

- такое ядро максимально удобно тестировать юнит тестами - тестируем выходные данные функции -  а это самый эффективный тест

Допустим у меня уже есть единый язык и 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 операцию.

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

само по себе обновление сущности абонента уже более сложное: 
тут вызов

https://git.codemonsters.team/guides/ddd-code-toolkit/src/branch/dev/src/main/kotlin/team/codemonsters/ddd/toolkit/domain/subscriberDataUpdate/SubscriberDataUpdateService.kt#L61

вызывается сервис subscribers

где запускается процесс обновления абонента по бизнес-правилам и там несколько сущностей обновить нужно, одну добавить. 

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

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

Надеюсь я ответил на ваши вопросы, если что-то не понятно - пишите.

Добрый день, спасибо за обратную связь!

Да, в целом, вы верно поняли мысль.

Вместо размазывания БЛ мы помещаем ее в объекты бизнес логики Entity, Aggregate. В примере исходных кодов я использую подход функциональной мутации имутабильных объектов (DDD made functional), в результате которого на выходе мы получаем запрос на изменение в Aggregate.

Важно обратить внимание на Type Driven Development при дизайне ValueObject-ов — это основной кирпичик + R.O.P. Строим на этом фундаменте вместе с unit тестами.

SOLID Мартина не заставляет, но единая ответственность может быть воспринята неоднозначно, что приводит к чрезмерной единой ответственности — 1 класс : 1 метод.

Запрос на изменение можно отправить-преобразовать в команду — дальше можно развивать историю и там дальше на пути встретимся с ивентами.

Я сделаю статью с примером по кукбуку - из исходников много можно будет чего вынести.
Также сделаю более подробные остановки на каждом пункте кукбука. В JPoint - была проба пера и я после этой записи много улучшений привнес.
Благодарю за обратную связь!

спасибо, и вариант названия мне нравится)

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

Информация

В рейтинге
Не участвует
Работает в
Зарегистрирован
Активность

Специализация

Fullstack Developer, Project Manager
Senior
Linux
PostgreSQL
SQL
MySQL
Docker
Database
Java Spring Framework
Kubernetes
CI/CD
OOP