Нащо нам ті домени/субдомени?

Чим більше я працюю з Domain Driven Design/Development і чим більше спілкуюсь з іншими архітекторами – тим більше мене відвертає від DDD. Справа у тому, що DDD досить складний для більшості проєктів, формулювання досить розмиті і яким чином DDD дозволяє досягти кращих результатів не зрозуміло.

Domain Driven Design занадто складний для більшості проєктів

Під занадто великою складністю для багатьох проєктів я маю на увазі те, що використання DDD підходу коштує значно більше, аніж переваги, які воно надає. Ви можете запитати: А де ж твої експериментальні дані?! А я тоді відповім: В спільноти DDD їх також немає, крім того, я звернуся до чудової аналогії чайника Рассела аби продемонструвати, що це спільнота DDD має доводити ефективність свого дітища, а не я його спростовувати. Та, більш того, мені здається, що подібного експерименту взагалі не можна провести.

Якщо я не можу впевнитися у тому, що якась практика робить моє життя кращим, то навіщо мені нею взагалі займатися?

Формулювання Domain Driven Design досить розмиті аби хоч щось значити

В DDD є домени (предметні області), піддомени та обмежені контексти (bounded contexts). Що воно таке – не дуже зрозуміло. Кожен, хто почав вивчати DDD запитує про те у чому різниця, а ті, хто вже трохі попрактикував їі щось відповідають, але ті відповіді також досить абстрактні та врешті решт не зрозуміло, що нам ці всі терміни дають.

Насправді ж мова йде про стару добру модуляризацію, яка існувала задовго до DDD і до якої DDD аж нічогісінько не додав, окрім шуму та можливості купити якийсь інфопродукт.

Що таке domain?

Домен або предметна область – це простір проблеми. Загалом певний бізнес і є доменом, тобто усі проблеми/завдання над якими працює бізнес – це його домен. Що нам надає цей термін? – Нічого. Ми можемо просто говорити “бізнес”. Так навіть краще, бо якщо замінити “domain model” на “business model”, то одразу отримаємо більше розуміння про що йде мова та, наприклад, що багато компаній не мають чіткої, формалізованої бізнес-моделі, яка постійно обговорюється та оновлюється. Якби бізнес займався цією важливою справою – не треба було б багато спілкуватися із експертами, бо все, що вони могли б надати – це посилання на документ із бізнес-моделлю.

В сталих бізнесах, які існують вже десятки років існують чітко прописані бізнес-моделі, але й вони час від часу змінюються. Якщо колись супермаркет займався роботою з асортиментом, вибором основних продуктів та “довгого хвоста”, плануванням закупівель, вивченням попиту, то зараз цим займаються лише або бідні підпріємці з будками у підземних переходах, або т.з. лакшері сегмент, де відомий власник самостійно подорожує по усьому світу і обирає найкращі вина, які він буде продавати у своєму магазині, бо все, що було до нього – лайно. Більшість же супермаркетів продають насправді не товари, а місця на полицях та сервіс для постачальників. Для людей же вони продають просто те, що вони знаходяться поруч та мають великий асортимент. Також супермаркети й будь-які інші “маркетплейси” отримують величезну купу даних про стан ринку і попит, що дозволяє їм створювати власні продукти та одразу відривати значну частину ринку. Якщо Ви продаєте щось на Amazon і воно успішне, то дуже скоро Amazon зробить більше вдалу та дешеву репліку зі своїм вбудованим шпигуном – Alexa. Щось я трохи відволікся…

Що таке subdomain?

Субдомен або підпредметна область (вкладена предметна область) – це частина домену, яка обмежена …

Існує два підходи до побудови бізнесу. Перший побудований на принципі “розділяй та володарюй”, який проявляється у тому, що компанія являє собою досить жорстку ієрархію з департаментами та чітко поділеними відповідальностями. Цей підхід ще можна назвати редукціоністським і він домінує (переважна більшість компаній схиляється саме у бік редукціонізму). Другий підхід – холічний. Він менш поширений та більше за все зустрічається у невеликих компаніях, де кожен займається майже усім.

У випадку із переважно редукціоністським підходом, субдомени визначаються структурою компанії та лінгвістично. А у випадку з холічним підходом, субдомени визначаються вийнятково лінгвістично. Тут варто зазначити, що лінгвістична складова вказує на те, що ми не слідуємо принцупу/-пам low-coupling/high-cohesion, які мають базуватися на логістиці даних. Ми тупо напихуємо в один субдомен усе, що стосується, наприклад обробки замовлень, а у інший усе, що стосується відправки і т.д. Загалом цей підхід схожий на патерн (анти-патерн) “Товста модель” у Ruby on Rails, де клас “моделі” може містити сотні, методів і мати тисячі строк коду. Але тут варто також зазначити, що субдомени відрізняються від bounded context’ів, про які мова піде трохи пізніше.

Субдомени в DDD також поділяють на основні (core), підтримуючі (supportive) та загальні (generic). Вони розрізняються за специфічністю та умовною значущістю для компанії. Такий поділ часто використовується великими компаніями аби віддати не ключові псубдомени на аутсорс.

Що таке обмежені контексти – Bounded context?

Якщо домен – це простір проблем, то обмежений контекст – це простір рішень. Визначення обмежений контекстів лежить вже на solution/software архітекторах, а не на експертах в предметних областях, enterprise architect, C*-levels.

