Знову про розробку на основі предметної області (Domain-Driven Design, DDD)

Введення

Занадто багато разів я зустрічав програми, про яких говорили, що у них є модель предметної області та додаток було спроектовано на основі це предметної області. Проте в дійсності все, що я бачив, було колекцією сутностей (я б навіть сказав DTO), мають купу властивостей без якої б то не було реальної логіки, пов'язаної з сутністю. Крім того, я можу знайти багато сервісів всіх видів, які містять барвисту суміш бізнес-логіки та/або інфраструктури. Якщо додаток ж використовує шину повідомлень (як NServiceBus, Mass Transit Bus або Azure Bus), то звичайно ж помітно, що якісь повідомлення передаються від одного модуля до іншого або кількох модулів. На жаль, листи часто мають дуже узагальнені назви, що містять слова «оновити», «змінити», «додати» або «видалити», і несуть велику кількість корисної навантаження — десятки різноманітних властивостей. Часто з назви повідомлення зовсім не очевидно, чи є воно командою або подією, і щоб визначити це, доводиться глибоко заритися в реалізацію.

Я щиро хотів би, щоб все написане вище було би перебільшенням або ж мало сенс тільки для «старих» програм, які розрослися і вийшли з-під контролю. Але сумна істина в тому, що це відноситься до багатьох нових проектів, навіть тим, яким лише кілька місяців від народження. Чому так відбувається? Звичайно, є багато різних причин: відсутність знань є однією з найбільш важливих.

DDD — Що важливо?

Коли ми хочемо створити новий додаток, в ідеалі з нуля, і ми хочемо застосувати DDD, то нам треба враховувати ось що: не все, що було написано у синій книзі, в рівній мірі важливо. На жаль, перші 14 голів або близько того описують деталі реалізації, що мають більше спільного з хорошим об'єктно-орієнтованого програмування і не стільки з проектуванням на основі предметної області. Останні кілька розділів книги містять дуже цікаві речі, але багато розробники не дочитують так далеко, і вже розпочали роботу над реалізацією своїх програм.

У пошуках єдиної мови

Коли ми починаємо новий проект, то ми повинні спочатку спробувати по-справжньому зрозуміти предметну область бізнесу, для якого ми будуємо додаток. Нам потрібно поговорити з зацікавленими особами та експертами в галузі (так, найчастіше це представники клієнта, для якого ми створюємо програмне забезпечення) і спробувати зрозуміти їхню мову. Нам треба уважно слухати, що вони говорять і як вони говорять. Чи користуються вони певними словами, які зрозумілі та використовуються таким же чином всіма, працюють у цій предметної області? Є сенс цих слів однозначним? Якщо ні, то ми повинні ставити питання і вимагати від експертів більш докладного опису їх термінології, або зміни формулювань, або навіть використовувати якісь аналогії. Одна з моїх улюблених «ігор» — це запитати експертів про те, як би вони робили свої завдання в відсутність комп'ютера. Що буде діями, а що об'єктами, предметами, концепціями або іменниками?

З часом (так, це може зайняти кілька днів або тижнів, щоб зробити це правильно), ми будемо мати загальний словник, зрозумілий всім зацікавленим сторонам, експертів у предметній області, бізнес-аналітикам, архітекторам, розробникам і тестерам. Ми будемо називати цей словник або «мова» «єдиною мовою».

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

Розділяючи складну проблему

Після того, як ми знайшли або визначили єдиний мову предметної області, ми можемо почати моделювати домен. Але набагато частіше предметна область бізнесу, для якого ми збираємося написати програмне забезпечення, є досить складною, щоб зрозуміти все відразу і/або легко упустити щось важливе. Таким чином, ми повинні почати розділяти всю складну область менші частини меншої складності. Це той самий підхід, що і під час їжі — ми не в змозі проковтнути весь стейк відразу, але можемо розрізати його на шматки, а потім з'їсти один шматок за іншим.

Ми можемо зробити так з кожною предметною областю. З допомогою експертів необхідно визначити під-домени, або області, які ми можемо ізолювати один від одного і подивитися на них окремо, щоб вирішити їх окремо. Ми називаємо ці під-домени обмеженими контекстами (прим. пер. — bound contexts). Обмежений контекст — це частина всієї предметної області, що має чіткі межі, взаємодіюча через чітко визначені інтерфейси з іншими обмеженими контекстами і яка може бути визначена індивідуально.

Визначення інтерфейсів і контрактів

Тепер, коли ми розділили складний бізнес домен на більш дрібні і менш складні обмежені контексти, нам треба подумати про те, як ці контексти повинні взаємодіяти один з одним. Кожен обмежений контекст зовні повинен виглядати як чорний ящик. Деталі реалізації не повинні мати значення, якщо я не є частиною цього контексту. Взаємодія з обмеженим контекстом відбувається з допомогою добре визначених інтерфейсів, використовуючи ретельно розроблені контракти. Ще раз — це чудово поєднується з нашим досвідом в реальному світі. Якщо я хочу мати справу зі страховою компанією, тоді обидві сторони, я і страхова компанія, повинні домовитися про деяких контрактах. Контракти докладно описують нашу взаємодію, в них немає неясності.

Після того як контракт створений і підписаний обома сторонами, його вже важко змінити: це можливо зробити, але доведеться докласти зусилля. Точно так само ми повинні думати при визначенні інтерфейсів і контрактів для наших обмежених контекстів. Контракти — це повідомлення (команди та події), якими обмінюються контексти. Саме тут ім'я та вміст контракту мають значення. Ім'я визначає контекст команди або події, а вміст — різницю в даних, необхідну для переходу з одного стану в інший.

