Применение DDD к базе данных Northwind

Я хотел бы выполнить некоторые упражнения и применить DDD к моей модели предметной области, применяемой к базе данных Northwind. Даже если Northwind является примером, я полагаю, что это было сделано для удовлетворения некоторых требований «виртуального бизнеса». Таким образом, цель состоит в том, чтобы иметь модель предметной области, которая соблюдает DDD, а данные хранятся в базе данных Northiwnd.

Рассмотрим эту модель сохранения EF:

alt text
(источник: developpeur .org)

Обратите внимание, что у нас есть только сущности и двусторонние отношения. Я хотел бы иметь настоящий DM, уважающий DDD. Более того, моя модель DM не обязательно должна быть зеркалом моей базы данных.

  1. Как бы вы изменили отношения, чтобы иметь только односторонние отношения или двусторонние отношения, когда это необходимо.

  2. Существуют ли отношения «многие к одному» или «один ко многим», которые можно было бы изменить на «один к одному»?

  3. Как бы вы моделировали агрегаты?

  4. Как насчет объектов, услуг и фабрик, если это необходимо?

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

Не стесняйтесь спрашивать подробности, если мой вопрос не ясен.

Заранее спасибо.


person Tomasz Jaskuλa    schedule 04.03.2010    source источник


Ответы (1)


В общем, у меня возникает соблазн ответить Mu (в дзенском смысле), потому что сценарий неверен с точки зрения DDD. В DDD мы начинаем с бизнес-требований и экспертов предметной области, и на их основе мы получаем модель предметной области.

Хотя это спорный момент, база данных является почти случайным артефактом бизнес-требований (которые почти всегда утверждают, что сущности должны быть сохранены).

Тем не менее, я постараюсь сделать все возможное.

В большинстве случаев заказ является довольно важным бизнес-объектом, и, очевидно, нам нужно знать о строках заказа, включая продукты в каждой строке, поэтому может показаться, что нам нужна связь от строки заказа (Order_Detail) к продукту.

Однако, когда нам дают конкретный продукт, нам редко нужно знать, в какие заказы он был включен, так что это сразу предполагает одностороннюю связь. Мы можем переходить от строки заказа к продукту, но не от продукта к строке заказа.

Однако приведенный выше анализ может оказаться ложным на более глубоком уровне. Представьте себе следующий разговор между разработчиком и экспертом в предметной области:

Разработчик: Мы создали эту связь между заказами и продуктами, чтобы всегда знать все о продуктах в конкретном заказе.

Exp: Звучит неплохо, но как насчет поставщика?

Разработчик: Это тоже включено.

Exp: Что происходит, когда мы меняем поставщика продукта?

Разработчик: Это будет неявно отражено и в данных заказа...

Пояснение: Это не то, что нам нужно. Мы хотим, чтобы данные отражали заказ на момент его отправки.

В этом случае оказывается, что на самом деле есть ошибка в схеме базы данных. Проблема может быть вызвана отчетностью, потому что бизнес-аналитики могут захотеть запустить отчеты о том, как разные поставщики влияют на прибыль (что я знаю).

В таком случае можно предположить, что ассоциацию со строками заказов следует полностью свести к продукту. Заказы должны содержать исторические (моментальные) данные о продуктах, а не текущие данные о продуктах.

Мы можем даже ввести ProductSnapshot Объект-значение, который семантически отражает Product Сущность, чтобы смоделировать это в модели предметной области.

В целом кажется все более и более разумным моделировать Order как совокупность самого себя и строк заказов (с ProductSnapShots), но как насчет отношений между заказами и клиентами?

Насколько я понимаю ассоциации и агрегаты, ассоциации определяют агрегаты. Учитывая заказ, хотели бы мы знать о клиенте? Вероятно. Учитывая клиента, вы хотели бы знать о заказах? Наверное.

Это предполагает двустороннюю связь, которая делает Customer агрегированным корнем. Это означает, что у вас будет CustomerRepository, но не OrderRepository. Каждый раз, когда вам нужен Орден, вы должны получить его через Customer.

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

Вы также можете рассмотреть возможность создания OrderRepository, но это вторгается в совокупный корень Customer. Если вы это сделаете, станет неясно, на ком лежит ответственность за Орден. Что произойдет, если вы перейдете от заказа к клиенту? Customer есть список Приказов, но все ли они заполняются в памяти, если вы читаете Приказ из OrderRepository?

Вероятно, нет, но они, вероятно, будут, если вы прочитаете Заказчика из CustomerRepository. Дело в том, что анализ агрегированных корней важен, и как только вы определили агрегат, вам придется придерживаться его и уважать.

Из-за этого я предпочитаю маленькие агрегаты большим агрегатам, поэтому в этом примере я бы ограничил агрегат до Order и его строк заказа и не имел связи между Order и Customer.

Отсутствие формальной связи между Order и Customer не означает, что мы вообще не можем связать их, но нам нужны явные услуги, чтобы получать все Заказы для данного Клиента. Мы не можем просто переходить от одного к другому.

person Mark Seemann    schedule 05.03.2010
comment
Пример не лучший. Очевидно, что база данных Northwind создавалась с учетом реляционных данных. Как вы сказали, мы не знаем требований, которые были в начале этой базы данных. Но ваш анализ очень хороший и подробный. Он показывает, как следует мыслить и моделировать DM. Спасибо за ваше время и подробный ответ. - person Tomasz Jaskuλa; 05.03.2010