Scope it first
"Members search the catalog, borrow and return physical copies, reserve books that are out, and pay late fines. Librarians manage inventory. Single branch — multi-branch as a follow-up. OK?"
This is the friendliest LLD classic, which is exactly why it's asked: with no concurrency fireworks to hide behind, the grading falls entirely on entity modeling — and one distinction decides the interview.
The one big idea: Book vs BookCopy
"1984 by Orwell" and "the physical copy with barcode #4471" are different things. The catalog entry (title, author, ISBN) exists once; the library owns five copies of it, each with its own condition, shelf and loan history:
- Search and reservations are about the Book ("is 1984 available?" = does any copy stand free).
- Borrowing, returning, damage and fines are about the BookCopy (which physical object is in whose hands).
Merge them and everything breaks: five copies means five duplicate title rows (the normalization sin), and "who has the book?" has no answer because the book isn't a thing anyone can hold. This is the same item-vs-instance split as BookMyShow's Seat vs per-show SeatState and a flight vs a specific departure — interviewers reuse the test endlessly because so many candidates fail it.
Entities & relationships
The supporting decisions worth saying out loud:
Loanis its own entity, not fields on Member or Copy — it's the relationship with history (who, what, when, due, returned). Past loans are the audit trail; fines compute from them. Whenever two entities relate with attributes, the relationship is a class.Reservationtargets the Book, not a copy — the member wants any copy of 1984; binding to copy #4471 would make them wait for that one while #4472 sits free. A FIFO queue per book; on return, the head reservation converts to a hold.BookCopy.statusis a small state machine (ON_SHELF → ON_LOAN → ON_SHELF, withRESERVED/LOSTbranches) — guard transitions; "checkout a LOST copy" should be unrepresentable (the State discipline).- Fines as records, not arithmetic on the fly — a
Fineis created at return-time (days late × rate via a Strategy — children's books may differ from DVDs), then persists until paid. Money facts are append-only.
A BookCopy is a small state machine — here it is. Walk a normal loan
(Shelf → OnLoan → Shelf), then the reservation path where a return skips the
shelf and goes straight to a hold (returnToHold); then try an illegal move — a
checkout while it's already on loan — and watch the copy simply refuse it.
1/5Start in Shelf. Each event is handled by the current state — the State pattern moves this branching out of one giant switch and into the state objects themselves.
Think it through like the interview
PROBLEMMembers search a catalog, borrow and return physical copies, reserve books that are out, and pay late fines. Librarians manage inventory. Design the classes.
- 1
Scope, then find the trap
“This problem is famously 'easy'. So what is it actually grading?”
- 2
Type vs instance
“'1984 by Orwell' and 'the copy with barcode #4471' — same object?”
unlocks after the stage above - 3
Relationships with history become classes
“Where do dueDate and returnedAt live — on Member? On BookCopy?”
unlocks after the stage above - 4
Attach things at the right level
“A reservation — does it point at the Book or at a BookCopy?”
unlocks after the stage above - 5
Walk the busiest scenario
“Asha returns 1984 three days late, and Rahul has a reservation. Narrate every object touched.”
unlocks after the stage above
Walk a scenario
"Asha borrows 1984": search finds the Book with
availableCopies() = 2 → librarian scans copy #4471 →
Library.checkout(asha, copy4471) validates the business rules
(member in good standing? under the 5-loan limit? no unpaid fines
over ₹100?) → copy ON_SHELF → ON_LOAN, a Loan with dueDate = +14
days. Return three days late → Loan closes, fine strategy creates a
₹15 Fine on Asha → copy's status checks the reservation queue:
Rahul reserved 1984, so ON_SHELF is skipped for RESERVED, Rahul
gets a notification and 48 hours to
collect, expiry releases it (TTL self-healing,
the library edition).
That late-return path is the busiest flow in the system — worth seeing end to end:
Business-rule placement is the quiet test here: the loan-limit check
lives in Library.checkout (it spans member + loans), the
status-transition guards live in BookCopy — rules sit with the data
they protect (encapsulation), not in one god
method.
Practice — level up
A library is inventory + lending: allocate a copy, return it, track who has what for how long. These drills rehearse those moves.
Climb in order — every rung assumes the one above it. Solve on LeetCode, then tick it here; progress is saved on this device.
Warm-up — count what's available
Per-type counters — available copies of each title.
Core — allocate & return specific copies
- Seat Reservation ManagerMedium
Reserve / release a specific numbered slot — a book copy.
Borrow → return pairs, with duration (the loan period).
Stretch — state as of a time
Look up a record as of a timestamp — due dates and loan history.