Как моделировать объекты, которые существуют во всех ограниченных контекстах и которые являются центральной частью приложения?
Я делаю приложение с использованием принципов DDD. Подумав обо всем, насколько я могу, я начинаю создавать свои ограниченные контексты. Я еще не установил окончательную структуру, но на данный момент мое приложение будет состоять из следующих ограниченных контекстов:
- Управление сотрудниками
- Приобретение
- Архив
- Отчеты
Я хочу, чтобы это было максимально гибким, поэтому я могу, например, развить и поддерживать их отдельно. Вероятно, они будут подвергать WCF или Web API взаимодействию с ними.
Я буду использовать реализацию Udi Dahans простого шаблона CQRS. Я бы предпочел не останавливаться на событиях с использованием источников событий, сообщений и т.д., Потому что это не будет очень совместное приложение (менее 1000 пользователей, и они вряд ли будут редактировать один и тот же небольшой набор данных), и это добавьте много ненужной сложности.
Итак, на вопросы:
Учреждения сотрудника и отдела являются общими для всех ВС, как моделировать это?
Отдел является частью организационной структуры, поэтому в управлении сотрудниками BC сотрудники работают в отделе, они могут управлять отделом, и у них есть история отделов, над которыми они работали.
При покупке товара BC покупаются в отделе и доставляются в отдел. У Suplliers разные контракты с разными отделами.
В архиве некоторая информация будет архивироваться и привязана к отделу и т.д.
То же самое относится и к сотрудникам.
Как сохранить данные из ограниченного контекста?
Они могут быть сопоставлены с одной базой данных или у каждого есть свои собственные.
Некоторые мысли, которые я сделал до сих пор
Как моделировать
Должен ли я сделать еще один BC под названием "Компания" или "Организация" и управлять отделами там?
В соответствии с вышеизложенной статьей Udi Dahans, я должен создать сущность подразделения и сущность сотрудника для каждого BC с только полями и поведением, которые мне нужны для этого BC. Это звучит разумно, но тогда я думаю о том, как на самом деле использовать это, и я не могу понять это. Мне нужно получить доступ к отделам, которые управляются где-то еще, но как именно я это делаю, а не смешивать свои BC?
Как использовать?
Скажем, что я получаю список отделов от somwhere путем запросов. В пользовательском интерфейсе я получаю список отделов, которые я тоже хочу сделать. Это первая покупка для этого отдела, поэтому покупка BC еще не знает об этом отделе... Итак, объект отдела в приобретении BC будет заполнен данными, хранящимися в anoher BC - так как я могу это сохранить? Мне нужно добавить некоторую информацию, такую как адрес доставки и адрес счета-фактуры, если этого не существует?
В "интерфейсе отдела регистров" я должен затем вызвать услугу "RegisterDepartment" на всех БС, а затем сделать так, чтобы они синхронизировались со всеми изменениями, выполненными через пользовательский интерфейс (MVC-контроллер)?
То же самое с сотрудниками. Я хочу знать, какой сотрудник совершил покупку или что-то поместил в архив. Поэтому мне как-то понадобился бы сотрудник-объект в этих БК, но он мог бы управлять ими из другого БК.
Сохранение
Некоторые из вышеперечисленных задач могут быть решены путем сопоставления различных объектов-сотрудников в одной таблице в базе данных. Приобретение BC и Archive BC не может регистрировать новых сотрудников, а добавлять информацию тем, кто там, и привязывать их к другим объектам в одной базе данных. Тогда в базе данных будет сказано, что все ВС до сих пор живут в одном мире...
Мне нужен совет, поэтому я не делаю то, что будет очень сложно поддерживать позже.
Ответы
Ответ 1
Похоже, что большинство ваших сомнений кругом: "Как единичные объекты реальной жизни, разделяемые разными ограничиваемыми контекстами?"
Дело в том, что сущности одинаковы, к каждому БК относятся по-разному. В Employee Management BC весь вес сосредоточен на подразделениях Employee and Department - вы должны иметь возможность добавлять их, изменять, назначать друг другу, сохранять историю и заботиться обо всей бизнес-логике относительно управления. Вы можете реализовать некоторые политики хранения персональных данных сотрудников, поддержания надлежащей официальной структуры или выполнения определенных обязанностей.
С другой стороны, объект отдела в контексте Покупки будет означать только, например, адрес счета и, возможно, лицо из ответственного отдела, а центр интереса будет составлять заказ. Все данные, которые напрямую не связаны с процедурой совершения покупки, должны предоставляться в другом контексте. Если, например, домен требует, чтобы каждый заказ был связан с отделом, а детали счета-фактуры отсутствовали, контекст покупки не должен пытаться заполнить их самостоятельно. Вместо этого может быть сделано уведомление об управлении сотрудниками для заполнения недостающих частей.
Обратите внимание, что это может произойти в одном приложении или даже в том же окне. Но вы должны убедиться, что это произойдет через контекст управления сотрудниками, то есть путем вызова контекстного публичного API.
В качестве побочного примечания я не знаю вашего домена, но вы можете пересмотреть свои границы контекста, например, отделив поставки от покупки.
Перейдя к использованию и следуя вашему примеру, если вы хотите совершить покупку, я рассмотрю следующий путь:
- Прочитайте необходимые данные отдела (подождите дольше с помощью "как" ), вы можете проверить, присутствуют ли в данный момент все данные
- Прочитайте товары, которые можно приобрести, в зависимости от вашего домена, возможно, стоит представить другой BC, например, Поставщики. Все это выше, это часть запроса "CQRS"
- Создайте заказ или любой другой необходимый объект контекста покупки, выполните проверку или любую другую логику.
- Зафиксировать изменения, сохранить объекты контекста покупки (часть "Команда" )
- Создание и публикация некоторых событий домена (например, для уведомления архива или отчетов)
И последнее, но не менее важное: вы не должны беспокоиться о глобальной сохранности на уровне домена. Каждый BC должен быть подключен к некоторому уровню доступа к данным или инфраструктуре, предоставляя необходимые объекты и заботясь о таких деталях, как от того, где их брать.
В частности, сущности не обязательно должны зеркалировать макет базы данных, и вопрос о том, хранить ли в одной или нескольких базах данных, должен быть только проблемой производительности. Например, некоторые объекты будут ссылаться на один и тот же объект (например, имя сотрудника), но могут принимать другие данные из совершенно разных таблиц или db (например, истории покупок или элементов, отправленных в архив). Вы можете использовать что-то вроде NHibernate, чтобы сделать это легко управляемым.
Ответ 2
Я отвечаю на старый вопрос здесь, но у меня есть еще один пример проблемы, возникшей в вопросе OPs.
У меня есть ситуация, когда я работаю над приложением, используемым в производственной компании. Эта компания имеет отделы продаж, операций, производства, счетов, технической поддержки. Во всех этих отделах существует концепция Клиента. Поэтому мне было трудно найти, как у меня есть объект Customer в этих отделах (который я наметил как мои связанные контексты).
Это когда мы снова и снова думали об этом, и я вспомнил комментарий, который я прочитал в блоге от Джимми Богарда, где он рассказал о модели домена, над которой он работал, в течение которой потребовалось несколько недель работы потому что чем больше они работали над проблемой, тем больше они понимали домен и могли прийти к элегантному дизайну.
Момент ясности заключался в том, что я перестала думать о настойчивости и перестала думать о клиентах в этих БК.
Я понял, что Sales BC должен знать о Клиентах, но им нужна очень конкретная информация, например, кто является MD, список контактов, список офисов, кто принимает решения, кто является финансовым контактом и т.д..
Теперь Ops BC отвечает за повышение порядка в системе, и им нужна концепция клиента. Однако им не нужно знать, кто такой MD, или список контактов, и кто заботится о том, какие офисы у этого клиента есть? Ops просто нужно знать имя клиента, а в нашем случае - код клиента с 4 символами. Когда я так думаю, мне даже не нужно сохранять эту информацию как Entity, это может быть просто объект Value в моей Ops BC. Но как я могу получить эту информацию в своем Ops BC? Ну, это очень просто. BC определяет интерфейс, через который мое приложение может взаимодействовать с Ops BC. Мое приложение не имеет представления о том, что происходит внутри этого Ops BC, но он знает, что существует корневой каталог Order Aggregatr, и у него есть метод RaiseNewOrder, который принимает аргумент типа CustomerValueObject. CustomerValueObject состоит из четырехбуквенного кода и имени клиента. Таким образом, в моем пользовательском интерфейсе приложений я могу использовать Sales (позвоните ему Customer Management) BC, чтобы получить список клиентов для представления выпадающего списка. Затем, когда я обрабатываю транзакционную часть операции, то есть пользователь, отправляющий новую информацию о заказе, я использую Ops BC и передаю в customerVO как аргумент.
Итак, мои операционные системы BC и Sales BC являются отдельными и автономными, у них есть внутренние понятия, которые им необходимы для обеспечения целостности домена, и я могу получить доступ к данным, которые мне нужны в моем пользовательском интерфейсе, оператор может выбрать клиента, чтобы затем выполнить действие в Ops BC.
То, что я понял, было заказчиком в команде по продажам, это не то же самое, что клиент с командой Ops. Для парней Ops клиент - это всего лишь то, что они помечают заказ. Они не интересуются внутренней работой этой компании или какой-либо информацией об этом. До тех пор, пока у меня есть общий идентификатор для клиентов во всех БК, у меня есть способ вытащить этот идентификатор данных, который мне нужен для презентации. Например, я могу использовать Ops BC, чтобы отменить список заказов для клиента XXXX. Для этого мне не нужно проходить через агрегатор Customer.
Теперь, бросьте эту морщину. Продавцам нужно будет в какой-то момент узнать о заказах, которые разместил клиент, поэтому мне нужно начать реплицировать информацию в моем Sales BC? Вот где я застрял, но потом я понял, что говорю о продажах, они являются пользователями пользовательского интерфейса, а в пользовательском интерфейсе я могу отменить список заказов для данного клиента.
Я до сих пор довольно новичок в DDD, но я понимаю, что DDD - это все разговоры с экспертами домена, и когда у вас есть эти разговоры правильно, вы понимаете, что сущность, которая, по вашему мнению, существует в BC... doesn ' т.
Я думаю, что мы, как разработчики через опыт, настроены на денормализацию данных, а также подумаем о структурах баз данных и о том, как мы будем сохранять эти объекты Customer обратно в таблицу... и поэтому мы видим, что объект является одним глотком материала, но эксперты домена не видят этих объектов таким образом.
Комментарий, который запечатал сделку для меня, был от довольно остроумного директора Ops, когда я задал вопрос типа "так что бы бухгалтеру нужно было видеть из этого приказа" и его ответ, минус ругательство было "я не знаю", не заботьтесь о том, чего они хотят, я просто хочу, чего хочу ". И я думаю, что вам нужно посмотреть на БК.
Я надеюсь, что эта вафли все равно поможет кому-то.