Как моделировать пользователей и группы в DDD?
За исключением вопроса, является ли следующий сценарий подходящим для DDD, я бы хотел обсудить его и попросить совета:
Учитывая, что у нас есть пользователи и группы. У пользователя есть имя, и у группы есть имя. Пользователи могут вступать в выездные группы, а также могут менять группы. Правила, которым они должны подчиняться: пользователь может состоять максимум из 2 групп, а группа может состоять максимум из 10 пользователей.
Как вы моделируете это? До сих пор я могу придумать три варианта, где каждый вариант имеет свои преимущества и недостатки:
Пользователи и группы являются объектами, и оба являются совокупными.
Join
,Switch
а такжеLeave
являются командами в совокупности групп. Хотя это прекрасно работает дляJoin
а такжеLeave
(поскольку они относятся только к одной группе), это не работает дляSwitch
, поскольку это относится к двум группам одновременно, и, следовательно, необходимо модифицировать два агрегата в одной транзакции, что нехорошо.Пользователи и группы являются объектами, и оба являются совокупными.
Join
,Switch
а такжеLeave
являются командами на совокупности пользователей. Это прекрасно работает для всех трех, и легко проверить, что пользователь не входит в более чем две группы одновременно, но как бы вы убедились, что правило максимум 10 пользователей на группы не нарушено?Пользователи и группы являются сущностями, оба являются совокупностями. Но есть и третий агрегат: отношения.
Join
,Switch
а такжеLeave
теперь команды на совокупности отношений. Хотя это кажется наилучшим подходом (так как оно дает отношение между пользователями и группами имен и делает его явным), я теперь полностью растерялся в том, как моделировать ограничения.
Кто-нибудь может дать мне подсказку?
Если бы было только одно из двух ограничений, это было бы очень просто: тогда вы могли бы поместить команды в агрегат, который также имеет ограничения. Но если у вас есть ограничения с обеих сторон, я потерян. Любая помощь?
1 ответ
Вы можете передать экземпляр группы пользователю, чтобы он проверил инварианты, охватывающие совокупность. Затем сообщите пользователю, что он присоединился к группе, и сообщите группе, что пользователь присоединился.
class Application
handle(UserWantsToJoinGroup command)
user = users.withId(command.userId)
group = groups.withId(command.groupId)
user.join(group)
class User
join(Group g)
if g.isFull throw
if this.isMemberOf(g) throw
if this.numberOfGroupsImIn >= 2 throw
publish new JoinedGroup(this.userId, g.groupId)
handle(JoinedGroup evt)
// modify state
class Group
handle(JoinedGroup evt)
// modifiy state