SwadhyAI Notes

All Low-Level Design notes

Behavioral modeling

Finding changing parts of the design

An extensibility point (a seam) is a place where a rule can change without rewriting the core flow. You name the variation first — “how we choose a spot will change” — then choose a pattern that fits.

Example: you finished park and exit. The interviewer adds airport pricing, EV spots, and a nearest-spot rule. If you already left seams for pricing and allocation, those follow-ups are new classes. If you did not, you edit ParkingLot again.

Workshop

Name the variation in English first

“The rule for picking a free spot will change.” That statement is the design decision. Strategy is a spelling. Say it in the first ten minutes: “I will keep pricing behind an interface because you will change the fee.”

  1. 01

    Ask what changes

    Pricing, allocation, vehicle types, split rules, win rules.

  2. 02

    Name the seam

    A sentence, not a pattern name.

  3. 03

    Hide it

    An interface the rest already talks to.

  4. 04

    Leave the rest

    Do not strategy-pattern the ticket id.

Will change versus furniture

Will changeSeamLater spelling
Fee formulaPricingStrategyStrategy
Which free spotAllocationStrategyStrategy
Car vs bike vs EVVehicle / Spot typeFactory + type
Equal vs percent splitSplitPolicyStrategy

Will not change yet — keep it simple

Ticket id generatorClock (inject, do not strategy)Floor numbersGate hardware names

Only then pick a tool

Strategy is the usual tool for a swapping algorithm. Factory is the usual tool for “which subclass.” A new vehicle type should not reopen the lot; it should land as a type plus a factory mapping. You do not abstract clocks, ticket ids, and floor numbers on day one. Those are not the follow-up.

The mistake is abstracting everything, or abstracting nothing. says do not invent a plugin bus. Protected Variations says do not bury the one thing that will move inside a switch on ParkingLot. The interview is almost always testing whether you can point at the moving part before you name a pattern.

Pockets still apply. Strategy is a pocket from responsibility assignment. Factory is a pocket. The controller stays thin. The entity still refuses CLOSED → ACTIVE. Extensibility does not move invariants into a plugin.

The lot stays simple

ParkingLot asks allocation.choose and pricing.fee. It does not switch on AIRPORT. A factory may pick the implementation once. Tests pass a fake that always returns spot 1. That is the seam working.

java
interface SpotAllocationStrategy {
  Optional<Spot> choose(List<Spot> free, Vehicle vehicle);
}

interface PricingStrategy {
  Money fee(Ticket ticket, Instant now);
}

class ParkingLot {
  private final SpotAllocationStrategy allocation;
  private final PricingStrategy pricing;

  ParkingLot(SpotAllocationStrategy allocation, PricingStrategy pricing) {
    this.allocation = allocation;
    this.pricing = pricing;
  }
}

class SpotFactory {
  Spot create(SpotType type, SpotId id) {
    return switch (type) {
      case COMPACT -> new CompactSpot(id);
      case EV -> new EvSpot(id);
    };
  }
}

// Airport pricing is a new PricingStrategy.
// Nearest spot is a new AllocationStrategy.
// ParkingLot does not open. Ticket’s machine does not change.

Good sentence

“Pricing will change, so ParkingLot will not own the formula. I will keep a PricingStrategy.” Pattern name comes second.

Cargo cult

“I will use Strategy” with no seam. Then TicketIdFactory, FloorStrategy, and AbstractGate hide the one follow-up that mattered.

Other problems, same habit

  • Splitwise: how an expense splits — equal, percent, exact. That is the seam. The group object stays boring.
  • Tic-tac-toe / chess: how a player chooses a move, or what counts as a win. Do not strategy-pattern the square index.
  • Ticket machine: not a seam. CREATED → ACTIVE → PAID → CLOSED is an invariant. Do not make StatusStrategy so a retry can invent CLOSED → ACTIVE.

What you do not hide

Inject a Clock so tests are deterministic — that is a dependency, not an extensibility point. See deterministic design. Do not wrap it in ClockStrategy. Ticket ids can be a function. Floor numbers are furniture. Open-Closed is for the moving part, not for every noun.

Common mistakes

Saying “I will use Strategy” before naming the seam

Strategy is a spelling. The design sentence is “pricing will change, so ParkingLot will not own the formula.” Pattern names without that design statement are empty pattern name-dropping. Read Strategy after the sentence exists.

Interfaces for things that will not move

A TicketIdFactory, FloorStrategy, and AbstractGate on a short parking-lot interview hide the one seam that mattered. Abstract the follow-up, not the furniture.

Making the state machine a strategy

Illegal transitions are not a variation point. CLOSED → ACTIVE must stay impossible when airport pricing arrives. Extensibility is for fees and stalls, not for resurrecting tickets.

First-ten-minutes script

“Use cases are park and exit. I will keep pricing and allocation behind interfaces because those are the usual follow-ups. Ticket is a small machine: CREATED, ACTIVE, PAID, CLOSED — that is not a strategy.” Then draw the collaboration. The pattern pages wait.

Clock is a dependency, not a seam

Pass a Clock so fee(ticket, now) is testable. That is injection. It is not PricingStrategy. Do not invent ClockStrategy, InstantFactory, and AbstractNow. The follow-up is airport pricing, not a new way to read the time. Keep the moving algorithms behind interfaces; keep time as a value you pass in.

Read next

Takeaway

Name the variation before choosing a pattern. Pricing, allocation, vehicle types — those are seams. Ticket ids and floor numbers are furniture. Strategy and Factory are spellings. The machine CREATED → ACTIVE → PAID → CLOSED is an invariant, not an extensibility point.