Масштабирование богатой доменной модели - PullRequest
10 голосов
/ 18 декабря 2008

Domain Driven Design поощряет вас использовать богатую модель домена. Это означает, что вся доменная логика находится в доменной модели, и что доменная модель является высшей. Постоянство становится внешней проблемой, поскольку сама модель предметной области в идеале ничего не знает о постоянстве (например, база данных).

Я использовал это на практике в одноместном проекте среднего размера (> 100 тыс. Строк Java) и обнаружил много преимуществ, в основном гибкость и возможность рефакторинга, которые он предлагает по сравнению с подходом, ориентированным на базу данных. Я могу добавлять и удалять классы доменов, нажимать несколько кнопок и развернуть новую схему базы данных и слой SQL.

Тем не менее, я часто сталкиваюсь с проблемами, когда мне трудно совместить богатую доменную логику с фактом наличия базы данных SQL, поддерживающей приложение. В общем случае это приводит к типичной «проблеме 1 + N запросов», когда вы выбираете N объектов, а затем выполняете нетривиальный метод для каждого объекта, который снова инициирует запросы. Оптимизация этого вручную позволяет выполнять процесс в постоянном количестве SQL-запросов.

В моем проекте я разрешаю системе подключать эти оптимизированные версии. Я делаю это, перемещая код в «модуль запросов», который содержит десятки запросов, специфичных для предметной области (например, getActiveUsers), из которых у меня есть оба в -напоминания (наивные и не масштабируемые) и реализации на основе SQL (для развертывания). Это позволяет мне оптимизировать точки доступа, но есть два основных недостатка:

  • Я эффективно перемещаю некоторую часть логики своего домена в места, где она на самом деле не принадлежит, и даже помещаю ее в операторы SQL.
  • Процесс требует, чтобы я просматривал журналы запросов, чтобы выяснить, где находятся «горячие точки», после чего мне нужно провести рефакторинг кода, уменьшив абстракцию его уровня путем понижения его в запросы.

Есть ли лучший, более чистый способ согласовать доменно-управляемый дизайн и его расширенную модель домена с тем фактом, что вы не можете хранить все свои сущности в памяти и поэтому ограничены бэкэндом базы данных?

Ответы [ 4 ]

5 голосов
/ 18 декабря 2008

Существует как минимум два способа решения этой проблемы, один из которых - техническая версия «что я могу сделать, чтобы загружать данные умнее». Единственная действительно умная вещь, о которой я знаю, - это динамические коллекции, которые частично загружаются вместе с остальными, загруженными по требованию, с возможной предварительной загрузкой деталей. На JavaZone 2008 был интересный разговор об этом

Второй подход был больше сфокусирован на мне, когда я работал с DDD; как я могу сделать свою модель так, чтобы она была более «загружаемой», не жертвуя при этом большим количеством добра DDD. Моя гипотеза на протяжении многих лет всегда заключалась в том, что многие DDD моделируют концепции доменов, которые на самом деле являются суммой всех допустимых состояний домена во всех бизнес-процессах и различных состояниях, возникающих в каждом бизнес-процессе с течением времени. Я считаю, что многие из этих проблем загрузки очень уменьшаются, если доменные модели нормализуются немного больше с точки зрения процессов / состояний. Обычно это означает, что объекта «Порядок» не существует, потому что ордрер обычно существует в нескольких различных состояниях, к которым прикреплена довольно разная семантика (ShoppingCartOrder, ShippedOrder, InvoicedOrder, HistoricalOrder). Если вы попытаетесь инкапсулировать это один объект Order, у вас всегда будет множество проблем с загрузкой / конструированием.

Но здесь нет серебряной пули ..

1 голос
/ 18 декабря 2008

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

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

Сначала напишите метод ListAllUsers, который делает все на уровне домена. Какое-то время это сработает, потом начнёт работать слишком медленно.

Когда модель расширенного домена становится медленной, создайте интерфейс под названием «IListActiveUsers» (или, возможно, что-то лучше). И пусть ваш код персистентности реализует этот интерфейс, используя подходящие методы (возможно, оптимизированный SQL).

Теперь вы можете написать слой, который проверяет эти интерфейсы и вызывает определенный метод, если он существует.

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

0 голосов
/ 25 марта 2015

Полагаю, вы должны рассматривать уровень запросов как часть логики вашего домена. Вы должны позволить себе писать оптимизированные запросы, которые могут быть выполнены только при «глубоком» знании вашего постоянного решения. Не пытайтесь абстрагироваться от всего. Кроме того, пакетная обработка - это еще одна часть вашего приложения, которой также должно быть предоставлено знание вашего домена. Я считаю ненужным избегать пакетной обработки просто потому, что не могу вписать ее в свою модель предметной области. Однако вы можете комбинировать подходы: использовать запросы, чтобы выяснить, какие объекты необходимо изменить, затем поставить в очередь свои идентификаторы и обрабатывать каждый из них самостоятельно, используя логику вашего домена.

0 голосов
/ 18 декабря 2008

Нет, не совсем. Не то чтобы я все равно знал об этом (хотя мне интересно услышать ответ сторонников DDD об обратном).

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

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

...