Skip to main content
Create your own
Lesson illustration

Building a Library Management System

Hello! Welcome to your next low-level design case study.

In our last lesson, we designed a parking lot system using a structured, five-step framework. This framework is your guide to confidently navigating LLD interview questions, ensuring you cover all the critical aspects from requirements to implementation.

Today, we'll apply that same framework to another classic problem. Your learning outcome is to design a library management system with book borrowing, returns, and fine calculation. This case study will reinforce your understanding of core OOP principles, entity relationship modeling, and how to separate responsibilities within a system.

Let's quickly recall the 5-step framework we'll be using:

  1. Clarify Requirements & Scope
  2. Identify Core Entities & Use Cases
  3. Design Classes & Interactions
  4. Implement Core Logic
  5. Verify & Discuss Extensions

By following these steps, you will build a robust design for the library system and further sharpen your LLD problem-solving skills.

Step 1: Clarify Requirements & Scope

As before, we start with a broad prompt: "Design a library management system." Our first job is to ask clarifying questions to establish a clear set of functional and non-functional requirements.

To understand what a good set of requirements looks like for this problem, let's consult a well-structured guide.

Grokking the Object Oriented Design Interview

The article 'Grokking the Object Oriented Design Interview' provides a clear and comprehensive list of requirements for a library management system. This is a great example of the level of detail you should aim for after your initial Q&A with an interviewer.

Please read the section titled 'System Requirements'. Take note of the specific details, such as the maximum number of books a member can check out and the different ways a user can search for a book.

The process of arriving at these requirements is a dialogue. You need to probe the problem space. Let's see how this is done.

Google Interview Question Solved | Low Level Design of Library Management System - Part 1

The video 'Google Interview Question Solved | Low Level Design of Library Management System - Part 1' by Soumyajit Bhattacharyay demonstrates how to break down a problem statement into a list of requirements. The presenter's distinction between 'verb' (use case) and 'noun' (component) requirements is particularly insightful.

Watch the segment from 00:48 to 04:29. Pay attention to how the presenter analyzes each requirement to identify both system actions and system components. This thought process is key to moving from requirements to design.

Combining these resources, we have a solid foundation. Our system needs to manage books, members, borrowing, returns, reservations, and fines.

Step 2: Identify Core Entities & Use Cases

With our requirements defined, we can now identify the "nouns" that will become our core classes and the "verbs" that will become our primary use cases.

Based on the requirements, our main entities include:

  • Book, BookItem (a specific copy)
  • Member, Librarian (our actors)
  • Library (the main system)
  • Account
  • BookReservation, BookLending (or Checkout)
  • Fine

The main use cases are:

  • Search for a book.
  • Check out a book.
  • Return a book.
  • Renew a book.
  • Reserve a book.
  • Calculate and collect fines.

To visualize how these pieces fit together, interviewers often appreciate a simple Use Case Diagram. This diagram shows the actors and how they interact with the system's functions.

Google Interview Question Solved | Low Level Design of Library Management System - Part 1

Let's continue with the same video, which now moves on to identifying actors and creating a Use Case Diagram. This will help solidify our understanding of the system's boundaries and interactions.

