Разделение вложенных сущностей, сохраняющих инвариантность в агрегатах в DDD

#domain-driven-design #aggregateroot #domain-model

#доменно-ориентированный дизайн #агрегатная установка #домен-модель

Вопрос:

В настоящее время я разрабатываю модуль на основе imap сообщений в приложении crm и пытаюсь соединить точки с помощью участников DDD.

Я начал с трех основных сущностей, все они связаны Совокупностью учетных записей:

  • Учетная запись — Учетная запись электронной почты. Имеет несколько Папок.
  • Папка — Папка в учетной записи электронной почты (например. Входящие, Отправленные, Черновик). Имеет несколько сообщений.
  • Сообщение — Сообщение электронной почты.

В этом случае инвариант находится в фактических коллекциях, в основном между учетной записью и папкой:

  • В учетной записи не может быть двух папок с одинаковым именем,
  • Учетная запись не может иметь несколько специальных папок (например, Входящие или отправленные).,
  • В почтовом ящике должно быть фактическое количество сообщений.

    Начальная совокупность здесь

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

Теперь у меня есть варианты:

  1. Разделите его на два агрегата: Учетная запись (с папкой в качестве локальной сущности) и Сообщение.

    Два агрегата разделились здесь

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

  1. Разделите их на три отдельных агрегата: Учетная запись, Папка и Сообщение.

    Три агрегата разделились здесь

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

  1. Что — то, чего мне, возможно, не хватает.

На данный момент я бы выбрал второе решение, но каков наилучший способ разделения этих сущностей в данном случае?

Ответ №1:

Я не уверен, что в DDD обязательно требуется, чтобы каждая сущность в совокупности загружалась как единое целое (хотя вполне возможно, что многие платформы, ориентированные на DDD, применяют такое ограничение). До тех пор, пока любой доступ осуществляется через совокупный корень и инварианты последовательно поддерживаются, никакие рекомендации DDD фактически не нарушаются.

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

При отсутствии возможности легко учитывать ленивую загрузку, я бы, вероятно, выбрал вариант первого подхода, но с сообщением, не имеющим прямой ссылки на папку. Можно было бы реализовать Папку таким образом (например, с фильтром цветения), чтобы поиск соответствующей папки был быстрым. Я не уверен, какие инварианты сообщения должны были бы сохраняться в отношении членства в папках (и вы, похоже, их не выражаете).