Как моделировать сущности, которые существуют во всех ограниченных контекстах и ​​являются центральной частью приложения?

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

  1. Управление персоналом
  2. покупка
  3. Архив
  4. Составление отчетов

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

Я буду использовать реализацию Udi Dahans простого шаблона CQRS. Я бы предпочел не использовать весь спектр источников событий, шины сообщений и т. Д., Поскольку это приложение не будет работать с большим количеством участников (менее 1000 пользователей, и они вряд ли будут редактировать один и тот же небольшой набор данных), и это добавить много ненужной сложности.

Итак, к вопросам:

Подразделения сотрудников и отделов являются общими для всех БК. Как это моделировать?

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

В закупочной БК товары приобретаются в отделе и доставляются в отдел. У поставщиков есть разные контракты с разными отделами.

В архиве некоторая информация будет заархивирована и привязана к отделу и так далее.

То же самое относится и к сотрудникам.

Как сохранить данные из ограниченного контекста?

Они могут быть сопоставлены с одной и той же базой данных или иметь свою собственную.

Некоторые мысли, которые я сделал до сих пор

Как моделировать
Должен ли я создать еще один БЦ под названием "Компания" или "Организация" и управлять там отделами?

В соответствии со статьей Udi Dahans, на которую я ссылался выше, я должен создать подразделение отдела и подразделение сотрудника для каждого БК с полями и поведением, которые мне нужны для этого БК. Это звучит разумно, но потом я думаю о том, как на самом деле использовать это, и я не могу понять это. Мне нужно получить доступ к отделам, управляемым где-то еще, но как именно я делаю это, а не смешиваю свои БК?

Как пользоваться?
Допустим, я получаю свой список отделов откуда-то, запрашивая. В пользовательском интерфейсе я получаю список отделов, которые я тоже хочу сделать. Это первая покупка для этого отдела, поэтому БК закупок еще не знает об этом отделе... Таким образом, объект отдела в БК закупок будет заполнен данными, сохраненными в другом БЦ - так как мне сохранить это? Мне нужно добавить некоторую информацию, такую ​​как адрес доставки и адрес счета, если его не существует?

В "интерфейсе отдела регистрации" следует ли тогда вызывать службу "RegisterDepartment" на всех БЦ, а затем убедиться, что они синхронизируются со всеми изменениями, внесенными через интерфейс (контроллер MVC)?

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

Упорно
Некоторые из указанных выше проблем могут быть решены путем сопоставления различных объектов-сотрудников с одной и той же таблицей в базе данных. Закупки BC и Archive BC не могут регистрировать новых сотрудников, но добавляют информацию тем, кто там находится, и привязывают их к другим объектам в той же базе данных. Тогда база данных убедится, что все БК все еще живут в одном мире...

Мне нужен совет, чтобы я не стал делать что-то, что потом будет очень сложно поддерживать.

2 ответа

Решение

Похоже, что большинство ваших сомнений вращаются вокруг: "Как отдельные объекты из реальной жизни совместно используются различными ограниченными контекстами?"

Дело в том, что, хотя сущности одинаковы, каждый БК по-разному к ним относится. В Employee Management BC весь вес сосредоточен на сущностях Employee и Department - вы должны иметь возможность добавлять их, изменять, присваивать друг другу, вести историю и позаботиться обо всей бизнес-логике управления. Вы можете внедрить некоторые политики хранения личных данных сотрудников, поддержания надлежащей официальной структуры или выполнения определенных обязанностей.

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

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

Кстати, я не знаю ваш домен, но вы можете пересмотреть границы контекста, например, отделив поставки от покупки.

Переходя к использованию и следуя вашему примеру, если вы хотите сделать покупку, я бы рассмотрел следующий путь:

  • Прочитайте необходимые данные отдела (давайте подождем позже с "как"), вы можете проверить, присутствуют ли все данные на этом этапе
  • Читайте товары, которые можно приобрести, в зависимости от вашего домена, возможно, стоит представить еще одну BC, например, поставщиков. Все вышеперечисленное является частью запроса в CQRS.
  • Построить заказ или любой другой необходимый объект контекста покупки, выполнить проверку или любую другую логику
  • Зафиксируйте изменения, сохраните объекты контекста покупки (часть "Команда")
  • Создайте и опубликуйте некоторые события домена (например, чтобы уведомить Архив или Отчеты)

