Learning pathsPricingChecking sign-in…
GUIDED PRACTICE

Library Management

Manage book copies, fair reservations, loans and returns with one active holder per physical copy.

Manage book copies, fair reservations, loans and returns with one active holder per physical copy. This worked design targets SDE-1; the scale figures below are exercise assumptions, not claims about a named company's implementation.

Clarify the prompt

Ask the interviewerDecision to record
Is reservation for a title or a specific physical copy?Title queues can allocate any eligible copy.
What are loan durations, reservation expiry and renewal rules?They drive state transitions.
Are multiple branches and transfers in scope?Start with one branch and explicit copy IDs.

Requirements and scope

The core deliverable is: Manage book copies, fair reservations, loans and returns with one active holder per physical copy. The first design implements the APIs below and the state constraints in the data model. Agree the latency, freshness, retention and failure policy before adding infrastructure. Every successful acknowledgment must have an explicit meaning: accepted intent, committed state or completed external work. These are separate milestones.

Capacity and bottleneck reasoning

Assume 100,000 titles, 300,000 copies and 10 checkouts/s at peak. A 500-byte loan history row and one million annual loans require about 500 MB/year before indexes. Index title queues and active loans.

Keep average and peak demand separate. Add replication, indexes, retries and safety headroom to raw arithmetic before selecting capacity. Load-test the busiest ownership key and recovery traffic as well as uniform happy-path throughput.

APIs and data model

  • POST /titles/{isbn}/holds -> queue position
  • POST /copies/{id}/checkout {memberId, requestKey} -> loan or 409
  • POST /loans/{id}/return -> returned; GET /members/{id}/loans
Contract / pseudocode
book(isbn PK, title); copy(copy_id PK, isbn, branch, state, version)
hold(hold_id PK, member_id, isbn, created_at, expires_at, state)
loan(loan_id PK, copy_id, member_id, due_at, returned_at); UNIQUE active loan per copy

Authorize resource ownership at the API boundary; do not trust IDs or state supplied by a client. Bind retry identity to the caller and payload for mutating operations. Reject an incompatible replay instead of returning an unrelated stored result.

Component relationships

Library Management: directed relationships and authoritative boundaries
Library Management: state boundaries
Read the diagram

Follow the labeled relationship panels; they are separate directed paths, not one global timeline.

Open original
Library Management: state boundaries
Library Management: directed relationships and authoritative boundaries

Library Management: state boundaries

Step-by-step design

1. Establish the authority

Separate bibliographic titles from physical copies. A hold expresses demand for a title; allocation converts the earliest eligible hold into an expiring offer for a copy. Order by created_at plus hold_id to break ties.

2. Make retries and concurrent work safe

Serialize return-and-reassignment on the title or a documented allocation key. Change copy state and hold ownership in one transaction. Checkout verifies the allocated member and expiry against database time.

3. Scale and recover the critical path

Renew only if policy permits and no conflicting reservation wins. Persist due dates and emit reminder events through an outbox; reminder delivery does not change loan ownership.

Worked request and concurrency example

Copy C1 returns while members M1 and M2 wait. The return transaction releases C1 and assigns it to M1 with expiry E. M2 stays queued. At E, a worker conditionally expires M1 only if its hold remains unclaimed. If M1 checks out first, the expiry update affects zero rows. A repeated return key returns the original result and cannot allocate the same copy twice.

Failure and recovery walkthrough

Two reservation workers race after a return. Lock the title allocation boundary or use a conditional copy update plus a unique active assignment. A notification failure leaves the assignment intact and retries the outbox event.

Library Management: one concrete failure or state-transition sequence
Library Management: concrete trace
Read the diagram

This numbered trace follows one scenario; explain the durable evidence at each transition.

Open original
Library Management: concrete trace
Library Management: one concrete failure or state-transition sequence

Library Management: concrete trace

Deep dive: titles are not copies, holds are not loans

