Requirements checklist
Ask, one at a time, absorbing each answer:
□ vehicle kinds + spot sizes shapes the fit rule □ size compatibility larger-ok / smaller-never? □ layout (floors/sections) lookup vs search; does "nearest" mean anything □ gates (entry/exit count) name the serialization assumption out loud □ pricing scheme + rounding it will change; give it a seam □ full-lot behavior refusal path is a first-class outcome □ out of scope payments, persistence, lost tickets — say where they'd live
The core model
SpotSize (ordered) SMALL < MEDIUM < LARGE
fits(v, s) s.size >= v.requiredSize -- ONE place
Spot id, floor, distance, size, activeTicket?
Ticket plate, spot, entryTime, exitTime? -- the transaction
ParkingLot freeBySize: size -> nearest-ordered free spots
activeTickets: id -> Ticket
Strategy (seam) findSpot(vehicle, availability) -> Spot?
PricingTable size -> hourly rate; round-up rule inside price()
park(v) strategy pick -> remove from free -> issue ticket
unpark(ticketId) lookup -> price from timestamps -> free the spot
Invariants: spot free XOR one active ticket · every active ticket ↔ one occupied spot · all counts derive from the free lists · only park/unpark mutate spot state.
Principles demonstrated (name them at the decision)
- Single responsibility — the fit rule has exactly one home (
fits); a rule change is a one-line edit. - Open/closed — assignment policy behind
SpotAssignmentStrategy, justified by change-anticipation: policy changes must not touch bookkeeping. - Separation of concerns — pricing is data in a table; business tinkering lands as config, not model surgery.
Complexity facts
park O(sizes) lookups + O(log F) tree op (~O(1) with 3 sizes) unpark O(log F); hash lookups otherwise space O(spots + active tickets) naive full-scan assignment is O(N) per arrival — admit it if you built it
What earns points, per report dimension
- Requirements & interface — you drove the scoping conversation; the fit rule, gates assumption, pricing scheme, and full-lot path were pinned before design.
- Core design & invariants — fit in one place, strategy seam, transactional ticket, pricing table, invariants stated unprompted.
- Extension probe — the round will move the requirements; points come from naming the change surface precisely: which classes change, which don't, and why the untouched ones were protected by your seams.
- Complexity honesty — claims with justification; the free-list index named as the thing that bought O(1)-ish assignment.
- Communication — design in words before code, decisions justified at the moment you make them, probes answered directly.