The LLD Design Interview Checklist

A five-phase checklist for the design and requirements phase of any low-level design interview, distilled from the BookMyShow case study and reusable for the next one.

August 30, 20266 min read

Everything in the BookMyShow design series adds up to a method, but it's spread across eight posts. This is that method compressed into one page, meant to be reread right before a design round, not worked through for the first time.

It's written generally, so it holds up for the next case study too, not just this one. Each phase links back to the post where the reasoning is spelled out in full, in case a line here doesn't immediately click.

Five phases in order: align, find entities, make class decisions, nail the use case, then solve the hard engineering problems ExpandFive phases in order: align, find entities, make class decisions, nail the use case, then solve the hard engineering problems

Phase 1: Align Before You Ask Anything

  1. State the business objective in one plain sentence and wait for confirmation, before any clarifying question. (full reasoning)
  2. Ask three fixed questions next, always in this order: scope (entities only, or a full system), interface (API, command line, or hardcoded input, never a UI), persistence (a real database, or in-memory).
  3. If a weak spot exists, it's something to go learn, not something to route around with careful question choices.
  4. Ask the way you'd actually talk to a product manager. A technically correct question delivered like a script still reads badly.

Phase 2: Find Entities by Walking the Physical Structure

  1. Before any use case, describe the real, physical version of the system, layer by layer. Each layer usually becomes a class. (full reasoning)
  2. Not every physical thing you picture needs its own class. A class exists because the system needs to represent something about it, not because it's physically present. (full reasoning)
  3. The outermost class is never named after the system itself. Walk down the structure until you hit the first thing with real attributes worth storing, and that's the actual root. A second, faster test for the same question: will there ever be more than one instance of it? A class that can only ever have one row was never an entity. (full reasoning, and here)
  4. Ask "can there be multiple X" only when the answer would change what you have to store, not just whether a list might hold one item or many. Most of these questions are obvious enough to skip.
  5. State scope-narrowing decisions yourself instead of waiting to be asked (movies only, not events; this platform, not every platform).
  6. Aim for five to eight core features before anything smaller. Extras like add-ons come after the core flow is fully worked out.

Phase 3: Turn Entities into Real Class Design Decisions

  1. Whenever something looks like a fixed category (a type, a tier, a status), ask whether it's the same fixed set for everyone, or something each tenant can define for themselves. Fixed means an enum. Definable means a full class. Run this test separately for every category-like field — two fields that look similar can land on opposite answers. (full reasoning, and here)
  2. For any value that varies (like a price), ask for the complete list of factors up front, not a narrow yes/no about one of them.
  3. Check whether that value actually belongs to one entity, or to the relationship between two entities. A price tied to both a seat type and a show belongs on that relationship, not on either side of it alone. (full reasoning)
  4. When a relationship carries its own data, give it its own mapping class instead of bolting the data onto one of the two entities. Two relationships that look similar can still need two separate mapping classes if they vary at different levels of granularity, and collapsing them into one causes redundancy: the same value gets duplicated across rows instead of living in one place. (full reasoning)
  5. A relationship belongs wherever the real user journey actually reads it, not automatically on both sides of it. Trace which direction the flow actually goes before deciding which class holds the reference. (full reasoning)
  6. Skipping a reference because it's reachable through another relationship only works when that chain resolves to exactly one thing. The moment the chain passes through a one-to-many relationship, it stops pointing at a single answer, and the far end needs its own direct reference again. (full reasoning)
  7. A schema can constrain what a row looks like, never how many rows should exist or when they get created. That's a service's job, not something to force into the data model. (full reasoning)
  8. A subclass is for a genuine category of behavior, not for an attribute that happens to hold more than one value. A movie supporting many languages is still one Movie with a list, not a subclass per language. (full reasoning)
  9. Redundancy needs a measured, specific reason, not a hunch that an extra join will be slow. It usually won't be. Add it once you can name the actual problem it solves, never by default. (full reasoning)
  10. A class diagram references real objects, never raw IDs. Ticket holds a Payment, not a paymentId — the ID only appears once an ORM maps that relationship to a schema. (full reasoning)
  11. Keep asking, at every step, whether something is a requirement (the interviewer decides) or a design decision (you decide). Don't hand the interviewer a decision that was always yours.

Phase 4: Nail Down the Core Use Case

  1. Get concrete rules through narrow, specific questions about the main flow, not one broad "what's the use case" question. (full reasoning)
  2. Group the answers as you go: what's required, what's a real but optional behavior, what's explicitly out of scope. Group them by kind, not in the order they occurred to you.
  3. Watch for features that sound real but don't touch your design at all. A feature can matter to the product and still be irrelevant to your class diagram.
  4. Find the one or two questions that reshape the whole architecture, like whether the system owns its data or just mediates access to someone else's, before spending time on smaller ones.

Phase 5: Solve the Hard Engineering Problems With the Simplest Model

  1. When a problem looks structurally hard, like representing an arbitrary shape, reach for the simplest model that can represent it before reaching for something clever. Coordinates on a grid beat an uploaded image. (full reasoning)
  2. When two actors can race for the same resource, separate what has to be exclusive from what can stay free. Selecting is free. Committing is exclusive. (full reasoning)
  3. Never hold an expensive lock for the length of an entire user-facing flow. Hold it only for the brief check-and-set, then let a status field carry the "reserved" fact forward on its own. (full reasoning, and here)
  4. Handle expiry lazily wherever possible. A timestamp compared at read time replaces a scheduler, with no background job needed.