Паттерн Спецификация: реальный опыт примененияКогда репозиторий начинает разрастаться от десятков методов вроде
getByThisAndThat(), код становится тяжёлым и неудобным. В таких случаях часто вспоминают паттерн
Specification — особенно после хвалебных отзывов на собеседованиях.
Но помогает ли он на практике?
🧱
Что такое «Спецификация»?Идея проста: вынести логику критериев выборки в отдельные классы, чтобы не засорять бизнес-логику и модель.
Пример из оригинала (Фаулер): решаем, в какой контейнер положить груз — не через ифы, а через метод
isSatisfiedBy().
📦
Варианты спецификаций:Hardcoded — простые классы с жёсткими условиями.
Параметрируемые — с конфигурацией через свойства.
Композитные — объединяют другие спецификации и поддерживают AND/OR/NOT.
💡
Как это выглядит в реальной системе?Пример из продакшена: программа лояльности, раздача карт клиентам по гибким правилам.
Каждая стратегия начислений генерирует свою спецификацию, которая используется при выборке клиентов для выдачи карт.
Пример кода:
$specification = $loyaltyProgram->createInitialCardIssuingSpecification();$cards = $cardRepository->findAllBySpecification($specification);При этом, за фасадом — сложная и кастомная реализация, где каждая спецификация превращается в SQL-запрос, в том числе с поддержкой bulk insert и пагинации.
⚠️
Где ловушка?Когда спецификации усложняются, репозитории превращаются в мешанину
match,
if,
IS NULL, кастомных условий и бэкфлипов.
🧩
Выводы:✔️ Использовать, если нужно чётко отделить бизнес-логику от инфраструктуры.
❌ Не использовать как «универсальный антидот» от методов
getByXAndY() в репозиториях.
🧼 Иногда проще честно написать
findByDateAndStatus().
🔁 Ключевая идея — спецификация — это не про репозиторий, а про знание. Описание того, что значит «подходит». И оно может жить в домене, даже если не содержит SQL.
А вы используете этот паттерн у себя? Или предпочитаете оставаться на стороне простых методов?
🔗 Хабр
Библиотека пхпшника