Обчислені цінності та прості читання - гострий біль для моїх дизайнів, керованих доменом!


9

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

Приклад:

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

У простому сценарії все працює чудово: служба відправляє вирази підкачки та сортування на РЕПО, а репо видає ефективний запит до БД.

Однак все розпадається, коли мені потрібно сортувати значення, створені в пам'яті з моєї моделі домену. Наприклад, у класі Product є метод IsExpired (), який повертає bool на основі бізнес-логіки. Тепер я не можу сортувати та розміщувати сторінки на рівні репо - це все було б зроблено в пам'яті (неефективно), і моя служба повинна знати тонкощі, коли видавати ці параметри репо і коли виконувати сортування / пейджінг себе.

Єдиний зразок, який, здається, має сенс для мене, - це зберігати стан сутності у db (зробити IsExpired () полем для читання та оновлювати його за допомогою логіки домену перед збереженням). Якщо я розділяю цю логіку на окремий сховище "читати модель / dto" та "звітування", я роблю свою модель більш анемічною, ніж мені хотілося б.

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

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

Відповіді:


3

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

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

Використовуючи модель доменної моделі, Уді Дахан

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

Виявляється, розробники часто беруть на себе більш жорсткі вимоги, ніж справді потрібно бізнесу. Рішення про використання об'єктів доменної моделі для показу інформації користувачеві є саме таким прикладом.

[...]

Для тих, хто достатньо старший, щоб пам'ятати, найкращі практики використання COM + керували нами для створення окремих компонентів для логіки лише для читання та для логіки читання-запису. Десятиліття потому ми з такими новими технологіями, як Entity Framework, але ті самі принципи продовжують діяти.

CQRS з акторами Akka та моделями функціональних доменів, Debasish Ghosh

Грег Янг виступив із чудовими сесіями щодо DDD та CQRS. У 2008 році він сказав, що "єдина модель не може бути придатною для звітування, пошуку та транзакційної поведінки". У нас є щонайменше дві моделі - одна, яка обробляє команди та подає зміни до іншої моделі, яка обслуговує запити та звіти користувача. Трансакційна поведінка програми виконується за допомогою багатодоменної моделі агрегатів і сховищ, тоді як запити подаються безпосередньо з денормованої моделі даних.

CQRS, Мартін Фаулер

Зміна, яку вводить CQRS, полягає в тому, щоб розділити цю концептуальну модель на окремі моделі для оновлення та відображення, які вона посилається як Command та Query відповідно відповідно до словника CommandQuerySeparation. Обґрунтування полягає в тому, що для багатьох проблем, особливо у більш складних областях, однакова концептуальна модель для команд і запитів призводить до більш складної моделі, яка не справляється і з цим.

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


2

СПЕЦИФІКАЦІЯ

Я знаю, що ви вже прийняли відповідь, але ви запитали про DDD, і точну відповідність цьому називає Еванс "специфікацією":
пряме посилання на книги Google,
якщо це посилання не працює, перевірте книгу в цих результатах
Це сторінка 226, якщо у вас є книга.

На сторінці 227 є 3 використання для специфікацій: Перевірка, Виділення, Створення нового спеціального об'єкта. Ваш "вибір" - IsExpired.

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

У простому світі це означатиме розміщення версії SQL у вашому сховищі та версії об’єктів у вашій моделі, звичайно, яка має недоліки. Логіка в двох місцях (погано, хтось забуде оновити ці місця), і у вашому сховищі є логіка домену.

Таким чином, відповідь полягає в тому, щоб поставити обидва набори логіки в специфікацію. Версія в пам'яті, очевидно, але версія сховища теж. Якщо ви використовуєте, наприклад, n-hibernate, ви можете використовувати вбудовану мову запитів для версії сховища.

В іншому випадку вам доведеться створити спеціальний метод репозиторію для цієї специфікації, який використовується з об'єкта специфікації. Виклики колекціонерів об'єктів, що відповідають специфікації, проходили б через специфікацію, а не сховище. І принаймні код кричить "я в двох місцях, не забувайте про це" майбутнім виконавцям. На сторінці 231-232 є чудовий приклад для вирішення дуже подібної проблеми.

Специфікація - це "дозволений" витік / пробуксування "чистоти" DDD. Він все ще може не задовольняти ваші потреби для різних цілей. Наприклад, ORM може генерувати поганий SQL; може бути занадто багато додаткового кодування. Тож вам, можливо, доведеться викликати методи сховища таким чином, що це майже як введення SQL у специфікацію. Погано, звичайно. Але не забувайте, що ваша програма повинна працювати з розумною швидкістю. Він не повинен виграти приз за чистоту DDD. Тож реальність перемикання сховищ даних може означати старомодне хірургічне втручання програми. Також погана річ. Але не так погано, як повільна (інакше SUCKing) програма. Якщо закінчення коробки в різних БД є реальністю, очевидно, ви будете дублювати бізнес-правила для кожного сховища даних для кожної специфікації. Принаймні, у вас є палець з цього питання, і ви можете скористатися схемою стратегії під час обміну сховищами. Але якщо ви використовуєте певну БД, вже пам’ятайтеЯГНІ.

Що стосується CQRS: Цитата Фоулера від pdr вище досі справедлива: "наявність однакової концептуальної моделі для команд і запитів призводить до більш складної моделі, яка не працює ні", і вам може знадобитися використовувати CQRS або подібне. Але це значно дорожче з точки зору розвитку та обслуговування. Якщо ви постачальник пакетів, конкуруючи з іншими, це може платити. Якщо ви пишете спеціальний додаток LOB для одного клієнта, зйомка для досконалості - це поганий вибір. Вам потрібно визначитися, чи варто мати цілком або здебільшого подвійну модель додаткових зусиль. Специфікаціяє хорошим компромісом, оскільки він дозволяє здійснити це розділення лише в одній невеликій частині програми, яка потребує цього, зі швидкістю (розробкою) швидкості та простоти однієї моделі. Удачі!


Це має ідеальний сенс. Я думаю, що мені потрібно кусати кулю і читати книгу Еванса :-) Зараз я бачу, що неглибоке розуміння цих понять може нас справді паралізувати!
drogon

0

Я думаю, я б поставив під сумнів, що це за бізнес-логіка, яка визначає, чи є ExEpired правдивим чи ні. Чи може ця логіка виконуватись запитом, коли стоїть модель даних? Якщо так, чи можете ви зробити свій сховище досить розумним, щоб використовувати логіку "isExpired", коли ви запитуєте його на Продукти певним чином? Якщо ні, можливо, вам доведеться переглянути свою модель даних.

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

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