Syllabus · F1
Requirement extraction from an ambiguous prompt
- Tier 3
- Process
- 5 min read
The idea
Requirement extraction from an ambiguous prompt
An ambiguous prompt names the problem but hides the conventions that decide the design. In corpus/parking-lot/problem.json, the prompt mentions "not every vehicle is the same size, and the rates aren't the same for all of them either." That names two things: footprint and pricing.
But it doesn't say whether a truck takes one spot or two. It doesn't say whether the fee rounds up to the whole hour or prorates to the minute.
The gap is closed by asking good questions. The corpus file lists twelve. "How many spots does each vehicle type need, and do a truck's have to be adjacent?" decides allocation. "Which way does the fee round — is one minute a full hour?" decides the timer rule. "Are the rates per vehicle or per spot occupied?" decides whether a truck pays twice.
You're done extracting when you've written down the actors, entities, requirements, and out_of_scope items. The corpus formats this as must_haves: a list of actors, entities, requirements, and an explicit array naming real temptations you're refusing.
The threshold: nothing in must_haves is obvious from the prompt alone. Everything in out_of_scope is something a competent engineer could reasonably ask for. Your extraction must match the reference solution's requirement list in substance.
Anchor your extraction to the prompt. The interviewer is testing whether you listen, not whether you guess well.
Worked walkthrough
Requirement Extraction: Bridging Ambiguous to Clarified
Run it first
There is no code to run here. Read the corpus files side by side.
corpus/parking-lot/problem.json
corpus/file-system/problem.json
Open both in your editor and compare prompt_ambiguous against prompt_clarified for each.
The parking lot prompt and its extraction path
The ambiguous prompt:
Design the software for a parking lot at a shopping mall. Vehicles arrive, they park somewhere, and they pay on the way out. Not every vehicle is the same size, and the rates aren't the same for all of them either. I'd like to see it run at the end.
What it does NOT say:
- How many spots does a truck take — one or two?
- Are spots adjacent, or can they be anywhere?
- How do you round the fee — to the whole hour, or to the minute?
- Does a truck pay once or twice if it takes two spots?
- What throws when the lot is full — an exception or a null ticket?
The good questions that close the gaps:
"How many spots does each vehicle type need, and do a truck's have to be adjacent?"
"Is the fee per started hour or prorated to the minute?"
"Which way does the fee round — is one minute a full hour?"
"Are the rates per vehicle or per spot occupied? Does a truck pay twice?"
"What should happen when the lot is full — an exception or a null ticket?"
The clarified prompt says:
One floor, a fixed number of identical standard spots in a fixed order. A motorbike or car takes one spot, a truck takes two adjacent ones… Fees are per started hour… A full lot refuses entry with IllegalStateException.
The must-haves the clarified prompt enables:
actors: ["driver arriving", "driver leaving", "lot operator"]
entities: ["parking lot", "spot", "vehicle", "vehicle type", "ticket", "receipt"]
requirements: ["park a vehicle and issue a ticket", "truck needs two adjacent spots", "round the fee up to a whole started hour"]
out_of_scope: ["multiple floors", "payment processing", "reservations", "persistence"]
The tell: nothing here was guessable from the ambiguous prompt
The convention "fee per started hour" is the single most important design decision. Round down and a two-hour stay costs one hour's fee. Round up and it costs two. The ambiguous prompt says neither. Neither is more intuitive. One good question, asked in the first minute, decides the whole timing system.
Why out_of_scope matters
corpus/rate-limiter/problem.json lists eight items out of scope: distribution, a shared store, persistence, queueing, logging, weights per request, and a background timer. Every one of them is something you might reasonably build. That is exactly why they belong in the list. Curveball 03 then deliberately takes one back: "count the denials per client." That is how the interviewer tests whether you meant it.
The file-system extraction
Read corpus/file-system/problem.json. The ambiguous prompt says "list what's in a directory, move things around." The clarified prompt answers five questions not in the ambiguous version:
- Are paths absolute or relative? (Absolute only)
- Does mkdir build missing intermediates? (Yes, unlike write)
- Does write build missing intermediates? (No, unlike mkdir — this is the convention that matters)
- What are the four distinct failures? (Path missing, file where directory needed, directory where file needed, clashing name)
- How many ways can an operation fail that the caller must tell apart? (Four distinct exceptions, not one)
Question 3 is the load-bearing design decision. Answered wrong, your API is incoherent: mkdir builds parents but write does not — the inconsistency is intentional and the clarified prompt defends it.
The threshold: anchored to the reference, not to intuition
Your extraction is done when:
- You can name every actor who uses this system.
- You can list every entity the problem mentions.
- You can write every requirement as a sentence starting with a verb: "create a directory", "move a file", "report a denial", "charge a fee."
- Your out_of_scope list names real temptations, not strawmen.
- The reference solution's own spec matches your extraction in substance.
A requirement you left out is one the reference has. A feature you added is one the reference does not — usually, a "design decision" that the interviewer never asked for.
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.java126 lines
worked/Main.java126 lines
/**
* Requirement Extraction: Parking Lot Example
*
* This main method walks through the extraction process for a parking lot system.
* See NOTES.md for the annotated extraction path.
*/
public class Main {
static class Extraction {
String section;
String[] content;
Extraction(String section, String... content) {
this.section = section;
this.content = content;
}
void print() {
System.out.println("\n--- " + section);
for (String line : content) {
System.out.println(" " + line);
}
}
}
public static void main(String[] args) {
System.out.println("Parking Lot Requirement Extraction");
System.out.println("=".repeat(40));
new Extraction(
"Ambiguous Prompt — the starting point",
"\"Design the software for a parking lot.\"",
"\"Not every vehicle is the same size.\"",
"\"Rates aren't the same for all of them.\"",
"",
"What it does NOT say:",
"- How many spots does a truck take?",
"- Are spots adjacent or anywhere?",
"- How do you round the fee?"
).print();
new Extraction(
"One Good Question — three conventions closed",
"Q: How many spots does each vehicle type need?",
"Q: Are they adjacent, or can they be anywhere?",
"",
"A: A truck takes TWO adjacent standard spots.",
"Design impact: spotAllocator must track",
"pairs and refuse non-adjacent assignments."
).print();
new Extraction(
"Extracted Actors",
"- driver arriving at the entrance",
"- driver leaving at the exit",
"- lot operator setting the rates"
).print();
new Extraction(
"Extracted Entities",
"- parking lot (1 floor, N spots)",
"- parking spot (standard size)",
"- vehicle (motorbike, car, truck)",
"- vehicle type (open enum? closed?)",
"- ticket (spot number + entry time)",
"- receipt (fee + duration)",
"- fee (per started hour or per minute?)"
).print();
new Extraction(
"Core Requirements",
"R1: Park a vehicle and issue a ticket",
"R2: Record which spot and when it arrived",
"R3: Refuse entry when no suitable spot",
"R4: A truck needs two adjacent spots",
"R5: Free the spot when the vehicle leaves",
"R6: Charge a fee based on stay duration",
"R7: Charge different rates by type",
"R8: Round fee up to whole started hour"
).print();
new Extraction(
"Out of Scope (Real Temptations)",
"- multiple floors or multiple lots",
"- payment processing or card handling",
"- reservations and season passes",
"- persistence to a database",
"- concurrent access from several gates",
"",
"Why each matters:",
"- floors: 'parking lot' could mean a garage",
"- payment: 'they pay' could mean really pay",
"- reservations: 'manage spots' could mean",
" booking them in advance"
).print();
new Extraction(
"The Load-bearing Convention",
"Q: What happens when the lot is full?",
"",
"Answer A: Throw IllegalStateException",
" -> Lot.park(Vehicle) -> Ticket or throw",
" -> Type-safe, fail-fast",
"",
"Answer B: Return Optional<Ticket>",
" -> Lot.park(Vehicle) -> Optional<Ticket>",
" -> Type-safe, fail-soft",
"",
"Answer chosen by reference: Exception.",
"API surface changed by this one question."
).print();
new Extraction(
"Threshold: Extraction is Done",
"✓ Every actor who uses the system named",
"✓ Every entity the prompt mentions listed",
"✓ Every requirement as a verb",
"✓ Out of scope names real temptations",
"✓ Matches reference in substance, if not words"
).print();
System.out.println("\n" + "=".repeat(40));
System.out.println("The interviewer is testing whether you listen,");
System.out.println("not whether you guess design patterns well.");
}
}
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.