← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

Specification Pattern

Architecture PHP 5.0+ Intermediate
debt(d7/e5/b5/t5)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate automated detection is 'no' and the code pattern is 'complex eligibility or validation rules scattered across service methods.' PHPStan is listed but cannot automatically flag missing or misapplied specification patterns — it takes a reviewer who recognises the anti-pattern of scattered business rules to identify that the Specification pattern is needed or misused. This won't surface in standard linting.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes encapsulating business rules into Specification objects with isSatisfiedBy(), and/or/not composition — but common mistakes include SQL leaking into specs, missing composition, and I/O in specs. Correcting misuse means identifying scattered rules across service and repository methods and consolidating them into dedicated Specification classes, touching multiple files across the codebase.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). The pattern applies across web, cli, and queue-worker contexts. When adopted, every future maintainer must understand the Specification abstraction and its composition model. Misuse (e.g., SQL-leaking specs or non-composable specs) can quietly spread, but the pattern itself doesn't reshape the entire architecture — it's scoped to business rule and query logic, making it a persistent but not system-defining tax.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap — a documented gotcha most devs eventually learn' (t5). The misconception field explicitly states developers believe Specifications are 'just a fancy way to write WHERE clauses.' Common mistakes confirm this: specs leaking SQL, not being composable, or performing I/O are well-documented pitfalls. The pattern's dual use in both in-memory filtering and query construction is non-obvious, and the distinction between business rule encapsulation and query construction trips up most developers encountering it for the first time.

About DEBT scoring →

Also Known As

specification business rule encapsulation composable criteria

TL;DR

Encapsulating business rules as composable objects that evaluate whether a candidate satisfies them — separating rules from entity code.

Explanation

The Specification pattern encapsulates a business rule as a class with an isSatisfiedBy($candidate): bool method. Specifications are composable: AndSpecification, OrSpecification, NotSpecification combine them with boolean logic. Example: ActiveCustomerSpecification->and(HasValidEmailSpecification) produces a compound rule. Benefits: business rules are named, reusable, and testable in isolation; they can be translated to query criteria (Doctrine Criteria or SQL WHERE clauses) for database-side filtering. PHP libraries: beberlei/specification, or implement the interface yourself (typically 10 lines). The pattern shines when the same rule must filter both in-memory collections and database queries — a Doctrine-aware specification generates DQL expressions while the core logic remains testable without a database.

Common Misconception

The specification pattern is just a fancy way to write WHERE clauses. Specifications encapsulate business rules as composable, reusable objects — they can be combined with and/or/not, used in both queries and in-memory filtering, and named to express domain concepts explicitly.

Why It Matters

The Specification pattern encapsulates business rules as composable objects — complex query conditions become named, testable, reusable specifications rather than SQL fragments scattered across repositories.

Common Mistakes

  • Specifications that leak SQL — they should express business rules, not WHERE clauses.
  • Not making specifications composable with AND, OR, NOT — the pattern's core value is composition.
  • Over-using specifications for simple, single-use queries — a repository method is simpler.
  • Specifications that perform I/O — they should be pure predicates, not data fetchers.

Code Examples

✗ Vulnerable
// Raw conditions scattered in repository:
public function findEligibleCustomers(): array {
    return $this->db->query(
        'SELECT * FROM customers WHERE active = 1 AND balance > 100 AND age >= 18'
    )->fetchAll();
}
// 'Eligible' means different things in different contexts — use a specification:
// $eligible = new ActiveSpec()->and(new MinBalanceSpec(100))->and(new AdultSpec());
✓ Fixed
interface Specification {
    public function isSatisfiedBy(mixed $candidate): bool;
}

class ActiveCustomer implements Specification {
    public function isSatisfiedBy(mixed $customer): bool {
        return $customer->isActive() && !$customer->isBanned();
    }
}

Added 15 Mar 2026
Edited 22 Mar 2026
Views 75
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 2 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 1 ping T 0 pings F 1 ping S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F
No pings yet today
No pings yesterday
Amazonbot 9 ChatGPT 6 Ahrefs 5 PetalBot 5 SEMrush 4 Google 3 Unknown AI 3 Bing 3 Claude 2 Scrapy 2 Twitter/X 2 Applebot 2 Perplexity 1 Meta AI 1
crawler 44 crawler_json 4
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Medium
⚡ Quick Fix
Encapsulate business rules as Specification objects with isSatisfiedBy($candidate) — combine with and()/or()/not() to build complex rules without giant if-statement blocks
📦 Applies To
PHP 5.0+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
Complex eligibility or validation rules scattered across service methods not reusable or composable
Auto-detectable: ✗ No phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Medium Context: Class Tests: Update


✓ schema.org compliant