Library Management
Design the desk software for a library: members check books out, return them, put a hold on a copy that's out, and get charged if they're late. It's a small domain, which is exactly why it's a good interview prompt - there's nowhere to hide a sloppy model behind sheer size, and the fee math has a habit of leaking into three classes if you let it.
Requirements
Functional
- A
Catalogmaps aBook(title, author, ISBN) to one or more physicalCopys. - A
Memberchecks out an available copy, creating aLoan; returning it closes the loan and frees the copy. - If every copy of a book is checked out, a member can place a
Hold; the next return of that book should go to the earliest hold in line, not back onto the open shelf. - Overdue loans accrue a fee, calculated per day late.
Non-functional
- The overdue fee formula (flat per-day today, tiered or capped tomorrow) must not require
editing
LoanorMember. - Checking whether a book is available, and who is next in line for it, must not require scanning every loan or hold in the system.
Design
Copy is the unit that actually moves between "on the shelf" and "checked out" - Book is
just catalog metadata shared by every copy of it. Fee math is pulled into a
FeePolicy the same way FeeStrategy handles pricing in
Parking Lot: Loan asks it for a number and never
computes one itself.
- 1The member never touches a Copy directly - the catalog is the only class that finds one.
- 2The book (not the catalog) knows which of its own copies are on the shelf.
- 3A loan is created for the specific copy found - not for "a copy of this book" in the abstract.
- 4Returning goes through the loan itself, since it is the one record of who has this exact copy.
- 5The book decides whether the returned copy satisfies its own hold queue or goes back on the shelf.
Each Book keeps its own hold queue, so "who's next" is a peek at that book's queue, and
returning a copy either satisfies the head of that queue or puts the copy back on the
shelf - never both.
Class diagram
Code
Design decisions
BookandCopyare separate classes, not one class with acopiesAvailablecounter. A counter can tell you how many copies are free, but not which one - and a hold needs to be satisfied by a specific physical copy being returned, not by a number ticking up. Splitting them means aLoanand aHoldcan each point at the exact copy they care about.- Overdue fee calculation is a
FeePolicy, resolved once perLoan.returnBook()call. Same reasoning as the parking lot'sFeeStrategy: pricing is the part of a library that changes when policy changes (a fee cap, a grace period, different rates for reference vs. lending copies), so isolating it meansLoannever edits when the fee schedule does. - The hold queue lives on
Book, not on a globalHoldManager. A hold is always "next in line for this book," so keeping the queue where the book already lives makes "who gets this copy next" a local check on return, instead of a query that has to filter a system-wide hold table by book first. - What's missing for a real system: hold expiration (a member who doesn't pick up
within 48 hours loses their place) needs a scheduled sweep this design doesn't include,
and multi-branch libraries need
Copyto carry abranchand holds to express a pickup-location preference - both left out to keep checkout/return/hold the whole focus.