Learning pathsPricingChecking sign-in…
← LLD problem library

LLD-004 · LOW LEVEL DESIGN

Library Management

Separate titles from copies, protect circulation invariants and preserve historical loan terms.

Local Java 21 reference verified: 221 checks. Learner drafts are not executed. Author self-review; independent review pending.

Existing introductory lesson · Version 1

Understand the problem

Design circulation for a library with multiple physical copies of a title. Support checkout, return, one renewal and a FIFO title-hold queue. Protect copy availability and member limits under concurrent calls. Explain how a policy update affects existing versus new loans.

Before you start

  • Entity identity vs value equality
  • Transactions and lock scope
  • Calendar dates and immutable policies
  • FIFO queue semantics

Scope and explicit decisions

  • In-memory circulation for registered members and configured physical copies. No catalog search engine, fines, procurement, authentication implementation, ebook licensing or inter-library transfers.
  • BookCopy has a stable copy ID and title ID. Several copies may share a title; lending the title itself would incorrectly collapse inventory.
  • A Policy contains version, loan duration in whole calendar days and active-loan limit. The current policy applies at checkout; each Loan captures its immutable policy. A policy decrease does not forcibly return existing loans.
  • Trusted callers supply LocalDate in the library timezone. No clock or timezone conversion occurs inside the model; deadline is a calendar date, not a UTC duration. Renewal on the due date is allowed; later renewal is rejected.
  • One renewal is allowed, extending the original due date by the captured policy duration. Any waiting title hold blocks renewal. Renewal uses expectedRenewals as an optimistic version and is not automatically retried with a different version.
  • Holds are FIFO by insertion and unique per member/title. Checkout consumes the head when present. Head priority applies to any copy of that title, even if several copies are free. An ineligible head blocks later members until its hold is cancelled; expiry and automatic skipping are not implemented.
  • checkout requestId is globally scoped to this Library instance. Reusing it for another copy/member fails; a retry resolves the same loan identity with its current returned state.
  • Returns are idempotent by loan ID. Retained loans and command results grow over time and disappear on process loss. Durable transactions and post-commit notifications are design extensions.

Worked examples

Input: c1 and c2 share title T. A borrows c1; B and C place holds for T.

Outcome: Queue [B,C]. A cannot renew while readers wait; C cannot bypass B even for free c2.

This chapter deliberately uses strict title-head priority. A more permissive allocation rule must be designed explicitly.

Input: Loan under v1=14 days begins January 1. Policy changes to v2=7 days. Renew old loan on January 15.

Outcome: Old loan extends to January 29. A new January 1 loan under v2 is due January 8.

The version used by a record determines its historical term.

Try before revealing

Hint 1

A title describes a book; which identity describes the thing being lent?

Hint 2

Which facts must checkout update atomically besides copy availability?

Hint 3

Keep old loan identity and policy so retries and upgrades cannot rewrite history.

Requirements and invariants

R1 — A physical copy has at most one active loan, and member active counts match those loans. checkout protects I1.

R2 — Title holds preserve FIFO priority without duplicate membership. placeHold protects I2.

R3 — A policy change cannot silently rewrite existing loan terms. changePolicy protects I3.

R4 — Repeated return of an old loan cannot free a copy now checked out to another member. returnCopy protects I1.

I1: Each nonreturned loan corresponds to exactly one activeCopies entry; each member count equals their active loans.

I2: Each title queue contains each member at most once; only its head may claim a copy while the queue is nonempty.

I3: A Loan retains its captured Policy; successful renewal extends its due date using that Policy, at most once.

Derive the design

Model copy ownership before adding repositories

Begin with a list of loans and scan for the active loan of a copy or member. It is correct under single-threaded access but costs O(L) per check. The reference adds activeCopies and per-member counts for expected O(1) access while keeping the loan log as the source for diagnostic invariant checks. These indexes are materialized state and must be maintained atomically, not treated as independent truths.

Alternative: A relational repository can enforce unique active copy ownership and use a transaction for member capacity and loan creation. A generic CRUD repository is insufficient if checkout performs several uncoordinated calls. Expose a domain operation or explicit unit of work with its guarantees.

Ask about copy and hold granularity

Do readers reserve a title or one physical item? Can two copies be checked out independently? Answer those questions before drawing class inheritance. The chosen model has many copies per title and one active loan per copy.

Write the invariant across all records

