DDD - Как применять инварианты в коллекциях в агрегатах - PullRequest
1 голос
/ 24 февраля 2020

Допустим, мы продаем автомобили, настраиваемые автомобили.

Клиент выбирает CarModel и затем начинает настройку CarModel. В нашем магазине она может выбрать только цвет Steeringwheel. Некоторые модели автомобилей могут иметь больше типов рулевых колес, чем другие.

Поэтому у нас есть Catalog, который содержит CarModels и SteeringWheels.

Клиент может создать CarConfiguration. Она выбирает модель, а затем из доступных для этой модели рулевых колес выбирает цветное рулевое колесо, которое ей нравится. всегда присутствовать в каталоге. Для реализации этого инварианта мы должны защитить (как минимум) два метода:

  • AddSteeringWheel на CarModel; мы можем добавить SteeringWheel, только если он доступен в Catalog
  • RemoveSteeringWheel в Catalog; мы можем удалить SteeringWheel, только если он не настроен ни на одном CarModel.

Как применить этот инвариант? CarModel не знает о коллекции SteeringWheel в Каталоге, а каталог также ничего не знает о рулевых колесах CarModel.

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

Другие варианты - создание свойств навигации и настройка ORM (в моем случае Entity Framework Core) для явной загрузки этих отношений. .

И, возможно, еще много, о чем я сейчас не могу вспомнить ...

Каковы самые изящные / pure-ddd / лучшие практики для достижения этой цели?

Ответы [ 3 ]

1 голос
/ 24 февраля 2020

Как применить инварианты к коллекциям в агрегатах

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

Например:

Для этого существует инвариант, что для автомобиля доступны рулевые колеса модель всегда должна присутствовать в каталоге

Так что же должно произойти, когда один человек обновляет CarConfiguration одновременно с другим человеком, изменяющим каталог? Что должно произойти со всеми существующими конфигурациями после изменения каталога?

Во многих случаях ответ таков: «эти действия должны быть разрешены, и мы исправим несоответствие позже»; ie мы попытаемся обнаружить проблему позже и подать отчет об исключении, если найдем что-либо.

(Если этот ответ не является удовлетворительным, вам нужно go вернуться к исходному решению разделить информацию на несколько агрегатов и просмотреть этот дизайн).

У Пэт Хелланда много полезного материала:

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

0 голосов
/ 24 февраля 2020

Инварианты между агрегатами не могут быть согласованными на переходном этапе, только в конце концов. Поэтому, когда вы добавляете рулевое колесо в вашу carModel, вы вызываете событие, скажем, SteveWheelUsedbyCarModelEvent, вы перехватываете это событие в обработчике событий домена и обновляете рулевое колесо. Агрегат рулевого колеса содержит идентификатор (или коллекцию, если она может использоваться несколькими конфигурациями автомобилей) модели автомобиля, которой он назначен.

0 голосов
/ 24 февраля 2020

Ну, во-первых, возможно, CarModel знает что-то о SteeringWheels, так как я предполагаю, что если вы добавите SteeringWheel с Price, Price из CarModel изменится ?!

Таким образом, вероятно, должен существовать объект или сущность значения как часть совокупности CarModel, которая представляет это.

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

...