DDD => поведение в корневом агрегате: создать экземпляр другого корневого агрегата - PullRequest
0 голосов
/ 03 мая 2018

У меня есть 2 корневых агрегата: - счет-фактура - жалоба

И у меня есть правило, которое гласит: «Я не могу удалить счет, если на него открыта жалоба».

В моем поведении удаления в совокупности счетов я хочу проверить, существует ли жалоба, например:

Complaint complaint = ComplaintRepository.findByInvoiceId(invoiceId);

if(complaint.isOpened) {
throw new Exception("Open Complain...");
}
else{
...
}

Мои коллеги и я не согласны с этим. Они сказали мне, что я не могу инициировать жалобу в своем поведении, поскольку жалоба отсутствует в моем агрегате. Я считаю, что у меня не может быть атрибута «Жалоба» в классе счетов-фактур, но: - Я могу ссылаться на один с объектом значения (они в порядке с этим) - Я могу прочитать / загрузить экземпляр, так как я не вызывал поведение на нем ...

У вас есть мнение по этому поводу?

Ответы [ 4 ]

0 голосов
/ 05 мая 2018

Другое соображение должно быть - что означает удалить счет в этом домене?

См. - http://udidahan.com/2009/09/01/dont-delete-just-dont/

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

Возможно, что они действительно говорят об отмене счета? Или архивировать это? Или наоборот?

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

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

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

0 голосов
/ 04 мая 2018

Это утверждение:

У меня есть 2 корневых агрегата: - счет-фактура - жалоба`

и это

И у меня есть правило, которое гласит: «Я не могу удалить счет, если на него открыта жалоба» `

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

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

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

Код, подобный вашему:

Complaint complaint = ComplaintRepository.findByInvoiceId(invoiceId);
//    
// at this time a new complain could be added!!!
//
if(complaint.isOpened) {
    throw new Exception("Open Complain...");
}
else{
   invoiceRepository.delete(invoiceId);// and this would delete the invoice although there is a complain on this invoice!!!
}

не будет соблюдать бизнес-правило I can't delete an invoice if a complaint is opened on it, если только оно не будет заключено в транзакцию с размером, превышающим одну совокупность.

С учетом вышесказанного у вас есть два варианта DDD:

  1. Просмотрите ваш дизайн: объедините два Агрегата в один, например, сделайте Compliant вложенным объектом внутри Счета.

  2. Используйте координатор более высокого уровня, который будет моделировать «удаление» Счета как длительный бизнес-процесс. Для этого вы можете использовать Saga / Process Manager. Самая «простая» такая Сага также удалит Жалобы, которые были добавлены после того, как Счет был удален. Более сложная Сага может даже помешать добавлению Жалобы после удаления Счета-фактуры (для этого потребуется каким-то образом перехватить открытие Жалобы).

0 голосов
/ 04 мая 2018

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

0 голосов
/ 03 мая 2018

Технически вы можете делать то, что предлагаете: с определенной точки зрения, если вы вводите интерфейс ComplaintRepository в счет-фактуру, либо путем внедрения в конструктор, либо путем внедрения метода, вы делаете Invoice зависимым от контрактов. как хранилища, так и жалобы, и это в значительной степени разрешено.

Вы правы, когда говорите, что не можете хранить ссылку на жалобу, но вы можете вводить артефакты DDD (например, фабрики / репозитории / сущности) в операции, когда они необходимы для запуска.

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

Учитывая все это, вы можете оказаться в сценарии, когда жалоба может быть просто частью совокупности счетов (хотя у вашей совокупности счетов, вероятно, есть другие обязанности, и вы начнете бороться с целью "Проектировать небольшие агрегаты") , Если подумать, это то, что предлагает инвариант «Я не могу удалить счет, если на него открыта жалоба».

Если для вас все-таки нецелесообразно моделировать жалобу как часть совокупности счетов, у вас есть несколько других вариантов:

  • Сделайте эти агрегаты в конечном итоге непротиворечивыми: вместо того, чтобы пытаться удалить счет-фактуру «одним снимком», пометьте его как помеченный для удаления в одной операции. Эта операция запускает некое доменное событие в вашем механизме обмена сообщениями. Это событие «InvoiceFlaggedForDeletion» затем проверит наличие жалоб на счете-фактуре. Если у вас нет жалоб, вы удалите его. Если у вас есть жалобы, вы снимаете флажок удаления.

  • Поместите процесс удаления в доменную службу. Таким образом, Доменная служба будет координировать усилия по проверке жалоб и удалению счета, когда это необходимо. Недостатком этого подхода является то, что ваша сущность Invoice будет менее явной в своих правилах, но с точки зрения DDD это иногда приемлемый подход.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...