Watch from 04:29 to 08:07. First, the presenter identifies the actors and use cases. Then, they construct a diagram that connects them. Notice the reasoning for why 'Search' should be a shared service accessible by both Members and Librarians to avoid code duplication. This is an application of the DRY (Don't Repeat Yourself) principle.

Step 3: Design Classes & Interactions

Now we move to the heart of the LLD process: defining the classes, their attributes, methods, and relationships.

A. Key Design Decisions

Let's think through some of the most important design choices.

1. Book vs. BookItem:
This is a critical distinction. A Book represents the abstract concept (e.g., "Clean Code" by Robert C. Martin), which has a title, author, and ISBN. A BookItem is a specific physical copy of that book, with a unique barcode and a status (e.g., Available, Loaned). The library might have ten BookItems corresponding to one Book. This one-to-many relationship is fundamental.

2. Actor Hierarchy:
Both Member and Librarian are people who interact with the system. We can model this using inheritance. A base Person class can hold common attributes like name and address. An Account class (or a SystemUser class as shown in some designs) can extend Person to add login credentials. Finally, Member and Librarian can extend Account, adding their specific attributes and behaviors. This leverages polymorphism and follows the Liskov Substitution Principle.

3. Service-Oriented Design:
Functionality like searching, issuing books, or calculating fines can be encapsulated in dedicated service classes. For instance, a SearchService can handle all search logic, and a FineService can manage fine calculations. This adheres to the Single Responsibility Principle (SRP) and makes the system more modular and maintainable. The Member and Librarian classes would then use these services (composition) to perform their tasks.

Let's watch a detailed walkthrough of how these classes can be designed.

GOOGLE INTERVIEW QUESTION SOLVED | LOW LEVEL DESIGN CODE | LIBRARY MANAGEMENT SYSTEM - PART2

The follow-up video, '...LIBRARY MANAGEMENT SYSTEM - PART2', provides an excellent, detailed explanation of the class design, covering the points we just discussed.

Watch these two key segments: Book and BookItem Design (02:00 - 05:25): Pay close attention to the justification for separating Book and BookItem. The presenter also introduces enums like BookStatus, which is a clean way to manage state. Actor Class Design (06:37 - 10:41): This section demonstrates the inheritance hierarchy for actors (Person -> SystemUser -> Member/Librarian) and explains why shared functionalities like search are composed as separate objects rather than duplicated in both classes.

B. UML Class Diagram

A UML class diagram brings all these ideas together into a single blueprint. It's the most important artifact you'll produce in an LLD interview.

UML Class Diagram for Library Management System
This UML Class Diagram shows the key classes and their relationships. Notice the `User` abstract class with `Student` and `Faculty` as concrete implementations, demonstrating inheritance. The `Library` class acts as a central hub, managing `Book`s and `User`s. The `Checkout` class links a `User` to a `Book` and includes logic for due dates and fines.

This diagram clearly shows:

  • Inheritance: The User hierarchy.
  • Composition: Library has a collection of Books and Users.
  • Association: A Checkout record associates a User with a Book.
  • Attributes and Methods: Key data members and functions for each class are laid out.

Step 4: Implement Core Logic

You won't be expected to write fully running code in a 45-minute interview, but you must be able to write the skeleton code for the most important operations. For our system, these are borrowing, returning, and calculating fines.

A. Borrowing, Returning, and Fine Calculation

Let's look at some clean Java code that implements these key use cases. This will demonstrate how the classes we've designed interact.

Grokking the Object Oriented Design Interview

The 'Grokking OOD' article provides excellent, concise Java code snippets that focus on the core logic. This is exactly the kind of targeted coding you'd do in an interview.

Navigate to the 'Code' section. Study the code for the Member class, specifically the methods checkoutBookItem(), returnBookItem(), and checkForFine(). Also, look at the BookItem and BookLending classes to see how they support these operations.

B. Focusing on the Fine Calculation

The calculateFine logic is a specific requirement of our learning outcome. Let's see how a dedicated service can handle this.

GOOGLE INTERVIEW QUESTION SOLVED | LOW LEVEL DESIGN CODE | LIBRARY MANAGEMENT SYSTEM - PART2

Let's return to the implementation video to see how the FineService is designed. This is a great example of SRP in action.

Watch the final segment from 12:46 to 14:34. The presenter designs a BookLendingClass and, most importantly, a FineService with a calculateFine method. This isolates the fine calculation logic from the Member or BookIssueService classes.

Test your understanding!

The Grokking example puts the checkForFine logic inside the Member class. The video example creates a separate FineService class. What are the pros and cons of each approach in the context of the SOLID principles?

Show answer
  • checkForFine in Member Class:

    • Pro: It's simple and intuitive. A member is responsible for their fines.
    • Con: It violates the Single Responsibility Principle (SRP). The Member class is now responsible for managing member data and for the business logic of calculating fines. If the fine policy changes (e.g., different rates for different member types or books), you have to modify the Member class.
  • Separate FineService Class:

    • Pro: It adheres to SRP. The FineService has one job: manage everything related to fines. This also supports the Open/Closed Principle (OCP). If you want to add a new way to calculate fines, you could implement a FineStrategy interface and inject it into the FineService, without changing the service itself. This design is more modular and extensible.
    • Con: It adds a bit more complexity with an extra class and the interaction between them.

For a robust, enterprise-level system, the FineService approach is superior. It demonstrates a deeper understanding of SOLID principles.

Step 5: Verify & Discuss Extensions

Finally, you should be able to walk the interviewer through a scenario to prove your design works and discuss how you might extend it.

A. Verifying with a Sequence Diagram

A sequence diagram is perfect for showing how objects collaborate over time to fulfill a use case.

UML Sequence Diagram for Library Management System
This UML sequence diagram illustrates the flow of interactions. When a Member wants to `borrowBook()`, they call the `Library`. The `Library` checks the `Book`'s availability, marks it as borrowed, and creates a `Transaction` record. For a `returnBook()`, the `Library` closes the `Transaction`. If the return is late, the `Transaction` object can use a `FineStrategy` to `calculateFine()` and determine the amount owed.

You can use this diagram to narrate the entire process, explaining which object calls which method in what order.

B. Discussing Extensions

A great way to end is by showing you've thought about future needs.
Interviewer: "This is a great design for books. How would you extend it to handle other library items like magazines or academic journals, which have different borrowing periods and fine rates?"

Your Response:
"That's an excellent question. We can handle this elegantly using polymorphism.

  1. I would introduce a LibraryItem abstract class, similar to the approach in the Library Management System - Java OOP Case Study document (LINK).
  2. This LibraryItem class would have an abstract method: abstract double calculateLateFee(int daysLate);.
  3. Our existing Book class would extend LibraryItem. We would also create new classes like Magazine and Journal that also extend LibraryItem.
  4. Each of these subclasses would provide its own concrete implementation of the calculateLateFee method, containing its specific fine logic (e.g., $1.50/day for books, $1.00/day for magazines).
  5. The rest of the system, like the Member or FineService, would continue to work with the LibraryItem interface. When they call calculateLateFee(), Java's runtime polymorphism will automatically execute the correct version of the method based on the object's actual type (whether it's a Book, Magazine, etc.). This adheres to the Open/Closed Principle, as we can add new item types without modifying the existing code that handles fine calculations."

Conclusion

Fantastic work! You have successfully applied the 5-step LLD framework to design a Library Management System.

Key Takeaways:

  • Framework is Reusable: The structured approach of clarifying, identifying entities, designing classes, implementing logic, and verifying is a powerful and reusable tool for any LLD problem.
  • Model the Real World: The Book vs. BookItem distinction is a crucial insight that comes from carefully modeling the real-world domain.
  • Leverage OOP and SOLID: We used inheritance for actors (Person -> Member) and polymorphism for extensibility (LibraryItem hierarchy). We applied SRP by creating separate service classes (SearchService, FineService).
  • Visualize Your Design: UML diagrams (Class and Sequence) are invaluable tools for clarifying your own thoughts and communicating your design to others.

In the next lesson, we will tackle our third case study: designing an elevator control system. This will introduce new challenges, particularly around state management and request scheduling, allowing you to apply your design skills to a different kind of problem.

Can't find a good explanation? Sign up and we'll make it for you

Sign up