The service owns a loan, active copy mapping and member count. Those facts must agree. Keeping a cached count is useful only if checkout and return update it under the same atomic boundary as the authoritative loan.

Put validation before irreversible queue changes

Read hold head, member count and copy state first. Compute LocalDate.plusDays before modifying maps. Only after creating a valid loan should the hold be consumed, so arithmetic or eligibility failure cannot lose priority.

Preserve identity through repeat returns

A return is attached to a loan ID, not merely a copy ID. If a stale return arrives after that copy was borrowed again, the old returned Loan resolves as a no-op and must not clear the new active mapping.

Responsibilities and ownership

BookCopy

Owns: Unique physical identity and bibliographic title reference

Methods: Validated immutable accessors

Does not own title-wide reservations or loan policy.

Loan

Owns: Member/copy identities, due date, captured policy, renewal version, returned flag

Methods: Immutable snapshot accessors

Library replaces snapshots; callers cannot edit due dates or return status.

Library

Owns: Active copy mapping, member counts, holds and request results

Methods: checkout, returnCopy, renew, placeHold, cancelHold

One local atomic boundary coordinates cross-record invariants.

Policy

Owns: Versioned term and limit values

Methods: Validated immutable constructor

Policy replacement affects new loans; historical meaning remains attached to old records.

Circulation ownership

A repository adapter must preserve the same cross-record contract; CRUD calls alone do not imply a transaction.

  1. Desk command + request ID
  2. ↓ Validate membership and identity

    Library atomic boundary
  3. ↓ Commit matching records and consume hold

    Loan / copy / member count
  4. ↓ Return stable loan identity

    Immutable loan snapshot
Loan lifecycle

One guarded renewal extends the active due date. A repeated return does not touch a later loan on the reused copy.

  1. Available copy
  2. ↓ Eligible checkout; respect title hold head

    Active loan with captured policy
  3. ↓ Return by loan ID

    Returned historical loan

Data model, schema and relationships

A bibliographic title is not a physical copy. Members borrow copies, while FIFO holds request a title; allocation connects the next eligible member to one copy.

Implementation boundary: Title/copy/member/loan/hold records mirror reference concepts. A database requires transactionally enforced member limits and copy ownership.

These are proposed logical schemas with field contracts, not executable database migrations. PK identifies a row, FK references an existing parent, UK is a uniqueness rule. A composite PK identifies the combination. Nullable references are marked with ?. A foreign key protects identity; cross-row limits, timing and state transitions also require the transaction rules below.

title: relationship map

Connectors name the relationship; multiplicities state parents per child and children per parent. 0..1 means optional, 1 required, 0..* any number. Self-links show two roles of the same entity.

title relationshipstitle 1 to copy 0..*: has physical copies. copy.title_id → title.id. title 1 to hold 0..*: has requests. hold.title_id → title.id.has physical copies1 parent · 0..* childrencopyid [PK]title_id [FK]statehas requests1 parent · 0..* childrenholdid [PK]title_id [FK]member_id [FK]titleid [PK]isbnname
copy: relationship map

Connectors name the relationship; multiplicities state parents per child and children per parent. 0..1 means optional, 1 required, 0..* any number. Self-links show two roles of the same entity.

copy relationshipscopy 1 to loan 0..*: has loan history. loan.copy_id → copy.id.has loan history1 parent · 0..* childrenloanid [PK]copy_id [FK]member_id [FK]copyid [PK]title_id [FK]state
member: relationship map

Connectors name the relationship; multiplicities state parents per child and children per parent. 0..1 means optional, 1 required, 0..* any number. Self-links show two roles of the same entity.

member relationshipsmember 1 to loan 0..*: borrows. loan.member_id → member.id. member 1 to hold 0..*: requests. hold.member_id → member.id.borrows1 parent · 0..* childrenloanid [PK]copy_id [FK]member_id [FK]requests1 parent · 0..* childrenholdid [PK]title_id [FK]member_id [FK]memberid [PK]active

Entity definitions and field contracts

title

Bibliographic identity.

FieldType / keyMeaning and reference
iduuid · PKTitle identity
isbntext · UKEdition identifier
nametext · VALUEDisplay title

Code mapping: Title record.

  • ISBN may be optional/nonunique in a broader catalog; declare edition rules.

copy

One physical lendable item.

FieldType / keyMeaning and reference
iduuid · PKBarcode identity
title_iduuid · FKBibliographic parent · title.id
stateenum · VALUEAvailable reserved or loaned

