DDD Изменение одного агрегата на транзакцию с инвариантами в обоих агрегатах - PullRequest
0 голосов
/ 02 мая 2018

Предположим, у меня есть сводный корень Арендатор и совокупный корень Организация . Мультипликаторы Организации могут быть связаны с одним Арендатором . Арендатор имеет только Id из Организации в совокупности.

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

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

Как мы можем принудительно применить эти инварианты, используя один агрегат на правило транзакции? При добавлении подписки в Organization мы можем легко проверить первый инвариант и запустить событие домена для обновления (возможной согласованности) Tenant , но что произойдет, если инвариант нарушен в совокупности Арендатор ?

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

Или реальный подход здесь состоит в том, чтобы использовать доменную службу для проверки инвариантов обоих агрегатов перед началом обновления? Если да, то размещаем ли мы инварианты / правила непосредственно в доменной службе или мы помещаем логические методы проверки на агрегаты, чтобы сохранить там логику?

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

Ответы [ 4 ]

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

Если вы хотите быть на 100% уверены, что инвариант никогда не нарушен, все команды SubscribeToProduct(TenantId, OrganizationId) должны управляться одним и тем же агрегатом (возможно, Tenant), который имеет внутренне все значения для проверки инварианта.
В противном случае для выполнения вашей операции вам всегда придется запрашивать «внешнее» значение (с совокупной точки зрения), это приведет к «задержке» в операции, которая откроет окно для несогласованности.

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

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

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

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

Есть несколько разных ответов.

Один из них - отказаться от «правила» - не важно ограничивать себя одним агрегатом на транзакцию. Что действительно важно, так это то, что все объекты в единице работы хранятся вместе, так что транзакция является событием «все или ничего».

BEGIN TRANSACTION
    UPDATE ORGANIZATION
    UPDATE TENANT
COMMIT

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

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

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

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

Простые формы этих протоколов, в которых мы предпринимаем обратимые действия для устранения проблемы, называются сагами. Кейти МакКаффри выступила с хорошо принятым докладом по этому вопросу в 2015 году, или вы могли прочитать Клеменс Вастерс или Бернд Рюкер ; Гарсия-Молина и Салем представили термин в своем исследовании долгосрочных транзакций .

Process Manager - это еще один общий термин для этой идеи согласованного протокола, где у вас может быть более сложный график состояний, чем commit / rollback.

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

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

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

В таком упражнении вы, вероятно, достигнете некоторых из уже изученных сценариев:

  • Создайте событие сбора (например, конференц-связь), чтобы убедиться, что избыточные подписки не выполняются: это путь к службе домена.

  • Каждая из них создает свои собственные подписки и уведомляет друг друга, в конечном итоге списывая лишние: это путь Event + Rollback.

  • Они могут скомпрометировать и сохранить общую книгу, где они могут проверить, как подписки распространяются на всю корпорацию, и эта книга является авторитетом в таких решениях: это отсутствующий совокупный путь.

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

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

Первая идея, которая пришла мне в голову, - это иметь свойство организации под названием «tenantHasSubscription», которое можно обновлять событиями домена. Если у вас есть это свойство, вы можете применить инвариант в совокупности организации.

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