И последнее, но не менее важное: вам не следует беспокоиться о глобальном постоянстве на уровне домена. Каждый BC должен быть подключен к некоторому уровню доступа к данным или инфраструктуры, обеспечивающему необходимые объекты и заботящемуся о таких деталях, как, где их взять.

В частности, сущности не обязательно должны зеркально отображать структуру базы данных, и вопрос о том, хранить ли они в одной или нескольких базах данных, должен быть только проблемой производительности. Например, некоторые сущности будут ссылаться на один и тот же объект (например, имя сотрудника), но могут брать другие детали из совершенно разных таблиц или БД (т. Е. Истории покупок или элементов, отправленных в архив). Вы можете использовать что-то вроде NHibernate, чтобы сделать это легко управляемым.

Я отвечаю на старый вопрос здесь, но у меня есть еще один пример проблемы, с которой сталкиваются в вопросе ОП.

У меня есть ситуация, когда я работаю над приложением, используемым в производственной компании. Эта компания имеет отделы по продажам, операциям, производству, бухгалтерии, технической поддержке. Во всех этих отделах есть концепция Заказчика. Поэтому мне было трудно разобраться, как у меня есть подразделение Customer в этих отделах (которое я обозначил как свои Связанные контексты).

Когда я размышлял об этом снова и снова, что-то щелкнуло, а потом я вспомнил комментарий, который я прочитал в сообщении в блоге от Джимми Богарда, где он говорил о модели предметной области, над которой он работал, для которой потребовались недели работы, потому что чем больше они работали над проблемой, тем больше они понимали предмет и смогли придумать элегантный дизайн.

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

Я понял, что отдел продаж должен знать о клиентах, но им нужна очень конкретная информация, такая как, кто является руководителем, список контактов, список офисов, кто принимает решения, кто финансовый контакт и т. Д.

Теперь Ops BC отвечает за повышение порядка в системе, и им нужна концепция клиента. Однако им не нужно знать, кто такой MD, или список контактов, и кого волнует, какие офисы у этого клиента? Оператору просто нужно знать имя клиента, а в нашем случае 4-значный код клиента. Когда я думаю, что через это, мне даже не нужно сохранять эту информацию как сущность, это может быть просто объект ценности в моем Ops BC. Но как мне получить эту информацию в Ops BC? Ну, это действительно просто. BC определяет интерфейс, через который мое приложение может взаимодействовать с Ops BC. Мое приложение не имеет представления о том, что происходит внутри этого Ops BC, но оно знает, что существует корень Order Aggregatr, и у него есть метод RaiseNewOrder, который принимает аргумент типа CustomerValueObject. CustomerValueObject состоит из 4-буквенного кода и имени клиента. Итак, в моем пользовательском интерфейсе приложения я могу использовать BC (назовем его "Управление клиентами"), чтобы получить список клиентов для представления раскрывающегося списка. Затем, когда я обрабатываю транзакционную часть операции, то есть пользователя, публикующего новую информацию о заказе, я использую Ops BC и передаю customerVO в качестве аргумента.

Итак, мои Ops BC и Sales BC являются отдельными и независимыми, у них есть внутренние концепции, которые им необходимы для обеспечения целостности домена, и я могу получить доступ к данным, которые мне нужны, в моем пользовательском интерфейсе, чтобы оператор мог выбрать клиент затем выполнить действие в Ops BC.

Я понял, что Клиент для команды продаж - это не то же самое, что Клиент для команды Ops. Для Ops ребята, клиент - это просто то, с чем они помечают заказ. Их не интересует внутренняя деятельность этой компании или какая-либо информация о ней. Пока у меня есть общие идентификаторы для клиентов по всему БЦ, у меня есть способ получить эти данные обратно, которые мне нужны для представления. Например, я могу использовать Ops BC, чтобы получить список заказов для клиента XXXX. Мне не нужно заходить через Customer Aggregate, чтобы сделать это.

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

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

Я думаю, что мы, как опытные разработчики, настроены на денормализацию данных, и думаем о структурах базы данных и о том, как мы будем сохранять эти объекты Customer обратно в таблице... и поэтому мы видим сущность как один шар вещей, но домен Эксперты не видят эти объекты таким образом.

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

Надеюсь, эта вафля кому-нибудь поможет.

Другие вопросы по тегам