Code mapping: Copy record.

  • At most one active loan/reservation per copy.

member

Borrower eligibility.

FieldType / keyMeaning and reference
iduuid · PKMember identity
activeboolean · VALUEMembership eligibility

Code mapping: Member state.

  • Borrowing limit spans all active member loans.

loan

Historical copy checkout.

FieldType / keyMeaning and reference
iduuid · PKLoan identity
copy_iduuid · FKBorrowed item · copy.id
member_iduuid · FKBorrower · member.id
due_attimestamp · VALUEDue instant
policy_versiontext · VALUEOriginal loan rules
closed_attimestamp? · VALUENull while active; terminal return evidence otherwise

Code mapping: Loan record.

  • Partial unique active copy_id; return must correlate current loan identity.

hold

FIFO title request.

FieldType / keyMeaning and reference
iduuid · PKHold identity
title_iduuid · FKRequested title · title.id
member_iduuid · FKRequester · member.id
sequencebigint · VALUEFIFO order
statusenum · VALUEACTIVE allocated fulfilled or cancelled queue state

Code mapping: Hold queue.

  • Unique active (title_id,member_id); stable sequence orders eligible holds.

Relationship cardinalities and their reasons

Parent → childMultiplicityFK / why
title → copy

has physical copies

1 parent per child; 0..* children per parentcopy.title_id → title.id

Many copies share one edition; a checkout consumes one copy.

copy → loan

has loan history

1 parent per child; 0..* children per parentloan.copy_id → copy.id

Only one historical loan may remain active.

member → loan

borrows

1 parent per child; 0..* children per parentloan.member_id → member.id

Member limit needs a shared atomic owner across concurrent different-copy checkouts.

title → hold

has requests

1 parent per child; 0..* children per parenthold.title_id → title.id

FIFO is per title, not per arbitrary copy.

member → hold

requests

1 parent per child; 0..* children per parenthold.member_id → member.id

A member may wait on many titles under policy limits.

Transaction boundaries

  1. checkout: lock member eligibility/active count and selected copy/hold order, then insert loan and update copy atomically.
  2. return: validate active loan identity, close once and allocate availability to the next eligible FIFO hold.

Indexes and uniqueness

  1. Partial unique active loan(copy_id); index active loan(member_id) for limits.
  2. Index active hold(title_id,sequence) for FIFO; unique active title/member request.

Schema traps and failure cases

  1. Checking member limit separately from inserting loans allows concurrent different-copy oversubscription.
  2. A stale return cannot release a copy under a newer loan.

Trace the records through one operation

  1. Title T has copies C1,C2; member M requests T.
  2. Checkout C1 creates L1 under current policy and member limit.
  3. Return L1 closes it once and advances the FIFO allocation without changing title identity.

Method contracts

checkout(copyId, memberId, requestId, today) → Loan

Validate identity, retry fingerprint, copy availability, member limit and hold priority. Compute due date before mutation; commit loan, count, copy ownership and dedupe result together.

returnCopy(loanId) → Loan

If already returned, return that snapshot without touching current copy ownership. Otherwise mark returned and decrement the associated member count atomically.

renew(loanId, expectedRenewals, today) → Loan

Reject returned/overdue/already-renewed loans, stale expectedRenewals and any waiting hold. Extend original due date under captured policy, then increment renewal count.

placeHold(titleId, memberId), cancelHold(titleId, memberId)

Validate configured title and registered member. Placement is duplicate-safe; cancellation removes the member if present. Both operate under the same aggregate monitor.

changePolicy(Policy)

Replace the current immutable policy for future checkout; no retroactive update of active or historical loans.

What, when, why and how

Each concept is attached to the requirement it protects, its implementation, an alternative and a test.

Entity identity versus title data

what
A physical copy is a separate identity from the shared bibliographic title.
when
The library owns multiple copies of one book.
why
Using ISBN/title as the loan key would either block all copies or allow the same physical item to be lent twice.
how
BookCopy stores copyId and titleId. Active ownership is keyed by copy ID; hold queues are keyed by title ID because a reader generally accepts any copy.

Code: BookCopy, activeCopies, placeHold · Invariants: I1, I2

Alternatives, cost and failure example

Alternative: If holding a specific rare copy is required, introduce copy-scoped holds deliberately; do not overload title queue semantics.