Зазвичай один субдомен відображається на один обмежений контекст, але це не завжди так. Обмежені контексти можуть поєднувати у собі декілька (зазвичай два) судбомени. Багато т.з. “експертів” у мікросервісній архітектурі (deployment strategy) вважають, що мікросервіси необхідно відображати один до одного на обмежені контексти. Я з цим згодний, але виключно через саме визначення обмежений контекстів у DDD.

Якщо говорити не про мікросервіси (яких слід будь що уникати), а про більш-менш монолітну архітектуру, то обмеженим контекстам мають відповідати модулі вищого рівня. Модуль – це дуже абстрактне поняття, як і компонент, тому я хочу наголосити на модулях саме ВИЩОГО рівня.

Що саме входить, а що не входить до того чи іншого обмеженого контекста – справа смаку, адже немає чіткої рекомендації з їх визначення. Якщо використовувати термінологію DDD до того, як я працюю над власними проєктами, то можна сказати, що для мене обмежений контекст – визначається деяким інваріантом, чи декількома пов’язаними інваріантами.

Концепція інваріантів чудово поєднується з ідеєю про логістику даних. Також інваріанти є найсильнішим зв’язком. Якщо певного інваріанту стосується лише одна єдина взаємодія/endpoint, то обмежений контекст в мене буде представлений лише цим одним endpoint’ом.

Висновок по секції

Загалом, і без DDD більшість розробників якось так і працює. Вони створюють обмежені контексти, модульні та/або плагінні архітектури, якщо тільки розробники не зовсім новачки (мають умовний рівень strong middle або senior), а проєкт не зовсім простий.

DDD тут не дає нічого, окрім іменування деяких ефемерних речей, використання яких не можна назвати найкращим підходом до розробки.

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

Не зрозуміло чому та як Domain Driven Design працює, а просто виконувати якісь ритуали не хочеться

Domain Driven Design – це дизайн, який напрямляється предметною областю. Предметна область у ньому втілюється як domain model і ця модель предметної області вважається найбільш цінною частиною системи.

По-перше, як я вже вище зазначав, в нових предметних областях моделі можуть постійно змінюватися, та навіть у вже давно існуючих вони також переживають певних змін, принаймні раз у десятиріччя. При цьому купа артефактів за захардкожена модель предметної області роблять зміни досить складними та дорогими. Ми не можемо десь щось мінімально підправити, а нам необхідно переробляти значну частнину моделі, а також усе, що на неї зав’язано, а на неї зав’язано має бути майже усе. Навіть якщо ми скрізь використовували патерн Anti Corruption Layer, то все одно фронт робот дуже великий.

По-друге, оскільки ми організуємо код не згідно логістиці даних, то отримуємо далеко не найефективніше рішення.

По-трете, сама ідея виокремленої доменної моделі порушує Single Responsibility Pripciple. SRP порушується тому що елементи доменної моделі не мають єдиної відповідальності, якщо тільки обмежений контекст побудований не навколо інваріанту чи взагалі єдиної взаємодії (а так майже ніхто не робить і цього немає у DDD). Загалом код доменної моделі, принаймні окремих bounded context’ів являє собою спагетті. Замість великої кастрюлі спагетті-коду, з DDD ви отримуєте те саме спагетті, але розкидане по тарілкам. Вже краще, але можна ще набагато краще.

По-четверте, ідея виокремленої доменної моделі порушує Dependency Inversion Principle (як і Hexagonal, і Clean). Згідно DIP користувач має визначати інтерфейс і залежати від нього, а певна деталь має його реалізовувати. Наприклад, для веб-додатків, користувачем є людина – користувач браузера. Ця людина користується UI/UX, а вже UI/UX користується якимось API, або презентація рендериться на сервері. Коли ми заявляємо, що модель предметної області – це головне, то порушуємо DIP. Аби обійти це і в Clean Architecture і в Hexagonal і в DDD необхідно використовувати Anti Corruption Layer між UI/UX та бекендом. Подібна трансляція через ACL досить складна за значно погіршує ефективність.

Врешті решт, твердження про те, що модель предметної області – це найголовніше і вона має явно і виокремлено існувати в коді – об’єкт віри і не більше того. Я допускаю, що на деяких проєктах DDD має сенс, але я бачив лише те, як DDD переускладнює та сповільнює розробку.

Загальний висновок / рекомендації

Як на мене, програмне рішення має обслуговувати предметну/бізнес модель, а не реалізовавати її у собі. Якщо програмне рішення реалізує предметну/бізнес модель у собі, то ми маємо проблему її дублювання на рівні організації компанії та у коді програмних рішень, що її обслуговують. Всі зміни тепер треба робити обов’язково у двох місцях і у коді вони зачіпають багато чого.

Для прототипів, експериментів, MVP, proof of concept, та досить нових предметних областей / бізнес моделей DDD – абсолютно протипоказане, оскільки швидко щось перевірити не вийде.

Можна навіть сказати, що DDD певним чином конфліктує з Agile (якщо Вас це турбує), а також DDD є прикладом upfront архітектури.

Загалом моя рекомендація полягає у тому, що DDD – це не панацея і, навпаки, DDD, а особливо, організації по субдоменам слід уникати. Код має бути модульним, але модулі мають будувитися навколо інваріантів та взаємодій, а не навколо субдоменів чи відповідних їм DDD’шних обмежених контекстів.

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *