Підхід DDD до основних операцій CRUD у складному доменно-орієнтованому застосуванні


9

Моя компанія переписує нашу веб-програму з нуля. Це велика програма на рівні підприємств зі складною областю у фінансовій галузі.

Ми використовуємо ORM (Entity Framework) для збереження.

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

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

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

Після того, як користувач натискає "Готово" на екрані інвестиційного рахунку, і POST робиться для контролера, тепер контролер має майже точне представлення в базі даних інвестиційного рахунку, яке потрібно зберегти. Але чомусь я повинен завантажувати представлення домену для внесення змін, а не просто відображати модель контролера безпосередньо на модель бази даних (Entity Framework model)?

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

Відповіді:


9

Добре, уявіть, ви реалізуєте сторінку створення свого облікового запису, зіставляючи публікацію форми безпосередньо на об'єкт EF, який потім зберігається в db.

Давайте припустимо, що база даних має різні обмеження, які запобігають введенню абсолютно неправильних даних. У акаунтах завжди є клієнти тощо.

Здається, все працює нормально. Але тоді бізнес приймає нове правило.

  • Рахунки, створені у четвер, отримують бонусну процентну ставку у розмірі 2%. (припустимо, що процентна ставка є одним із полів рахунку)

Тепер ви повинні десь покласти цю логіку, і у вас немає об’єкта домену, щоб поставити її.

DDD припускає, що у вас завжди будуть такі правила, і ви, мабуть, так і робите. Створення облікового запису повинно мати різні чеки, журнал аудиту тощо. Це не буде просто "записом рядка в db"

Плануйте свій домен, припускаючи, що немає стійкості або контролерів MVC із зайвою логікою. Переконайтеся, що ви захоплюєте всі вимоги, і всі вони є у доменній моделі.


3
Це хороший спосіб викласти це. Я ненавиджу пошук правил бізнесу, змішаних з деталями БД. +1
candied_orange

Хороші моменти, але що робити, якщо ці правила перевірки застосовуються лише під час створення та оновлення входів користувача? Після того, як ми маємо введення даних користувача, модель, яка створюється при виконанні обчислень, є зовсім іншою моделлю. Чи повинні ми мати дві доменні моделі для інвестиційного рахунку? Один для операцій CRUD з необробленими входами для користувача та інший для тих випадків, коли ці входи використовуються для створення доменної моделі, що використовується в обчисленнях?
wired_in

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

Уявіть складний двигун розрахунку. Один із вхідних даних, необхідних для здійснення обчислень, - це інвестиційний рахунок, але весь інвестиційний рахунок для калькуляційного механізму - це потік доходу протягом певного періоду часу. Ця доменна модель інвестиційного рахунку повністю відрізняється від сировинних входів, які користувач ввів для цього інвестиційного рахунку. Однак, коли користувач вводить основні входи, такі як Ім'я, Поточне значення тощо, все ще має бути логікою перевірки, але це не повинно мати нічого спільного з моделлю, яку використовує двигун calc. Отже, чи є тут дві доменні моделі для інвестиційного рахунку?
wired_in

..... або, можливо, модель інвестиційного рахунку в домені є надмірною для операцій CRUD, і просто повинні бути використані якісь атрибути валідатора або щось таке
wired_in

7

Як це має сенс?

Коротка відповідь: це не так .

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

Уді Дахан мав цікаве спостереження, яке може допомогти з’ясувати це

Дахан вважає, що сервіс повинен мати як певний функціонал, так і деякі дані. Якщо у нього немає даних, то це лише функція. Якщо все, що він робить, це виконання операцій CRUD над даними, то це база даних.

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

Якщо ви маєте справу з системою CRUD, зазвичай ви не є системою запису даних. Реальний світ книга запису, і база даних тільки локально кешувати подання про реальний світ.

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

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

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

Це правильно для випадку, коли база даних - це книга записів .

Уарзі висловився так .

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

Додаток можна вважати CRUD лише в тому випадку, якщо навколо моделі даних немає ділової логіки. Навіть у цьому (рідкісному) випадку модель даних - це не ваша модель домену. Це просто означає, що, оскільки жодна бізнес-логіка не задіяна, нам не потрібна абстракція для управління нею, і тому ми не маємо доменної моделі.

Ми використовуємо модель домену для управління даними, що належать всередині домену; дані за межами домену вже керуються десь ще - ми просто кешуємо копію.

Грег Янг використовує складські системи як основну ілюстрацію рішень, де запис записів знаходиться десь в іншому місці (тобто: підлогу складу). Реалізація, яку він описує, дуже схожа на вашу - одна логічна база даних для захоплення повідомлень, отриманих зі складу, а потім окрема логічна база даних, кешуючи висновки, зроблені з аналізу цих повідомлень.