This original one-branch baseline lets members reserve a title, receive an expiring offer for a returned physical copy, check it out and return it. A catalog search may use a projection, but assignment and borrowing use authoritative copy/hold/loan state. Start with a relational transaction; inter-branch delivery, payments and recommendation/search scaling are separate extensions.

EntityIdentity and invariant
TitleBibliographic identity; many physical copies may refer to it
CopyOne physical item, with branch and circulation state
HoldOne member's demand for a title, ordered by (created_at, hold_id) in this exercise
OfferA particular active hold/copy allocation with member, generation and expiry
LoanBorrowing interval for one copy; at most one active loan per copy

A returned copy does not make every reservation fulfillable. Assign it only to the next eligible waiting member. Eligibility includes membership/policy and any suspension under the chosen contract. “FIFO” here means oldest eligible hold under a serialized title-allocation decision, not an accidental worker execution order.

Make return and reassignment one decision

Contract / pseudocode
begin local transaction
  resolve return operation key and verify active loan/copy
  lock the title allocation guard, then affected copy/hold/loan in fixed order
  close the matching active loan once
  select oldest eligible waiting hold ordered by created_at, hold_id
  if found: allocate this copy to that hold, set offer expiry/generation
  otherwise: mark copy available
  store return result and notification outbox intent
commit

Every conflicting return, allocation, checkout, expiry and renewal path must follow the same authority/lock-order protocol. Define the exact row acquisition order in an implementation; a guard used by only one endpoint is not protection. Keep external reminder/email work outside the transaction and recover publication through the outbox. A repeated return key returns the original result; it cannot allocate the same returned copy twice.

Checkout and expiry must agree at the boundary

The exercise checks offer eligibility at authoritative database time, with checkout allowed only while now < expires_at. At equality, expiry may win; a delayed worker does not extend eligibility implicitly. Both transitions match current offer identity/generation and state.

Library offer race: C1 is offered to M1 with generation 4; expiry wins the active-offer transition; C1 is offered to M2 under generation 5; M1's delayed checkout presents generation 4; the service rejects it without disturbing M2
A member's old notification is not a continuing right to a reassigned copy.
Read the diagram

Copy C is offered to member M1 at generation 4 → The offer reaches its expiry boundary → Allocator offers C to M2 at generation 5 → M1 submits a delayed generation 4 checkout → Reject M1; preserve M2 ownership

Open original
Library Management: recovery decision
Library offer race: C1 is offered to M1 with generation 4; expiry wins the active-offer transition; C1 is offered to M2 under generation 5; M1's delayed checkout presents generation 4; the service rejects it without disturbing M2

A member's old notification is not a continuing right to a reassigned copy.

If checkout wins before expiry, create the loan and consume the offer atomically. A duplicate expiry sees a non-active offer and does nothing. If expiry wins first, M1 cannot borrow C1 using the old offer even if an email still says it is available. M2's new assignment must not be released by M1's old expiry work. The final unique active-loan constraint protects against two successful borrowings of one copy.

Renewal, loss and policy changes add real state

A renewal is not a blind overwrite of due_at. Validate active loan identity, member status, renewal count and competing eligible holds under the same title/copy authority. Under this exercise's policy, an eligible waiting hold blocks renewal. Another product can choose a different policy, but must make the conflict decision explicit.

A lost/damaged copy leaves circulation through an audited transition. Do not leave an active offer promising an unavailable item. Requeue or cancel its hold under a declared rule, preserve queue-order evidence, and resolve the member's notification. Fee calculation or an external payment is a distinct workflow; a payment timeout cannot change physical-copy existence.

Catalog-title deletion and copy withdrawal are different operations. Historic loans may require retained identity even after a copy is withdrawn, while privacy/retention policy governs personal details. Remove a title from search without silently deleting the evidence needed to reconcile active borrowing.

Recover from a notification failure

Offer allocation is the durable business fact. If email publication fails, the member can still see the offer through an authorized account view while the outbox retries the same event identity. Decide whether the pickup expiry begins at allocation or after a defined notification milestone; this exercise uses allocation time and makes that visible to the member. Provider delivery is not silently assumed from a queue acknowledgement.

