← Concepts

阅读中文版本

Specification Composition

The specification pattern represents a business rule as a composable predicate object, so that rules combine with and/or/not into complex criteria without the query logic duplicating for each.

architecture

Definition

The specification pattern encapsulates a business rule as an object that tests whether a candidate satisfies it, and specifications compose with boolean operators to build complex criteria from simple ones, so that the rule logic is expressed once, reused across query and validation, and extended by composition rather than duplication.

Context and scope

Applied in dynamic query building, validation rules, and any domain where the set of applicable criteria is assembled at runtime from building blocks.

Common misconceptions

  • Specifications are just predicates — a predicate is a function; a specification is an object that composes with other specifications and can be reused for query, validation, and explanation
  • Specification composition is always clearer than a query — for a single rule a query is clearer; composition pays off when rules combine at runtime

Anti-patterns

  • Building a specification for every rule including one-off constants, adding object overhead where a predicate would do
  • Composing specifications so deeply that the resulting rule cannot be explained to a domain expert, defeating the readability intent

Related concepts

Authoritative source

https://en.wikipedia.org/wiki/Specification_pattern

What it is

The specification pattern encapsulates a business rule as an object that tests whether a candidate satisfies it, and specifications compose with boolean operators to build complex criteria from simple ones, so that the rule logic is expressed once, reused across query and validation, and extended by composition rather than duplication. Applied in dynamic query building, validation rules, and any domain where the set of applicable criteria is assembled at runtime from building blocks. The organizing principle is which decisions are hard to reverse and should be made once, versus which are easy to reverse and should be deferred.

How it works

Boundaries are drawn along axes of change: things that change together are colocated, things that change independently are separated by interfaces whose contracts are explicit and versioned. Dependencies point toward stability — domain logic depends on abstractions, infrastructure depends on domain, never the reverse. The structure makes the system’s intent legible without reading every module.

When to choose and pitfalls

Choose this structure when the system will outlive its first deployment and face requirements you cannot now predict. The pitfall is premature abstraction — adding indirection for a flexibility that never materializes, paying its complexity cost forever. The opposite pitfall is entangling concerns that later need to separate, forcing a rewrite instead of a refactor.