LLD Dojo

Syllabus · F2

Explicit scope negotiation — stating what you are not building

The idea

Scope negotiation — the line you draw

When you extract requirements, you list what you're building. An out_of_scope list names real alternatives you're refusing.

Look at the rate-limiter spec: "distribution, a shared store, persistence, queueing, logging, weights per request, a background timer" are all listed as out of scope. These aren't lazy omissions. A competent engineer would reasonably ask for any of them. You're saying no to each one deliberately.

Why that matters: the interviewer will ask for one anyway. Curveball 03 adds "count the denials per client" — which the reference solution explicitly forbade. If you never said "no metrics", you're now scrambling to retrofit logging into code you designed to ignore it. You lose points on extensibility.

What you're defending is the threshold between your design and someone else's. Rate-limiter without a cluster is a client-side limiter, period. Without persistence, it forgets on restart. Without a background timer, you can't refill automatically. Each one you leave off changes what you're building.

Your out_of_scope list should name things that:

  1. Are tempting — a real engineer would ask for them
  2. Are expensive — they'd reshape the whole design
  3. Are explicitly named in the problem or the clarifying questions

If the interviewer asks for something not in your list, you're not stubborn for refusing — you're unprepared because you didn't see it coming. Your list gets stronger by reading other problems and learning what gets asked.


Worked walkthrough

Scope Negotiation: Saying No Deliberately

Run it first

This is a reading lesson, not a code lesson. Open these problem specs side by side:

corpus/parking-lot/problem.json
corpus/rate-limiter/problem.json
corpus/splitwise/problem.json
corpus/file-system/problem.json

In each one, find the must_haves.out_of_scope array and read it in full.

What out_of_scope actually is

Out of scope is not "things I didn't implement." It's "things I'm explicitly not building." The difference matters because the interviewer tests whether you meant it.

Parking lot

"out_of_scope": [
  "multiple floors or multiple lots",
  "payment processing or card handling",
  "reservations and season passes",
  "number-plate recognition",
  "persistence to a database",
  "concurrent access from several gates"
]

Why each one matters:

Each one changes the design top-to-bottom. If the interviewer asks "what about multiple floors," and you never said no, you're retrofitting now.

Rate limiter

"out_of_scope": [
  "distribution, a shared store, a cluster, or replication of any kind",
  "persistence, or surviving a restart",
  "eviction or expiry of idle keys",
  "weights or costs other than one unit per request",
  "queueing, throttling, or waiting on the caller's behalf",
  "per-endpoint or per-method rules, and authentication of the caller",
  "metrics, logging, or reporting on denials",
  "any background thread, timer or scheduled refill"
]

Notice "metrics, logging, or reporting on denials" is in scope as explicitly out of scope. Curveball 03 in the reference solution asks: "Count denials per client for the last hour." That's exactly the thing the reference said no to, and now the difference is whether you refactored or rewritten half your code.

The tell: what a competent engineer would ask for

An item belongs in out_of_scope when:

  1. A reasonable engineer would ask "what about X?" in the first ten minutes
  2. Answering "yes" would reshape the whole design
  3. It's mentioned in the good_questions list OR it's a known pain point in similar systems

Parking lot:

Rate limiter:

The rule: if a competent engineer would reasonably ask, it belongs in the list.

What's NOT out of scope

Edge cases don't go here. "What if the lot is full?" is a requirement, not out of scope. You handle it explicitly.

Implementation details don't go here. "Should I use an ArrayList or a HashMap?" stays in your head.

Things nobody would ask for don't go here. "Quantum computing support for parking lots" is silly.

The threshold

Your out_of_scope list is done when:

  1. Every item is something the reference solution also lists, or something from the good_questions the reference answers as "no"
  2. You can explain why each one matters to the design
  3. You can describe what the design assumes as a result — single-threaded, in-memory, one floor, etc.

The grader checks: did you name the items in problem.must_haves.out_of_scope? If you missed any, you get missed-out-of-scope and route to this lesson.

The real test: in a curveball, when the interviewer asks for something on your list, you don't panic. You say "that's out of scope as we defined it" and explain the cost of adding it.

Common misses

"Persistence" appears in every problem. It always goes out of scope unless the prompt explicitly asks for a database. You're building an in-memory model to show that you understand the domain, not a production system.

"Concurrency" — the prompt usually says "can I assume one thread?" If you ask and they say yes, write it down. If you don't ask, you have no excuse for assuming it.

"Scaling" — "millions of users" and "millions of records" are expensive and almost always out of scope in an interview. If the prompt doesn't say "this needs to scale," don't build for it.

"Error handling beyond happy path" — sounds optional, but if the requirements say "throw exceptions," error cases are IN scope and you can't avoid them.


Worked source

The 1 file of the worked design

