Telegram Web
emacsway-log: Software Design, Clean Architecture, DDD, Microservice Architecture, Distributed Systems, XP, Agile, etc.
Pattern Specification можно реализовать парой строчек кода, в случае использования JSONB поля для хранения агрегата, путем применения jsonpath. Для реализации метода IsSatisfiedBy подойдет, например, - https://jsonpath2.readthedocs.io/en/latest/ А для компиляции…
С какими трудностями я обычно сталкивался в своей практике при реализации Specification Pattern?

1. Расслоение, если мы хотим применять его как для фильтрации объектов в оперативной памяти, так и в БД. Обычно эта проблема решается через Expression Tree, но в Golang такой опции нет, что, правда, легко обходится самодельным синтаксическим деревом.

При этом возникает вопрос о том, должна ли логика предиката реализовываться в виде интерпретатора на основе Expression Tree или дублироваться хардкодно?

2. Когда агрегаты храняться в JSONB колонке БД, обычно проблем не возникает, и мы можем применить коробочные реализации JSONPath.

Трудности возникают когда сущности агрегата хранятся в отдельных табличках без использования JSONB.

В частности, структура таблиц и структура агрегата нередко отличаются. Например, агрегат часто использует композитные первичные ключи и композитные ValueObjects. Это означает, что синтаксическое дерево для предиката агрегата будет отличаться от синтаксического дерева для запроса в БД. Т.е. просто так "коробку" прикрутить не получится. И мне известны только единичные специалисты, обладающие достаточной квалификацией, чтобы написать код трансформации одного дерева в другое.

3. Большинство коробочных интерпретаторов для Expression Tree, которые можно приспособить для реализации Specification Pattern, умеют оперировать только примитивными типами данных, и без существенной доработки не умеют совершать операции над ValueObjects, особенно, если язык программирования не поддерживает перегрузку операторов.

4. Инкапсуляция агрегата. Это отдельный большой вопрос, который часто обсуждается в отрасли и уже не раз обсуждался мной. Чаще всего для извлечения защищенного состояния агрегата используются:
1. Общие области видимости (как в Golang) или дружественные классы (C++).
2. Mediator Pattern (описан в красной книге Vaughn Vernon).
3. Рефлексия (нередко используется в коробочных решениях, особенно в ORM).
4. Memento Pattern, хотя и часто называют, но ошибочно, если внимательно разобраться.

5. Самая любимая моя проблема - это предикаты к атрибутам коллекции сущностей агрегата с использованием Expression Tree.

Как выразить в Expression Tree следующее условие:
хотя бы одна из сущностей коллекции агрегата имеет значение "x" атрибута "a" и значение "y" атрибута "b", или хотя бы одна из сущностей той же коллекции имеет значение "j" атрибута "с"?

Ничего не получится, если напишем нечто подобное:
agg.ent[*].a == x && agg.ent[*].b == y && agg.ent[*].c == j

Кажется, такое ни одна коробка не умеет, за исключением операторов wildcard "*" и локального елемента "@" в JSONPath. Собственно, оттуда я и перенял решение:
agg.ent[*] ? (@.a == x && @.b == y) || agg.ent[*].c == j

Если скомпилировать это выражение в SQL запрос к обычным реляционным табличкам (без JSONB), то получится два JOIN.

Не знаю, можно ли выразить нечто подобное с помощью LINQ в C# (если да, то сообщите, пожалуйста, в комментарии).

Когда должно вернуть true следующее выражение:
agg.ent1[*].a == agg.ent2[*].a ?
Когда совпадает хотя бы один элемент в обоих подмножествах, или когда оба подмножества эквиваленты?

Нет ничего сложного в реализации Specification Patrern on Expression Tree, если обладать достаточным опытом и квалификацией. Реализация занимает всего несколько сотен строк кода.

Сложно найти/подготовить такого специалиста в команду.
👍6👏21🔥1
2025/07/08 18:06:22
Back to Top
HTML Embed Code: