Menu

Earn Premium with Referrals

Invite your friends and earn Premium rewards through our referral program.

See how it works and start inviting friends.

Encapsulate What Varies
LLD

Encapsulate What Varies

Identify changing behavior and isolate it to make designs easier to modify and maintain.

The Problem It Solves

Payment modes arrive monthly: card today, UPI next sprint, wallets after that. If payment logic sits inline inside checkout code, each addition edits battle-tested flow — every edit risks the whole checkout, every addition grows the diff review surface. The pattern across nearly all maintenance pain is identical: stable logic and unstable logic live in the same place, so change in one damages the other.

The principle: identify what varies, isolate it behind a stable interface, and let the stable side depend only on that interface.

 BEFORE — variation embedded              AFTER — variation sealed

 ┌───────────────────────────┐            ┌────────────────┐
 │ Checkout                  │            │ Checkout       │
 │  if card → chargeCard()   │   extract  │  +             │
 │  if upi  → collectVpa()   │ ────────►  │ depends on     │
 │  if wallet→ debitWallet() │            │ PaymentMode    │
 │  (edited every release)   │            │ (never edited) │
 └───────────────────────────┘            └───────┬────────┘

                                   CardMode | UpiMode | WalletMode ...
                                   (new classes, old code untouched)

Left: one class absorbing every market change. Right: the axis of change became a family of plug-ins; Checkout hasn’t been modified since the extraction — new payment modes are additions.

How to Find What Varies

  • Listen for “and” / “or” in requirements (“supports cards or UPI or wallets”) — conjunctions of alternatives mark an axis.
  • Listen for future tense: “later we’ll add…”, “for now only X” — stated future variation is free design input.
  • Watch churn history: any file edited weekly by different people contains a hidden variation axis.
  • Ask the direct question in interviews: “What is most likely to change here?” The answer names the seam.

Mechanics

interface PaymentMode { PaymentResult pay(Money amt); }

class Checkout {
    private final Map<PaymentType, PaymentMode> modes;   // injected
    PaymentResult pay(PaymentRequest req) {
        validateCart(req.cart());                        // stable part
        return modes.get(req.type()).pay(req.amount());  // varying part
    }
}

The stable method’s structure never changes; the map absorbs growth.

What It Does Not Solve

  • It does not predict the future — it localizes known or stated variation. Guessing axes nobody asked for produces speculative generality.
  • It does not remove conditional complexity from genuinely fixed logic; extracting a single never-changing branch adds indirection for nothing.

Trade-offs

Inline variationEncapsulated variation
First implementationFasterSlightly slower (extra interface)
Each later variantEdit core, retest everythingAdd class only
Blast radius of a bad variantWhole flowThat variant alone
Risk if axis guessed wrongLow (nothing built)Wasted abstraction

Interview Signals

  • Answering “what varies?” before drawing any diagram separates designers from transcribers — it is the key that selects which pattern (Strategy for algorithms, Factory for creation, Observer for notification) applies.
  • Stating the cost honestly — “I’m adding one interface to buy isolation on this axis” — reads as judgment, not ceremony.

My Private Notes

Notes are auto-saved locally to this device.