SwadhyAI Notes

All Low-Level Design notes

API, persistence & data modeling

Designing a class API

Class API design means naming typed methods for each use case — not one untyped funnel. Example: the interviewer asks for a parking lot. One candidate writes Object process(Object request). Another writes Ticket park(Vehicle) and Receipt exit(TicketId). The second design is already teaching the domain; the first postpones every decision.

The is the system operations. Names are verbs from the . Arguments are domain types, not Object, Map, or a JSON string. are things the caller will need next.

Grade this first

Verb from the story

park, exit, pay — not process.

Typed arguments

Vehicle, TicketId — not Object.

Useful returns

Ticket, Receipt, Optional.

No internals

Spots and SQL stay behind the lot.

Weak surface

One funnel, no types

process(Object) hides every decision. The compiler cannot help. The next method cannot be named because there is only one funnel. You cannot test “exit a missing ticket” without inventing a map key the method happens to understand.

Strong surface

Commands named after the story

park(Vehicle) is a . exit(TicketId) is another. find(TicketId) is a . You can talk about full lots, unknown tickets, and retries without decoding a blob.

What the public methods are for

In HLD you sketch HTTP paths. In LLD the same idea lives on a class: a small, named surface. The REST API design note is the network cousin of this page. Here the “client” is another object in the same process — a gate, a kiosk, a test.

SignatureKindWhy this shape
Ticket park(Vehicle vehicle)CommandAllocates a spot; caller needs the ticket id to print.
Receipt exit(TicketId id)CommandCloses the stay; caller needs the fee.
Optional<Ticket> find(TicketId id)QueryLookup may miss. Empty is not a crash.
int occupiedCount()QueryDerived from state. Safe to call twice.

Keep the surface small

ParkingLot does not need printReport, sendSms, and connectDb on day one. Add a method when a use case needs it. Prefer an or a new type over a boolean that changes meaning. The parking lot case is the running example for this whole section.

A fat API is how God objects start. Every extra method is a reason to change the class. If the kiosk needs a receipt reprint, that is a query on an already closed ticket — not a second exit.

Java: use cases, not a blob

Write the signatures even if the bodies are empty. Filling HashMaps comes after the names are honest.

java
// Weak — one funnel, no types
class ParkingLot {
  Object process(Object request) {
    // park? exit? pay? the map keys decide
    return null;
  }
}

// Strong — commands named after the story
class ParkingLot {
  Ticket park(Vehicle vehicle) { /* allocate, then save */ }

  Receipt exit(TicketId id) { /* close, price, free the spot */ }

  Optional<Ticket> find(TicketId id) { /* query — no writes */ }
}

What not to return

Live collections

return tickets.values() lets a caller clear() your store. Return a copy, a page, or an unmodifiable list. The lot owns the collection.

Storage types

Connection, ResultSet, and EntityManager on ParkingLot are a persistence leak. The lot talks to a repository port. JDBC stays in the adapter.

Layout types

ParkingSpot[] from park() couples the gate to floors and sizes. Return Ticket. The spot id can live on the ticket if the receipt needs it.

That is an API . The follow-up pages on persistence boundaries and input and output models are the same rule at different API boundaries.

Interview sequence

Write the API before the map

  1. 1List the actor verbs: park, exit, find, maybe pay.
  2. 2Name arguments as domain types: Vehicle, TicketId — never Object.
  3. 3Pick returns: Ticket, Receipt, Optional, empty list. Not null for collections.
  4. 4Refuse internals: no Connection, no live HashMap, no ParkingSpot[].
  5. 5Then implement. The HashMap is an adapter, not the design.

Flags, overloads, and meaning

park(vehicle, true) — true what? Charger? Valet? Handicap? A flag is not an API. When the story grows, add ParkOptions or a second and keep the original method doing what it did. That habit is API evolution: extend the contract; do not silently change it.

java
class ParkingLot {
  Ticket park(Vehicle vehicle) {
    return park(vehicle, ParkOptions.defaults());
  }

  Ticket park(Vehicle vehicle, ParkOptions options) {
    // charger / valet flags live here, not as a nameless boolean
  }
}

Mistakes that fail the round early

process(Object) / handle(Map)

If the signature does not name the verb, the design is not done. Write park(Vehicle) even if the body is empty. Fill the body next.

Leaking internals

Returning ParkingSpot[] or Connection from park() couples callers to storage and layout. Return Ticket. Keep spots and SQL behind the lot.

void park with a side-channel

Stashing the last ticket on a getter the caller “just knows about” is a hidden return type. Return Ticket from park.

One method per HTTP verb cargo-cult

You do not need create/read/update/delete on ParkingLot. You need the story’s verbs. CRUD is a database shape, not a parking lot.

How this pairs with commands and queries

Naming park and exit is half the job. The other half is not letting find write. Read commands vs queries next, then nullability so find returns Optional instead of a surprise null. In system design, “clients retry the same call” usually means idempotency. In LLD, the matching idea is making pay safe to send twice.

Exercises

  1. Rewrite a class that only has process(Map) into park, exit, and find. What types did you invent just to make the signatures compile?
  2. A teammate wants park to return the ParkingSpot so the UI can draw the floor. What do you return instead, and where does the floor number live?
  3. List three methods you would refuse to put on ParkingLot on day one. Which class would own each?
ContinueCommands vs queries·LLD approach·HLD approach

Takeaway

Interviewers grade the API before they grade the HashMap. park(Vehicle) and exit(TicketId) are the design. process(Object) is a postponement. Keep the surface small, typed, and free of JDBC and live collections.