То, може, ми маємо тут два обмежених контексту? Кожен з іншою моделлю дляinvestment account

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

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

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


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

Я просто повернувся до цього через кілька років, і ваш коментар резонує зараз більше, ніж раніше чомусь. Тут є багато хороших речей, але ви могли б пояснити одне для мене? Ви сказали: "Основою доменної моделі, зрештою, є забезпечення того, щоб усі оновлення даних підтримували поточний бізнес-інваріант". Це стосується частини нашої програми, яка зберігає / оновлює інформацію. Інша частина - це просто двигун розрахунку. Він приймає представлені дані як вхідні дані та викладає результати. Це тоді не є частиною доменної моделі? Оскільки це не впливає на збережені дані?
wired_in

2

У вашому домені ви не повинні знати, що база даних навіть існує.

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

Деталі бази даних існують і їх потрібно вирішувати. Вони повинні жити деінде. Поставте їх через межу. Ретельно контролюйте, як ви спілкуєтесь через цю межу чи це не межа.

Дядько Боб має сказати про те, що потрібно вносити ваші дані:

Зазвичай дані, що перетинають межі, - це прості структури даних. Якщо ви хочете, ви можете використовувати основні структури або прості об’єкти передачі даних. Або дані можуть бути просто аргументами у викликах функцій. Або ви можете упакувати його в хешмап або сконструювати в об'єкт.

Важливим є те, що ізольовані, прості структури даних передаються через межі. Ми не хочемо обманювати та передавати рядки Entities або Database. Ми не хочемо, щоб структури даних мали будь-яку залежність, яка б порушувала правило Dependency.

[…] Коли ми передаємо дані через межу, це завжди у формі, найбільш зручній для внутрішнього кола.

Чиста архітектура

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

Чистий аркуш шпаргалки

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

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


Ми використовуємо ORM (Entity Framework), тому наша база даних вже відібрана, але моделей даних (клас Entity Framework), природно, є майже 1 до 1 з таблицями баз даних. Проблема полягає в тому, що в деяких частинах нашого додатку користувач по суті просто оновлює модель даних (на екрані - це лише список текстових полів, де кожне текстове поле є полем у базі даних (модель даних).
wired_in

Тому я не бачу причини не просто використовувати представлення необроблених даних (модель даних) під час виконання операцій CRUD. У нас є складне представлення домену, яке використовується для розрахунків. Це я вважаю нашою моделлю домену, але я не розумію, чому я б завантажував цю картину в частину нашої програми CRUD.
wired_in

Визначте, що ви маєте на увазі під «використанням представлень необроблених даних». Дані вводяться, дані перевіряються відповідно до правил домену, дані зберігаються якось, дані розраховуються проти, результати виводяться на будь-які. Я щось пропускаю?
candied_orange

Я намагаюся сказати, що необроблені дані, які ми отримуємо від користувача для інвестиційного рахунку, - це не те, як ми представляємо цей інвестиційний рахунок в основних частинах нашого додатку, як, наприклад, коли він використовується для calcs. Наприклад, у нас може бути булевий вхід, який ми зберігаємо в базі даних під назвою IsManagedAccount. Користувач надає нам це за допомогою перемикача на екрані редагування. Таким чином, представлення з бази даних вниз на екрані становить від 1 до 1. Коли ми будуємо свою доменну модель пізніше в додатку, у нас може бути клас ManagedAccount, таким чином, не буде булевого властивості. Дві структури сильно відрізняються.
wired_in

Отже, коли користувач просто редагує необроблені введення на екрані редагування, чому я завантажую зображення домену, а потім додаю велику складність, щоб якось відобразити сильно набраний клас ManagedAccount назад до плоского представлення, що є лише одним класом з IsManagedAccount майно?
wired_in

1

Застосування теорії DDD:

У цьому домені є два обмежені контексти:

  • Розрахунки інвестиційного рахунку. Математична модель інвестиційного рахунку є одним із елементів, можливо, сукупності.
  • Основні фінанси. Клієнтський інвестиційний рахунок є одним із Суб'єктів.

Кожен обмежений контекст може мати різний архітектурний дизайн.

Приклад:

Клієнтський інвестиційний рахунок є суб'єктом господарювання (можливо, агрегатом, залежить від домену), і збереження даних здійснюється через сховище суб'єкта господарювання (RDB або інший тип БД, як база даних OO).

Не існує підходу DDD до операцій CRUD. Щоб поле БД було прив'язане до даних об'єкта, порушує принципи проектування.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.