Совокупные границы - PullRequest
0 голосов
/ 12 июня 2018

Можно ли разделить сущность между многими агрегатами?

Вопрос

Может ли сущность быть общей для нескольких агрегатов?В Синей книге (Эванс) в главе 6 о агрегатах приведен пример использования сущностей Тир и Колесо в корневой машине агрегатов.Если бы этот пример был расширен до двух агрегатов, легковых и грузовых автомобилей, было бы приемлемо снова использовать шины и колеса с грузовиками?

Ответ

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

Да, скорее всего, вы хотите, чтобы это был собственный агрегат с мягкими ссылками.Кстати, нет проблем с доступом к идентификатору объекта извне, проблема в том, что один и тот же объект находится в двух агрегатах.

Грег

И мой вопрос

Ссылка на идентификацию внешнего агрегированного корня из вашей совокупности не является проблемой.

Предположим, у нас есть совокупный корень Resource, который принадлежит совокупному корню Device.UpdateResource

{
    "id":"933be22c-6e1f-11e8-adc0-fa7ae01bbebc",
    "userId":"2bf9d69a-6e20-11e8-adc0-fa7ae01bbebc",
    "deviceId":"a6caeaea-6e1f-11e8-adc0-fa7ae01bbebc",
    ...
}

Команда была введена пользователем, идентифицированным по уникальному идентификатору.Пользователь является участником 1..n Group s.Devices принадлежит также 1..n Group s как ell.Теперь мой вопрос: если я хочу проверить, находится ли пользователь, который сделал запрос, в той же группе, что и устройство, к которому применяется запрос, мне действительно нужно запрашивать другой агрегат?Это будет означать загрузку тех же событий, которые поддерживаются агрегатом Devices.

Понятно, что два аггегата не могут обновить один и тот же объект - в данном случае Device.Но агрегат Resource просто загрузит его для проверки запроса.В аггерате это сделать быстрее, чем выдавать команду другому агрегату.

Или?:) Спасибо

Ответы [ 2 ]

0 голосов
/ 12 июня 2018

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

В некотором роде.

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

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

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

Resource::updateResource(Command c, PermissionsService p) {
    if (p.hasPermission(c.userId, c.deviceId)) {
        ...
    }
}

Простая реализация PermissionsService может просто вытянуть необходимуюсостояние из репозиториев.

Быстрее сделать это внутренне в аггерате, чем выдавать команду другому агрегату.

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

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

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

Resource::updateResource(Command c, PermissionsService p) {
    Time time = ... 

    if (p.hasPermission(c.userId, c.deviceId, time)) {
        ...
    }
}

С трех логикой состояний в ваших запросах

  • У меня есть доступ к представлению, действующему в то время,и ответ да
  • У меня есть доступ к представлению, действующему в то время, и ответ нет
  • У меня нет доступа к представлению, действующему в то время
0 голосов
/ 12 июня 2018

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

ВCQRS один не запрашивает модель записи, по определению.В DDD модель записи является Агрегатом.Агрегат не должен зависеть от (использовать) данных, которыми он не владеет.Это правило вынуждает нас поместить код туда, где он принадлежит, чтобы проверить инвариант в правильном Агрегате.В CQRS «данными» являются (доменные) события.

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

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

Бизнес-инвариант a user may only update the devices from the same group as him, по-видимому, принадлежит другому ограниченному контексту, а именно авторизации.Это означает, что с вашей текущей совокупной границей не может быть обеспечено строгое соблюдение этого правила.Сильная согласованность гарантируется только внутри одного агрегатного экземпляра.В этом случае всегда есть возможность, что пользователь может обновить устройство, которое он не должен.Эту ситуацию нельзя безопасно предотвратить.Таким образом, вам необходимо спроектировать вашу систему таким образом, чтобы она восстанавливалась из этой ситуации.

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

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

...