Cost: Two identity spaces require explicit joins/lookups, but preserve correct cardinality.

Counterexample: Two copies of the same title share one boolean available flag; returning one makes both appear available.

Test: Configure c1/c2 with one title; checkout c1 and separately exercise c2 under member/hold constraints.

Aggregate atomicity and derived indexes

what
Treat loan creation, copy ownership, member count and request result as one change.
when
Concurrent circulation commands can interleave.
why
A safe copy map alone cannot enforce a member borrowing two different copies simultaneously against a limit of one.
how
synchronized checkout validates all conditions and writes all maps under one monitor; return and renewal use the same owner. invariantHolds recomputes active counts from loans.

Code: checkout, returnCopy, invariantHolds · Invariants: I1

Alternatives, cost and failure example

Alternative: For several processes use database constraints plus a transaction protecting both copy and member admission, with stable lock ordering or serializable conflict handling.

Cost: One monitor limits parallelism; indexes add maintenance complexity but speed normal lookup.

Counterexample: Two desks independently read member count zero, then each creates a loan on a different copy.

Test: Race checkout and verify one-copy ownership; repeated circulation recomputes and compares all counts after every operation.

FIFO reservation semantics

what
A title queue orders who may claim the next eligible copy.
when
Returns and new checkouts compete with waiting readers.
why
Without an explicit priority rule a newly arriving borrower can bypass a long-standing hold.
how
placeHold deduplicates member entries; checkout rejects non-head borrowers and removes the head only after successful loan creation. Renewal is blocked by any pending hold.

Code: placeHold, checkout, renew · Invariants: I2

Alternatives, cost and failure example

Alternative: Automatically skip ineligible/expired holds only with a documented deadline and notification policy; this simple reference requires explicit cancellation.

Cost: Queue contains/remove is O(H). Strict head priority can reduce utilization when the head cannot currently borrow.

Counterexample: Pop the head before checking member limit; a failed checkout silently loses that reader’s reservation.

Test: Repeat the same hold, attempt non-head checkout, fail renewal with waiting holds, then verify FIFO consumption.

Immutable policy snapshots and optimistic renewal

what
Retain the rule that created a loan, and reject a renewal based on stale state.
when
Policy changes or two renewal requests occur while a loan is active.
why
Current configuration must not silently shorten old terms; duplicate renewal should not extend the due date twice.
how
Loan stores Policy. renew requires expectedRenewals, allows at most one extension and applies the captured duration to the existing due date.

Code: Policy, renew, changePolicy · Invariants: I3

Alternatives, cost and failure example

Alternative: If renewals intentionally use current policy, version that business decision and show its impact on existing users instead of treating it as an implementation detail.

Cost: Snapshots retain old policy versions and make data retention/serialization contracts important.

Counterexample: Change 14-day policy to 7 days and accidentally rewrite the existing due date while calculating a renewal.

Test: Verify old v1 renewal adds 14 days, new checkout uses v2 seven days, and stale renewal version is rejected.

Read and run the Java reference

Reveal complete Solution.java

Java 21. Save as Solution.java; compile with javac --release 21. The repository also contains Test.java and the lld:java verification command. This reference implements the local contract above.

