What is the GRASP principle "Protected Variations", and what problem is it meant to solve?
answer
- predict the variation point
- stable interface wraps the volatile thing
- clients bind to contract, never past it
- meta-principle over OCP, DIP, info hiding
- Larman GRASP; Cockburn 1996
basics
~20 sProtected Variations says: find the parts most likely to change or vary, and put a stable interface in front of them. Other code depends on that interface, so a change stays contained instead of rippling outward.
solid answer
~50 sProtected Variations (PV) is one of the GRASP principles (General Responsibility Assignment Software Patterns, from Craig Larman). Its question is: how do you design so that instability in one element does not damage other elements? Its answer: identify points of predicted variation or instability, and assign responsibilities so that a stable interface surrounds them. Clients then depend only on that interface; the volatile thing lives behind it and can be swapped, rewritten, or multiplied without touching callers. "Stable" means the interface's shape and semantics change far less often than what it hides. PV is deliberately a meta-principle: information hiding, encapsulation, the Open/Closed Principle, the Dependency Inversion Principle, polymorphism, indirection, data-driven design and service lookup are all concrete ways of achieving it. The cost is an extra layer of abstraction, so PV is applied where variation is genuinely predicted, not everywhere.
code
pseudocode · 16 lines// Unprotected: the checkout depends on a concrete, volatile provider.
checkout(order):
stripe = StripeClient(apiKey)
stripe.charge(order.total, order.card) // swap provider => edit here
// Protected: a stable interface wraps the predicted variation point.
interface PaymentGateway:
authorize(amount, instrument) -> AuthResult // stable vocabulary,
// no provider terms leak
checkout(order, gateway: PaymentGateway):
gateway.authorize(order.total, order.instrument)
// Variation now lives only in implementations:
// StripeGateway, AdyenGateway, SandboxGateway
// Adding a provider adds a class; checkout() is untouched.go deeper
State the problem/solution pair: predicted variation, stable interface around it, clients bind to the interface. Give one concrete example such as swapping a payment provider or a storage backend.
Add the mechanisms (polymorphism, indirection, data-driven design, service lookup) and name PV as the generalisation behind OCP, DIP and information hiding.
Bring in cost. Distinguish variation points from evolution points, discuss speculative generality and the rule of three, and describe how you choose the seam so the abstraction doesn't leak.
Talk at system scale — anti-corruption layers, ports and adapters, versioned contracts, plugin boundaries — and frame protection as buying an option: worth it when the predicted change is likely and the retrofit cost is high.
## The terms, defined first - **GRASP** = *General Responsibility Assignment Software Patterns*, a set of nine principles catalogued by Craig Larman for deciding **which object gets which responsibility**. Members include Information Expert, Creator, Controller, Low Coupling, High Cohesion, Polymorphism, Pure Fabrication, Indirection, and **Protected Variations**. - **Coupling** = how much one element must know about another. If A calls a concrete class B and B changes, A may have to change too — that is a *ripple*. - **Variation point** = a place where the system must support *several* behaviours **right now** (e.g. three payment providers, two tax rules). - **Evolution point** = a place where variation is *anticipated for the future* but is not required today. - **Stable interface** = a contract (method names, parameters, meanings, error behaviour) that is expected to change much more slowly than the code hiding behind it. ## The principle, stated > **Problem:** How do you design objects, subsystems and systems so that variations or instability in these elements do not have an undesirable impact on other elements? > > **Solution:** Identify the points of predicted variation or instability; assign responsibilities to create a **stable interface** around them. This formulation is Larman's; he credits Alistair Cockburn's 1996 IEEE Software article *"Protected Variation: The Importance of Being Closed"*, which in turn ties the idea back to David Parnas's **information hiding** (1972 — modularise around the decisions most likely to change) and Bertrand Meyer's **Open/Closed Principle** (open for extension, closed for modification). ## How it actually works Three steps: 1. **Predict.** Ask where change is likely: external systems and APIs, formats and protocols, business rules and pricing, regulations and tax, hardware/devices, UI technology, persistence technology, algorithms with competing implementations, anything a competitor/customer will demand a variant of. 2. **Wrap.** Introduce something stable in front: an interface/abstract type, a facade, an adapter, a configuration table, a lookup service, an event. 3. **Bind clients to the stable thing.** Callers must not be able to reach past the wrapper. If clients can still see the volatile type (via a leaked return type, a downcast, a public field, a thrown provider-specific exception), the protection is nominal only. ## Why it is called a *meta*-principle PV is the generalisation; the others are instances of it: | Mechanism | What variation it protects against | |---|---| | Encapsulation / information hiding | Variation in internal representation and data structures | | Interfaces + polymorphism | Variation in behaviour among a family of types | | Open/Closed Principle | Change by *adding* new code rather than editing existing code | | Dependency Inversion Principle | High-level policy varying because a low-level detail varied | | Indirection (adapter, facade, proxy) | Variation in an external or legacy component | | Data-driven / config-driven design | Variation in values, rules, mappings — moved out of code entirely | | Service lookup / dependency injection | Variation in *which* implementation and *where* it comes from | | Interpreter / rules engine | Variation in logic, expressed as data at runtime | | Law of Demeter | Variation in the *object graph structure* you navigate | | Standard formats/protocols | Variation between vendors | ## The cost, and why PV is not "always yes" Every protective seam adds a level of indirection: more types, harder navigation ("jump to definition" lands on an interface), harder debugging, and a real risk of **speculative generality** — Fowler's smell for an abstraction built for a variation that never arrives. Larman's own guidance is that **variation points** (needed now) almost always justify protection, while **evolution points** (speculative) need judgement: protect when the *predicted* change is likely, the *cost of being wrong later* is high, and the protection is cheap. A common heuristic is the **rule of three**: the first case is concrete, the second is duplicated deliberately, the third earns the abstraction — by then you can see the real axis of variation instead of guessing it. ## Edge cases and failure modes - **Wrong seam.** You wrapped the database but the variation was in the *query semantics*; the interface leaks anyway. - **Lowest-common-denominator interface.** Forcing several providers behind one contract can strip away the capabilities that made each provider worth having. - **Leaky abstraction.** Timeouts, retries, pagination, transaction scope and error taxonomies from the hidden component surface through the interface, so callers end up coding to the implementation regardless. - **Protection with no client.** Only one implementation ever exists and none is expected — pure overhead. ## One-line summary PV = *decide what will change, put a stable contract in front of it, and forbid anyone from reaching around the contract.*
- Does Protected Variations mean you should put an interface in front of everything?No. It applies to *predicted* points of variation or instability. A universal wrapper policy produces speculative generality: extra indirection, more types, harder navigation, and abstractions shaped around guesses rather than real axes of change. Stable, self-contained, unlikely-to-change code should stay concrete.
- What makes an interface 'stable' in this context?Its shape *and* its semantics change far less often than what it hides: the vocabulary is expressed in the client's domain rather than the provider's, it does not leak provider-specific types, errors or lifecycle, and adding a new implementation does not force it to grow new methods.
A wall socket. Appliance makers protect themselves from variation in power generation (coal, nuclear, solar, a diesel generator in a storm) by binding only to a stable interface: shape of the plug, voltage, frequency. Everything upstream can be replaced without rewiring a single lamp — and the moment an appliance needs to know which power plant it is on, the protection has leaked.
saying these in an interview costs you the question
- Reducing PV to "use interfaces everywhere" — the principle is about *identifying predicted variation*, not adding indirection uniformly.
- Claiming PV is the same thing as encapsulation. Encapsulation is one mechanism among many (polymorphism, config-driven design, service lookup, indirection, standard formats).
- Assuming an interface automatically means protection, while the concrete type still leaks through return types, downcasts or provider-specific exceptions.
- Saying PV is only an object-oriented, class-level idea — Larman states it applies at object, subsystem *and* system scale.
- Treating PV as free: it always buys flexibility with indirection, and unused flexibility is a cost, not an asset.