SwadhyAI Notes

All Low-Level Design notes

Low-level design

What they actually grade besides “used a pattern”

Interviewers grade the object model, responsibility assignment, public API clarity, room for change, two-actor races, and narration. Pattern names are tools after those answers exist — they are not the scorecard. Naming Factory plus Strategy without saying who owns allocation can still score poorly.

You have already learned to split responsibilities, stay in-process, talk through forty-five minutes, and build a class list without a Manager. This page is how those answers are marked.

Scorecard at a glance

  • Model — real things, real values, one invariant.
  • Jobs — each verb has a home.
  • API — park and exit, not process(Object).
  • Change — new fee is a new type.
  • Two actors — name the race.
  • Talk — they grade the conversation too.

The scorecard, written as a table so you can study it

Interviewers rarely hold a printed rubric. They still listen for these six. If you name-drop Factory plus Strategy plus Observer without who owns allocation, you can hit zero on all six at once.

They listen forStrongWeak
ModelTicket, spot, vehicle; Money as a value; one vehicle per spotHelpers, DTOs, and a Manager that is the model
JobsChooser allocates, spot occupies, book issues, policy pricesEvery answer is “the service”
APITicket park(Vehicle); Receipt exit(TicketId)void process(Object request)
ChangeEV pricing is a new Pricing type; lot stays stableAnother if in exit, edited in five files
Two actorsShared state named; occupy is the atomic stepIgnore two gates, or lock everything
TalkScope, API, trade-off, next step, spokenSilent typing; they cannot mark what they never heard

API clarity is a scored item, not a nicety

First they grade the . Then they grade jobs and the API. Who allocates a spot? Who prices? Who stores the ticket? If every answer is “the service,” responsibilities have collapsed into a . park and exit should be easy to say. process(Object) is not.

Vague — hard to grade, hard to extend

java
void process(Object request);

Map<String, Object> handle(Map<String, Object> body);

String run(String command, String[] args);

Clear — this is what they want to hear first

java
Ticket park(Vehicle vehicle);
Receipt exit(TicketId ticketId);

// illegal cases are types too
class LotFullException extends RuntimeException { }
class UnknownTicketException extends RuntimeException { }

Change is a scored item

Show the gap. Do not recite the pattern catalog.

Can you add EV spots or a new fee without editing the lot in five places? That gap is the point of Strategy later. Saying the word early does not earn the mark. Showing the does. The follow-up is not a surprise. Design as if it will arrive.

java
interface Pricing {
  Money fee(Ticket ticket, Instant exitTime);
}

class HourlyByType implements Pricing {
  public Money fee(Ticket ticket, Instant exitTime) { /* hours * type rate */ }
}

class HourlyPlusEvSurcharge implements Pricing {
  private final Pricing inner;
  private final Money surchargePerHour;

  public Money fee(Ticket ticket, Instant exitTime) {
    Money base = inner.fee(ticket, exitTime);
    if (ticket.vehicle().type() != VehicleType.EV) {
      return base;
    }
    long seconds = Duration.between(ticket.enteredAt(), exitTime).getSeconds();
    if (seconds < 0) throw new IllegalArgumentException("negative stay");
    long hours = Math.max(1, seconds / 3600 + (seconds % 3600 == 0 ? 0 : 1));
    return base.plus(surchargePerHour.times(hours));
  }
}

// the lot does not change when the surcharge appears
class ParkingLot {
  private final Pricing pricing;
  Receipt exit(TicketId id) {
    Ticket ticket = tickets.require(id);
    Money fee = pricing.fee(ticket, clock.instant());
    ticket.spot().vacate();
    return new Receipt(ticket.id(), fee);
  }
}

Two gates: name the race even if you do not lock it yet

If two gates exist, they grade the . Two threads must not hand out the same spot. You do not need a clever lock in minute five. You do need to name the shared state and the one step that must not split. Then, if time remains, put occupy behind a lock or make choose-and-occupy a single critical section.

Two-gate timeline

  1. T0Gate A and Gate B both call park(car). Chooser sees spot 12 free.
  2. T1If occupy is a public field write, both set occupied and both issue tickets.
  3. T2Invariant dies: one stall, two tickets. The model was never protecting itself.
  4. Fixoccupy() throws if already held, and choose+occupy is synchronized (or a single atomic method on the lot).