Solution.java Java 21
import java.time.LocalDate;
import java.util.*;
/** In-memory circulation aggregate. Calendar dates are supplied by a trusted library-zone adapter. */
public final class Solution {
    private Solution() {}
    private static void id(String s){if(s==null||s.isBlank())throw new IllegalArgumentException("identifier");}
    public record BookCopy(String id,String titleId){public BookCopy{Solution.id(id);Solution.id(titleId);}}
    public record Policy(String version,int days,int maxLoans){public Policy{id(version);if(days<1||maxLoans<1)throw new IllegalArgumentException("policy");}}
    public record Loan(String id,String copyId,String memberId,LocalDate due,Policy policy,int renewals,boolean returned){}
    private record Request(String member,String copy,String loan){}
    public static final class Library {
        private final Map<String,BookCopy> copies=new HashMap<>();
        private final Set<String> members;
        private final Map<String,Loan> loans=new HashMap<>();
        private final Map<String,String> activeCopies=new HashMap<>();
        private final Map<String,Integer> counts=new HashMap<>();
        private final Map<String,ArrayDeque<String>> holds=new HashMap<>();
        private final Map<String,Request> requests=new HashMap<>();
        private Policy current;
        private long sequence;
        public Library(List<BookCopy> copies,Set<String> members,Policy policy){
            for(var c:copies)if(this.copies.put(c.id(),c)!=null)throw new IllegalArgumentException("duplicate copy");
            this.members=Set.copyOf(members);members.forEach(Solution::id);current=Objects.requireNonNull(policy);
        }
        private void member(String member){if(!members.contains(member))throw new IllegalArgumentException("unknown member");}
        private BookCopy copy(String copy){var c=copies.get(copy);if(c==null)throw new IllegalArgumentException("unknown copy");return c;}
        private void title(String title){if(copies.values().stream().noneMatch(c->c.titleId().equals(title)))throw new IllegalArgumentException("unknown title");}
        public synchronized void placeHold(String title,String member){
            title(title);member(member);var q=holds.computeIfAbsent(title,k->new ArrayDeque<>());
            if(!q.contains(member))q.addLast(member);
        }
        public synchronized void cancelHold(String title,String member){title(title);member(member);var q=holds.get(title);if(q!=null)q.remove(member);}
        public synchronized Loan checkout(String copyId,String memberId,String requestId,LocalDate today){
            id(requestId);Objects.requireNonNull(today);member(memberId);BookCopy c=copy(copyId);
            var previous=requests.get(requestId);
            if(previous!=null){if(!previous.member().equals(memberId)||!previous.copy().equals(copyId))throw new IllegalArgumentException("key reused");return loan(previous.loan());}
            if(activeCopies.containsKey(copyId))throw new IllegalStateException("already on loan");
            if(counts.getOrDefault(memberId,0)>=current.maxLoans())throw new IllegalStateException("member limit");
            var q=holds.get(c.titleId());if(q!=null&&!q.isEmpty()&&!q.peekFirst().equals(memberId))throw new IllegalStateException("hold priority");
            LocalDate due=today.plusDays(current.days()); // Validate arithmetic before mutation.
            String loanId="L"+(++sequence);var l=new Loan(loanId,copyId,memberId,due,current,0,false);
            loans.put(loanId,l);activeCopies.put(copyId,loanId);counts.merge(memberId,1,Integer::sum);requests.put(requestId,new Request(memberId,copyId,loanId));
            if(q!=null&&!q.isEmpty())q.removeFirst();return l;
        }
        public synchronized Loan returnCopy(String loanId){
            var l=loan(loanId);if(l.returned())return l;
            var returned=new Loan(l.id(),l.copyId(),l.memberId(),l.due(),l.policy(),l.renewals(),true);
            loans.put(loanId,returned);activeCopies.remove(l.copyId());counts.put(l.memberId(),counts.get(l.memberId())-1);return returned;
        }
        public synchronized Loan renew(String loanId,int expectedRenewals,LocalDate today){
            Objects.requireNonNull(today);var l=loan(loanId);
            if(l.returned()||l.renewals()!=expectedRenewals||l.renewals()>=1||today.isAfter(l.due()))throw new IllegalStateException("renewal rejected");
            var q=holds.get(copy(l.copyId()).titleId());if(q!=null&&!q.isEmpty())throw new IllegalStateException("waiting hold");
            // Extend original due date; old policy stays attached to this loan.
            var updated=new Loan(l.id(),l.copyId(),l.memberId(),l.due().plusDays(l.policy().days()),l.policy(),l.renewals()+1,false);
            loans.put(l.id(),updated);return updated;
        }
        public synchronized void changePolicy(Policy policy){current=Objects.requireNonNull(policy);}
        public synchronized Loan loan(String id){var l=loans.get(id);if(l==null)throw new IllegalArgumentException("unknown loan");return l;}
        public synchronized List<String> holdQueue(String title){title(title);var q=holds.get(title);return q==null?List.of():List.copyOf(q);}
        public synchronized boolean invariantHolds(){
            var actual=new HashMap<String,Integer>();int active=0;
            for(var l:loans.values())if(!l.returned()){active++;if(!l.id().equals(activeCopies.get(l.copyId())))return false;actual.merge(l.memberId(),1,Integer::sum);}
            return active==activeCopies.size()&&members.stream().allMatch(m->actual.getOrDefault(m,0).equals(counts.getOrDefault(m,0)));
        }
    }
}

checkout keeps request identity separate from availability

An accepted request resolves before a current availability decision, so its retry still refers to the original loan. The fingerprint is copy+member; today is treated as execution context rather than a new business command.