Every file below is the one the app opens, verbatim. This is the part worth reading slowly: the prose above argues for a shape, and these are the lines that have it.

worked/Main.java112 lines

/**
 * Scope Negotiation: Stating What You Are NOT Building
 *
 * This main method walks through the out-of-scope extraction for the rate-limiter problem.
 * See NOTES.md for the detailed explanation and more examples.
 */
public class Main {

  static class ScopeItem {
    String item;
    String whyItMatters;
    String designImpact;

    ScopeItem(String item, String whyItMatters, String designImpact) {
      this.item = item;
      this.whyItMatters = whyItMatters;
      this.designImpact = designImpact;
    }

    void print() {
      System.out.println("\n" + item);
      System.out.println("  Why: " + whyItMatters);
      System.out.println("  Design: " + designImpact);
    }
  }

  public static void main(String[] args) {
    System.out.println("Rate Limiter: Out-of-Scope Negotiation");
    System.out.println("=".repeat(60));

    System.out.println("\nProblem: Implement a token-bucket rate limiter in a single process.");
    System.out.println("Questions the interviewer answered as NO:");

    new ScopeItem(
      "1. Distribution, clustering, or replication",
      "A shared rate limiter across multiple servers needs a central store.",
      "You build a single-process limiter. State lives in memory, nowhere else."
    ).print();

    new ScopeItem(
      "2. Persistence or surviving a restart",
      "A real limiter remembers tokens across crashes.",
      "Your limiter forgets on restart. It's in-memory only. No database, no file."
    ).print();

    new ScopeItem(
      "3. Eviction or expiry of idle keys",
      "A production limiter cleans up old clients automatically.",
      "Your design assumes clients either keep calling or don't matter. No cleanup thread."
    ).print();

    new ScopeItem(
      "4. Weights or costs other than one unit per request",
      "A real limiter might count large uploads as 5 units instead of 1.",
      "You charge exactly 1 token per request. No variable cost."
    ).print();

    new ScopeItem(
      "5. Queueing, throttling, or waiting on the caller's behalf",
      "Some limiters slow callers down instead of denying them.",
      "You deny immediately with an exception. No queue, no backoff."
    ).print();

    new ScopeItem(
      "6. Per-endpoint or per-method rules",
      "Real systems limit different endpoints differently.",
      "You have one limiter, one rate. Same limit for all callers."
    ).print();

    new ScopeItem(
      "7. Metrics, logging, or reporting on denials",
      "Production systems track how often and why they deny.",
      "Your limiter is silent. No counters, no logs, no metrics."
    ).print();

    new ScopeItem(
      "8. Any background thread, timer, or scheduled refill",
      "Token buckets usually refill automatically in the background.",
      "Your refill is demand-driven only. No timer thread, no scheduler."
    ).print();

    System.out.println("\n" + "=".repeat(60));
    System.out.println("The Interview Test");
    System.out.println("=".repeat(60));

    System.out.println("\nCurveball 03 (from the reference solution):");
    System.out.println("  'Count denials per client for the last hour.'");
    System.out.println("\nThis is exactly item #7: 'metrics, logging, or reporting'");
    System.out.println("you said OUT OF SCOPE.");
    System.out.println("\nTwo paths:");
    System.out.println("  Path A (you said no and meant it):");
    System.out.println("    -> Add a Metrics interface behind your limiter");
    System.out.println("    -> New file, zero edits to existing code");
    System.out.println("    -> Curveball cost: one new file");
    System.out.println("\n  Path B (you never said no, scrambling now):");
    System.out.println("    -> Retrofit logging into the deny logic");
    System.out.println("    -> Edits spread across multiple files");
    System.out.println("    -> Curveball cost: five edits, lost extensibility points");

    System.out.println("\n" + "=".repeat(60));
    System.out.println("The Threshold: Scope Negotiation is Done");
    System.out.println("=".repeat(60));
    System.out.println("\n✓ Every item is something the interviewer might ask for");
    System.out.println("✓ Every item would reshape the design if you said YES");
    System.out.println("✓ Every item is listed in the reference's out_of_scope");
    System.out.println("  (or mentioned in good_questions with a 'no' answer)");
    System.out.println("✓ You can explain why each one matters to the design");
    System.out.println("\nWhen the interviewer asks for one, you don't panic.");
    System.out.println("You say: 'That's out of scope as we defined it, and");
    System.out.println("here's what changes if we add it.'");
  }
}

The faded stage is not here, on purpose

In the app, the third stage of this lesson is a written completion: a prompt with blanks, answered in prose and then graded against what the reference extraction expects. The grading needs the app, so this page stops at the worked walkthrough.

Run the app for the drill: it is the download in the header, and it works offline once unpacked.

← F1 · Requirement extraction from an ambiguous prompt F3 · Clarifying-question quality →

← all lessons