Ми повинні чітко розрізняти команди і події. Команда завжди має тільки одну мету. Мета команди може або прийняти, або відхилити команду. Результатом виконання команди, як правило, є зміна в системі. Було зроблено щось, що змінило стан моделі. З іншого боку, подія може мати від нуля до декількох передплатників. Так, це вірно, що події можуть бути проігноровані… але події ніколи не можуть бути відхилені, оскільки вони повідомляють нам про те, що вже відбулося. Щоб чітко відрізняти команди від подій, ми повинні використовувати імперативні імена для команд; події ж повинні називатися в минулому часі. Імена повинні використовувати створений нами єдиний мову.

Чого ми повинні уникати DDD

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

Будувати додаток тільки навколо даних
У минулому більшість бізнес-додатків були орієнтовані на дані. В першу чергу архітектори та інженери створювали схему даних, а все інше було за нею. Люди говорили"… в кінці дня, тільки дані мають сенс… Дані, які ми збираємо — наша цінність. Програми, які збирають та/або використовують дані з'являються і зникають, але самі дані залишаються… ". І хоча дані залишаються, просто неправильно стверджувати, що дані — це все, що має значення! Дані самі по собі не мають сенсу. Окремо дані лежать мертвим вантажем і тільки логіка надає їм сенс. І одні і ті ж дані мають різне значення в різних контекстах. Таким чином, ми завжди повинні починати з контексту і логіки.

Точка зору, що дані — це головна цінність — призводить до того, що бази даних часто використовуються в якості точки інтеграції. Багато різні програми використовують одну і ту ж БД. Це призводить до безлічі проблем у довгостроковій перспективі. Щоб дати вам хорошу аналогію, того, про що я кажу, давайте уявимо, що у мене є гаманець з грошима в кишені. Тепер мій друг витратився і хоче запозичити 10 доларів. Як наш світ працює в цьому випадку? а) один ввічливо просить мене позичити 10 баксів, і я відкриваю свій гаманець, щоб передати йому гроші або б) один дістає мій гаманець з моєї кишені (я не помічаю цього), і забирає 10 $ купюру з нього. Таким чином: ніколи не використовуйте базу даних, як точку інтеграції в бізнес-додатках.

Коли я розробляю додаток, ERD (ER-модель даних — прим.пер.) є однією з найменш важливих речей для мене. Я не дозволяю собі і моделі моєї предметної області бути підконтрольними сховища даних або моделі даних. Для мене бізнес-додаток не означає автоматично, що я повинен використовувати СУБД, і що моя модель даних повинна бути в 3-й нормальній формі!

Говорити про деталі реалізації
Головна ідея DDD не в сутності, сервісах, застосування фабрики або репозиторію. Це все деталі реалізації. Вони не мають ніякого реального сенсу поки ми не зробили домашнє завдання і визначили єдиний мову, обмежені контексти, а також інтерфейси і контракти. Якщо ми почнемо займатися реалізацією занадто рано, то в результаті отримаємо анемічну модель, що складається з колекції DTOs, оточених великою кількістю сервісів і розмазаний всюди бізнес-логіки.
Використовувати технічний шум
У нашому додатку ми ніколи не повинні використовувати поняття або слова на кшталт save, update, insert, delete, handle, manage. Це або дуже технічні терміни або абстрактні поняття, не мають конкретного змісту. Якщо у мене є збереження, то одна з перших речей, які я роблю — це прибираю кнопку «Зберегти» з інтерфейсу програми. Збереження — не бізнес-концепція. Уявіть собі світ без комп'ютерів — використовують реальні люди висловлювання на кшталт "..., дозвольте мені зберегти це ..." (одне виключення — це збереження грошей на банківському рахунку). Крім того, в реальному бізнесі, ми ніколи не застосовуємо слова «Видалити» або «Додати» або «Оновити» до чого-небудь. Хіба ми видаляємо працівника, коли він більше не потрібен компанії?

Дуже загальні терміни, як «менеджер» необхідно також уникати. Що робить менеджер? Що значить «управляє»? Ні, ні, будь ласка, дайте нам більше контексту!

Транзакції БД
Хоча транзакції БД — це хороша річ, не варто зловживати ними. Бізнес-транзакції є набагато більш важливими, ніж транзакції БД. Незважаючи на те, що за визначенням, транзакції БД повністю цілісні (і виконуються швидко), бізнес-транзакції такими не є. Приклад бізнес-транзакції, з якою ви всі ймовірно добре знайомі — те, що відбувається в Starbucks, коли вранці ви замовляєте улюблений кави. Це «довгий» процес з багатьма можливо «суперечливими» проміжними станами і асинхронними завданнями. Тим не менш, все це працює, масштабується і широко прийняте всіма.

Таким чином, при моделюванні вашої предметної області за допомогою DDD, не думайте про транзакції БД (або ще гірше «розподілених транзакцій») взагалі. Думайте про можливі дії, їх результати і про сценарії скасування дії в разі невдачі. І ви побачите, що ви будете вирішувати головним чином бізнес-проблеми, а не боротися з технічними проблемами.

Висновок

Щоб успішно використовувати DDD треба зробити кілька речей дуже добре з самого початку: визначити загальний словник (єдиний мову), розділити загальну складну проблемну область у менші під-домени, звані обмеженими контекстами, і ретельно визначити межі та контракти, що використовуються між окремими обмеженими контекстами. З іншого боку, ми повинні уникати певних практик, які дуже часто використовуються розробниками програмного забезпечення: будувати додаток тільки навколо даних при моделюванні предметної області тільки навколо даних (без логіки); зосередження уваги на деталях реалізації (сутності, сервіси і т. д.) взамін основних концепцій, розглянутих вище; використання загальних і специфічних для розробників термінів і понять при реалізації програми; і, нарешті, переоцінці цінності транзакцій бази даних замість акцентування на бізнес-процесах або транзакціях.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.