В CQRS и DDD агрегат является границей транзакции. Поэтому я всегда моделировал команды таким образом, что каждая команда всегда обращается только к одному агрегату. Конечно, технически было бы возможно написать обработчик команд, который обращается к нескольким агрегатам, но это не было бы в пределах одной транзакции и, следовательно, не было бы согласованным.
Если вам действительно приходится обращаться к нескольким агрегатам, Я обычно go с менеджером процессов, но иногда это похоже на накладные расходы. Кроме того, насколько я понимаю, диспетчер процессов всегда реагирует только на доменные события, он напрямую не рассматривается командами. Поэтому вам нужно решить, к какому агрегату поставить отправную точку.
Я видел, что некоторые люди решают эту проблему с помощью так называемых доменных или прикладных служб, которые также могут получать команды, а затем работают с несколькими агрегатами. - но в этом случае транзакционная природа процесса теряется.
Чтобы привести простой пример, чтобы лучше проиллюстрировать сценарий:
- Пользователь должен присоединиться к группе.
- У пользователя максимальное количество групп.
- В группе максимальное количество пользователей.
Куда поместить команду, запускающую начальный процесс присоединения, и как это назвать? user.join(group)
чувствует себя так же, как и group.welcome(user)
. Я бы, вероятно, go для первого, потому что это ближе к вездесущему языку, но в любом случае ...
Если бы у меня было что-то выше агрегатов, например, вышеупомянутые сервисы, то я мог бы запустить что-то вроде :
userManagement.addUserToGroup(user, group);
Однако эта функция addUserToGroup
должна будет вызывать обе команды, что, в свою очередь, означает, что она должна позаботиться об обработке обеих команд - что несколько противоречит интуитивно понятному наличию отдельных агрегатов вообще и наличие агрегатов в качестве транзакционных границ.
Как правильно будет смоделировать это?