Как моделировать пользователей и группы в DDD?

За исключением вопроса, является ли следующий сценарий подходящим для DDD, я бы хотел обсудить его и попросить совета:

Учитывая, что у нас есть пользователи и группы. У пользователя есть имя, и у группы есть имя. Пользователи могут вступать в выездные группы, а также могут менять группы. Правила, которым они должны подчиняться: пользователь может состоять максимум из 2 групп, а группа может состоять максимум из 10 пользователей.

Как вы моделируете это? До сих пор я могу придумать три варианта, где каждый вариант имеет свои преимущества и недостатки:

  1. Пользователи и группы являются объектами, и оба являются совокупными. Join, Switch а также Leave являются командами в совокупности групп. Хотя это прекрасно работает для Join а также Leave (поскольку они относятся только к одной группе), это не работает для Switch, поскольку это относится к двум группам одновременно, и, следовательно, необходимо модифицировать два агрегата в одной транзакции, что нехорошо.

  2. Пользователи и группы являются объектами, и оба являются совокупными. Join, Switch а также Leave являются командами на совокупности пользователей. Это прекрасно работает для всех трех, и легко проверить, что пользователь не входит в более чем две группы одновременно, но как бы вы убедились, что правило максимум 10 пользователей на группы не нарушено?

  3. Пользователи и группы являются сущностями, оба являются совокупностями. Но есть и третий агрегат: отношения. 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
Другие вопросы по тегам