At an illustrative 20,000 returns/day, average return traffic is only about 0.23/s. School/library closing-time bursts can be much higher, and a single popular title is a separate contention point. Use bounded allocations and short transactions; a global library-wide lock unnecessarily serializes unrelated titles. Monitor active offer age, expiry/reassignment conflicts, notification lag, missing copies and circulation discrepancies.

Library assessment: preserve fair and exclusive circulation

Question: M1 and M2 have identical hold timestamps. Which one receives a returned copy under this exercise?

Show answer and explanation

Answer: Use hold_id as the deterministic tie-break within the authoritative eligible queue. Do not let whichever notification worker runs first choose the winner.

Question: M1's checkout reaches the service at the offer's exact expiry instant. Can client send time authorize it?

Show answer and explanation

Answer: No under the stated rule. The authoritative eligibility decision uses now < expires_at; an expired/reassigned generation cannot create a loan. Client clocks and an old email do not extend the offer.

Question: May a renewal succeed while another member has an eligible waiting hold?

Show answer and explanation

Answer: Not under this exercise's policy. Recheck that predicate with the renewal decision; a stale preliminary list cannot establish that no hold exists.

Score one point for title/copy separation, deterministic eligible ordering, atomic return/allocation, offer-generation expiry/checkout and renewal/withdrawal policy. Then add another branch and explain which ownership and transfer states must be introduced before relaxing the single-branch transaction boundary.

Review Transactions and Isolation and PostgreSQL locking before translating the pseudocode into an implementation. This is an original circulation exercise; tests model selected state transitions, not an integrated library system.

Decisions and alternatives

DecisionTrade-off
Alternative 1Title-level serialization is simple and fair but a popular title becomes a hot key. Branch-scoped queues reduce contention while changing fairness across branches.
Alternative 2Store an authoritative due_at rather than recomputing from current policy. Versioned policies require extra history but keep old loans explainable.

Operational contract

Monitor overdue counts, queue wait time, allocation age and outbox age. Audit every state change with member and copy IDs; restrict staff overrides and keep a reason. Recover lost jobs by scanning due active holds.

Choose alert thresholds from the agreed user-facing objective. Assign an owner for stuck work and a replay/repair procedure that preserves the original business identity. Bound queue depth, concurrency and recovery throughput so an outage does not produce an uncontrolled catch-up burst.

Foundation, senior and staff depth

  • Foundation: Distinguish titles, physical copies, holds and loans.
  • Senior: Serialize FIFO assignment, expiry and checkout using the same authority.
  • Staff: Defend renewal fairness, notification recovery and lost-copy reconciliation.

Practice before revealing the answer

Spend 45 minutes: 5 clarifying scope, 7 on capacity/APIs/state, 12 on the first architecture, 15 on the concurrency and failure examples, and 6 on trade-offs and operations. Draw your own design before comparing it with this chapter.

Question: What happens if hold expiry and checkout arrive at the same time?

Show answer and explanation

Answer: Both must compete at the same authoritative state transition. Checkout succeeds only for an active unexpired allocation; expiry succeeds only for the current hold version. Exactly one transition wins, and the loser receives the current state.

Verification and rollout

Race checkout against expiry at equality and replay an old offer after reassignment. Verify one active loan per copy, deterministic eligible FIFO order and atomic return/allocation/publication. Test renewal when another eligible member is waiting.

Primary technical reference

Official documentation for the mechanism used in this exercise. This lesson is an original interview design, not a description of undisclosed company internals.

Before this design, review these mechanisms and identify which owns the critical state transition:

Use the Interview Playbook to adapt the depth and timing, then return to the question breakdown overview.

13:00Self-guided practice timer
The timer resets when you leave this page. Save your design separately.
Your challenge

What happens if hold expiry and checkout arrive at the same time?

Your design draft

Clarify assumptions, explain your approach, and test the difficult cases. Save your draft, then compare it with the study notes.

Read study notes

Self-review checklist

Self-guided practice. Automated AI feedback and code execution are not connected.