returnCopy checks old terminal state first

A duplicate return exits before activeCopies.remove. That ordering prevents a stale return from removing another borrower’s active loan after copy reuse.

renew extends an existing promise

Use due.plusDays(capturedPolicy.days), not today plus days. This prevents an early renewal from shortening the existing period and makes terms deterministic.

holdQueue returns an immutable snapshot

External callers can inspect order without mutating the queue. Changes go through placeHold/cancelHold, which preserve member validation and uniqueness.

Complexity and limits

  • Checkout uses expected O(1) copy/member/request maps and O(1) queue-head access. Due-date arithmetic is constant for bounded LocalDate operations.
  • placeHold/cancelHold scan H title reservations for duplicate/removal, and current title validation scans C configured copies. A title index can remove that O(C) scan after measurement.
  • invariantHolds scans L retained loans and M members: O(L+M). It is a diagnostic/test check, not required in the hot path.
  • Space O(C+M+L+H+R) for copies, members, retained loans, holds and request records. Retention is intentionally unbounded over process lifetime; durability is not implemented.

Walk through the actual reference

These walkthrough fixtures are emitted only after the Java harness verifies their operations and expected state. Concurrency tests additionally exercise competing callers.

Copy identity and hold priority

Step 1 of 3: A checks out c1

Loan L1 due January 15; c1 unavailable

Invariant: One active loan per copy

Read the complete trace table
ActionState after actionInvariant
A checks out c1Loan L1 due January 15; c1 unavailableOne active loan per copy
B then C reserve titleQueue [B,C]; A renewal rejectedWaiting readers have priority
A returns, B checks out c1B now owns active copy; queue [C]Old loan return cannot release new loan

Policy cutover preserves loan terms

Step 1 of 3: Change v1 14 days to v2 7 days

Existing loan still refers to v1

Invariant: Historical policy immutable

Read the complete trace table
ActionState after actionInvariant
Change v1 14 days to v2 7 daysExisting loan still refers to v1Historical policy immutable
Renew B at original due dateDue extends to January 29 under v1Renewal uses captured term
Create C new loanDue January 8 under v2New loans use new policy

Mistakes and counterexamples

Treat a title as the lendable object

Failing case: c1 and c2 share title T; lending c1 makes c2 disappear.

Repair: Separate title metadata from physical copy identity.

Return by copy ID alone

Failing case: An old return event arrives after the same copy has been loaned to B.

Repair: Return by loan ID and check its terminal state before touching current ownership.

Consume a hold before checkout succeeds

Failing case: Head member is at the borrowing limit.

Repair: Validate first; pop the queue only with committed loan creation.

Renew with mutable global policy

Failing case: A new seven-day policy unexpectedly changes a fourteen-day loan.

Repair: Capture versioned terms and document whether renewal retains or switches them.

Engineer → Senior → Staff

Choose a deep dive

Model circulation using the correct identities.

Executed: checkout, return, due dates, member limits and basic title holds.

Change exercise

Add two copies of one title and demonstrate independent availability without bypassing the member cap.

Worked answer guidance

Key physical ownership by copyId. Keep titleId only for shared metadata and title-wide holds. Show the active loan/copy relationship directly in tests.

Interview follow-ups

Why is BookCopy an entity despite being represented as a record?

Entity is a domain concept based on identity, not a Java keyword. The record carries a stable copy ID; immutable representation does not erase identity.

Why use LocalDate rather than milliseconds for due dates?

The rule is expressed in library calendar days. Milliseconds introduce timezone/DST ambiguity; convert at the trusted boundary using the library zone.

Your design attempt

Each language has a separate draft across all three levels. Saving is device-only and does not sync to your account. Anyone using this browser profile can load it. Loading is always explicit.

Java 21 reference code is provided for local study. Use Run program in the editor to execute your code and test driver. Program runs show output; they do not grade your design.

Solution.java
Run program · Java 21

No unsaved changes · 208/20000

Self-review

Checks apply to this visit. Self-review is not a passed submission or verified mastery.

Open focused practice →

Provenance and scope of evidence

Original teaching material. The local contract is implemented by Solution.java and tested by Test.java on Java 21. Distributed persistence, real provider/device adapters and deployment are not claimed.

Reference verification is not independent editorial review, production deployment verification or a claim that distributed adapters are implemented.