Шаблон спецификации и DDD

В контексте личного игрового проекта для получения дополнительной информации о шаблонах DDD мне не хватает объекта Specification. для моих фильтров.

Глядя на примеры, кажется, что все (например, LinQ) ориентировано на базы данных SQL. Однако во многих базах данных NoSQL для большинства запросов даже просто «выбрать * из таблицы» требуется предопределенное представление. Тем не менее, если репозиторий отображает веб-службу, даже тип запросов гораздо более жесткий.

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

Как мне совместить «сортировку» и «фильтрацию» в моих репозиториях? В качестве примера рассмотрим репозиторий для списка элементов Order.

(Query)findAllSortedByDate;
(Query)findAllSortedByName;
(Query)findAllSortedByQuantity;

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

Очевидно, мне нужен какой-то объект "спецификации", но я не уверен, что:

  1. Должен ли я использовать их для своих репозиториев, делая их умнее? Или мне следует использовать их для моих моделей просмотра?
  2. Как правильно ограничить объекты моей спецификации для хорошей устойчивости полиглота?

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

  1. В целом, должен ли я пытаться сохранить какой-либо тип сортировки/фильтрации в моих репозиториях? Кажется, что это может добавить ненужной сложности, если все результаты запроса могут быть загружены в память.

ОБНОВЛЕНИЕ. Чтобы оживить этот вопрос, учтите также, что, хотя представления NoSQL можно фильтровать и сортировать, для полнотекстового поиска может потребоваться внешний механизм индексирования, такой как Lucene или SQLite-FTS, предоставляющий только уникальный идентификатор Сущности для запроса, которые необходимо снова отсортировать и отфильтровать.


person SystematicFrank    schedule 12.08.2013    source источник


Ответы (2)


ФИЛЬТРАЦИЯ

Под «интерфейсом, подобным коллекции» Фаулер не имеет в виду что-то, что предоставляет API, напоминающий массив или список: это не имеет ничего общего с ICollection<T>, например! Репозиторий должен инкапсулировать все технологические детали уровня сохраняемости, но его API должен быть определен так, чтобы он был выразительным в бизнес-домене.

Вы должны думать о спецификациях как о логических предикатах, релевантных предметной области (на самом деле, они являются гражданами первого класса в модели предметной области), которые могут быть составлены как для проверки различных качеств объекта, так и для выбирать объекты из набора (набор, который может быть либо репозиторием, либо простым списком). Например, в модели финансовой области, которую я разработал для итальянского банка, у меня было DurationOfMBondSpecification, StandardAndPoorsLongTermRatingSpecification и так далее.

Фактически, в DDD спецификации исходят из бизнес-требований (часто договорных обязательств), которые должны соблюдаться программным обеспечением во время его работы. Их можно использовать как абстракцию для фильтра, но это скорее побочный эффект.

О СОРТИРОВКЕ

В большинстве случаев сортировка (и нарезка, и группировка...) — это просто задача презентации. Когда это бизнес-задача, правильные компараторы (и группировщики и т. д.) должны быть очищены как понятия предметной области на основе знаний эксперта в предметной области. Тем не менее, даже если это просто забота о презентации, гораздо эффективнее обрабатывать ее в репозитории.

В .NET одним из возможных (и очень дорогих) решений этих проблем является написание собственного поставщика LINQ (или нескольких), который может переводить все запросы, которые могут быть выражены с помощью вездесущего языка, в желаемый уровень сохраняемости. Однако у этого решения есть существенный недостаток: если вы не сможете перевести все запросы с самого начала, вы никогда не сможете оценить трудозатраты на изменение приложения, использующего домен: время будет наступит время, когда вам придется провести глубокий рефакторинг QueryProvider для обработки нового сложного запроса (и такой рефакторинг обойдется вам гораздо дороже, чем вы можете себе позволить).

Чтобы решить эту проблему, в (находящейся в стадии разработки и очень амбициозной) структуре Epic (отказ от ответственности: я я основной разработчик), мы решили объединить шаблон спецификации и шаблон объекта запроса, предоставив API общего назначения, который позволяет клиентам фильтровать по спецификациям, сортировать с помощью компараторов и нарезать с помощью целых чисел без (непредсказуемых) затрат на LINQ.

В схеме Фаулера (ниже) мы передаем в репозиторий как спецификацию (aCriteria), так и дополнительные требования к сортировке:

введите здесь описание изображения

В качестве альтернативы вы можете просто использовать пользовательские репозитории: более дешевый подход, если у вас нет тысяч различных типов запросов.

Бонусное решение

Быстрое, но все же правильное решение состоит в том, чтобы "просто" использовать для запросов язык сохраняемости как есть. DDD предназначен для сложных операционных границ, а запросы (в большинстве случаев) не работают: таким образом, вы можете просто использовать язык, предоставляемый вашей базой данных SQL или NoSQL, для получения необходимых вам прогнозов и/или идентификаторы объектов, которыми нужно управлять. Вы увидите, как набор данных, которые вы запрашиваете, сильно отличается от набора данных, необходимых для обеспечения инвариантов предметной области!

Вот почему, например, иногда файлы сериализации могут быть лучшим подходом к сохраняемости домена для рассматриваемой проблемы.
В конце концов, что такое файловые системы, если не самые распространенные базы данных NoSQL. ! :-D

person Giacomo Tesio    schedule 13.08.2013
comment
привет, какой тип данных должен быть возвращен шаблонами спецификации? IEnumerable, IQueryable, выражение? - person ; 24.08.2019

В DDD Спецификация — это предикат, который применяется к объекту предметной области. Он охватывает потребность в «фильтрации», но не потребность в «сортировке», поскольку сортировка использует не логическую функцию объекта предметной области, а выбор свойства и направление сортировки.

То, что я обычно пишу, когда мне нужна фильтрация и сортировка, — это метод репозитория в следующих строках:

findAll(Specification<Order> specification, 
        SortingOptions<Order> sortingOptions)

В этот момент нам вообще не нужно думать о лежащем в основе механизме персистентности. Интерфейсы вашего репозитория доменного уровня должны определяться не вашим хранилищем данных, а потребностями домена.

Если ваш источник данных затрудняет создание запросов, которые фильтруют и/или сортируют, вы можете выбрать фильтрацию/сортировку объектов в результате запроса в памяти впоследствии. Однако вместо того, чтобы делать это в модели представления, IMO лучше создать конкретную реализацию вашего репозитория, которая будет загружать объекты в память и выполнять сортировку/фильтрацию. операция тут же.

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

person guillaume31    schedule 13.08.2013
comment
привет, какой тип данных должен быть возвращен шаблонами спецификации? IEnumerable, IQueryable, выражение? - person ; 24.08.2019