java
class ParkingLot {
  public synchronized Ticket park(Vehicle vehicle) {
    ParkingSpot spot = chooser.choose(vehicle)
        .orElseThrow(LotFullException::new);
    spot.occupy(vehicle); // throws if a stale chooser result is already held
    return tickets.issue(vehicle, spot, clock.instant());
  }
}

class ParkingSpot {
  private Vehicle occupant;

  synchronized void occupy(Vehicle vehicle) {
    if (occupant != null) throw new IllegalStateException("already held");
    occupant = vehicle;
  }
}

synchronized on the whole lot is coarse and fine for an interview lot with tens of spots. Mention that you would refine locking per floor or use compare-and-set if the lot were huge. The mark is that you saw the race. Details live in race conditions.

Talking is on the scorecard

is how they see the design. Confirm scope. Name a trade-off in a short sentence. Silent perfect code still reads as weak, because they cannot mark a design they never heard. Quiet typing looks like guessing.

You

I will keep park and exit as the only public commands. Pricing is a separate type because you said EV might arrive. Two gates share spots, so occupy will be the atomic step. I will code the happy path next unless you want the race first.

Interviewer

What if I add a monthly pass?

You

Then Pricing grows a second implementation that returns zero for pass holders. The lot still calls pricing.fee. I would not put pass logic on ParkingSpot.

Interviewer

Why not a full Observer for SMS?

You

I would not, unless notifying is in scope. A comment that TicketBook.close could later notify is enough. Observer without a real subscriber is unused complexity.

Speech that scores low

  • “I will use Factory plus Strategy plus Observer.”
  • “Let me just start coding and see.”
  • “The Manager can handle all of that.”
  • “Threads? We can ignore that.”
  • Silence for eight minutes while a class diagram grows.

Speech that scores high

  • “In-process, park and exit, EV out of scope unless you add it.”
  • “Chooser allocates; spot occupies; book issues.”
  • “Pricing is the seam for a new fee.”
  • “Two gates: occupy must be atomic.”
  • “Happy path next, then unknown ticket, then we can add EV.”

Follow-ups they almost always ask

Add EV spots and a different fee

SpotType already classifies stalls. Chooser already filters canFit. Pricing gets a new implementation. If you have to edit park, occupy, and exit, the seam was missing. This is the change mark.

The lot is full

Optional empty from the chooser becomes LotFullException (or a Result). Do not return null Ticket. Null is how callers invent a second illegal path.

Two gates at once

Name shared state. Name the atomic step. Then lock or retry. See atomicity and visibility.

Tickets must survive restart

TicketBook is the seam. InMemory today, SQL tomorrow. ParkingLot still does not see ResultSet. That is LLD persistence, not a region map. See persistence boundary.

You do not know a library they named

Reason out loud. “I have not used that scheduler. I would still keep a TaskStore interface and put the library behind it.” Do not invent confident details. Do not go silent. The approach page is the talking order; this page is why talking is marked.

How the six marks sit on the clock

You can hit every mark without filling the whiteboard

Minute five: model and scope spoken. Minute ten: API on the board. Minute twenty: jobs assigned, seam named. Minute thirty-five: happy path plus one illegal case. Minute forty-five: race named, follow-up shown. That is a complete round even if Observer never appears.

People

Actors and two gates named early so the race is not a surprise.

Voice

Every checkpoint is a sentence they can write in notes.

Trade-off

Coarse lock vs per-spot lock; in-memory vs SQL behind TicketBook.

Practice the scorecard, not pattern names

  1. Take the parking paragraph and speak the six marks in two minutes with no code. If you cannot, the class list is not ready.
  2. Write only the public API and one invariant. Ask a friend to add EV. Point at the type that changes. If you point at five files, the seam failed.
  3. Draw two gates and one spot. Say the atomic step. Then write occupy so a second caller cannot succeed.

The rest of the fundamentals loop

Takeaway

They grade the model, the jobs, the API, the gap for change, the two-actor race, and the talking. Pattern names are tools after those answers exist. Narrate as you go. Place every verb. Keep park and exit easy to say. When a new fee rule arrives, add a type — do not rewrite the lot. That is the whole fundamentals loop, from splitting responsibilities to scoring the round.