Loading content...
Every exceptional software system begins not with code, not with architecture diagrams, not even with technology choices—but with a crystal-clear understanding of what the system must do. These are functional requirements: the behaviors, actions, and capabilities that define a system's purpose.
In the context of Low-Level Design, understanding functional requirements is not merely a procedural step—it is the intellectual foundation upon which every class, interface, method, and data structure is built. Miss a functional requirement, and you'll build the wrong system. Misunderstand one, and you'll design components that don't fit together. Overlook edge cases within requirements, and your design will crumble under real-world conditions.
This page will transform how you approach the "what does the system do?" question. You'll learn to extract requirements with surgical precision, categorize them systematically, and use them as the compass that guides every design decision.
By completing this page, you will master: • The precise definition of functional requirements and their distinction from other requirement types • Systematic techniques for extracting functional requirements from problem statements • How to decompose complex requirements into actionable, designable components • Methods for validating completeness and consistency of functional requirements • Real-world patterns for translating requirements into design artifacts
Functional requirements describe what a system must do—the specific behaviors, features, and functions that the system must exhibit. They answer questions like:
In contrast to non-functional requirements (which describe how well the system performs—speed, reliability, scalability), functional requirements are about capability and behavior.
Ask yourself: "Can I demonstrate this requirement by showing the system doing something?" If yes, it's likely a functional requirement. If the answer is about speed, reliability, or quality characteristics, it's probably non-functional.
Example: "Users can search for books by title" → Functional (demonstrable action) Example: "Search returns results in under 200ms" → Non-functional (quality characteristic)
A well-formed functional requirement has several key components:
| Component | Description | Example |
|---|---|---|
| Actor | Who or what initiates the behavior | User, Admin, External System, Scheduled Job |
| Action | The verb describing what happens | Create, Update, Delete, Search, Calculate, Notify |
| Object | What entity is being acted upon | Order, User Account, Payment, Reservation |
| Preconditions | What must be true before the action occurs | User must be authenticated, Item must be in stock |
| Postconditions | What must be true after the action completes | Order status changed to 'Confirmed', Email sent |
| Business Rules | Constraints that govern the behavior | Maximum 5 items per order, Discount applies only to premium members |
Functional requirements can be organized into several meaningful categories that help ensure completeness:
In LLD interview scenarios and real-world design tasks, requirements don't arrive as neat lists. They come embedded in problem statements, buried in conversations, or implied by context. The ability to extract requirements is a critical skill.
This foundational technique systematically identifies actors, actions, and entities:
Let's apply the extraction technique to a typical LLD problem:
Problem Statement: "Design a library management system. The system should allow librarians to add, update, and remove books. Members can search for books, borrow available books, and return them. The system should track borrowing history and send overdue notifications. Members can reserve books that are currently borrowed by others."
From the extraction above, we can formalize the following functional requirements:
| ID | Requirement | Actor | Category |
|---|---|---|---|
| FR-001 | Librarians can add new books to the catalog | Librarian | Data Management |
| FR-002 | Librarians can update book information | Librarian | Data Management |
| FR-003 | Librarians can remove books from the catalog | Librarian | Data Management |
| FR-004 | Members can search books by title, author, or ISBN | Member | User Operations |
| FR-005 | Members can borrow available books | Member | User Operations |
| FR-006 | Members can return borrowed books | Member | User Operations |
| FR-007 | System tracks complete borrowing history per member | System | Data Management |
| FR-008 | System sends notifications for overdue books | System | Automated Behavior |
| FR-009 | Members can reserve books currently borrowed by others | Member | User Operations |
The most dangerous requirements are those never explicitly stated but absolutely expected. Missing an implicit requirement can derail an entire design. Expert designers develop intuition for uncovering these hidden requirements.
Implicit requirements typically fall into predictable categories:
For every explicit requirement, ask: • Who is allowed to perform this action? (Authorization) • What validation must inputs pass? (Data validation) • What if it fails? (Error handling) • What state changes occur? (State management) • Should this be auditable? (Audit trail) • Can this happen concurrently? (Concurrency) • Are there limits or boundaries? (Edge cases)
This systematic questioning reveals hidden requirements before they become design defects.
Consider the explicit requirement: "Members can borrow available books."
Applying our checklist reveals numerous implicit requirements:
| Category | Implicit Requirement | Design Impact |
|---|---|---|
| Authorization | Only authenticated members can borrow | Need authentication check before borrow operation |
| Validation | Book must exist and be available | Check book status before allowing borrow |
| State Change | Book status changes to 'Borrowed' | Update book state and record borrower |
| State Change | Borrowing record is created | Create association between member and book with date |
| Edge Case | Member may have borrowing limit | Check current borrowed count against limit |
| Edge Case | Book may have outstanding reservations | Determine who gets priority—first reserver? |
| Concurrency | Two members might borrow simultaneously | Need atomic check-and-update for book status |
| Error Handling | What if book is suddenly unavailable? | Return clear error message, suggest alternatives |
| Audit | Track who borrowed what and when | Store borrower ID, book ID, timestamp |
This single explicit requirement expanded into nine implicit requirements that directly impact the design. Each one requires class responsibilities, method behaviors, or data structures to be addressed.
Complex requirements often need decomposition before they can drive design decisions. A high-level requirement like "Members can borrow books" actually encompasses multiple sub-behaviors that need individual attention.
Complex requirements form hierarchies where high-level capabilities decompose into specific operations:
12345678910
FR-005: Members can borrow available books├── FR-005.1: System verifies member authentication├── FR-005.2: System validates book exists and is available├── FR-005.3: System checks member hasn't exceeded borrowing limit├── FR-005.4: System checks for active reservations by other members├── FR-005.5: System updates book status to 'Borrowed'├── FR-005.6: System creates borrowing record with due date├── FR-005.7: System calculates due date based on book type/member tier├── FR-005.8: System notifies member of successful borrowing└── FR-005.9: System cancels member's own reservation if existsDecomposition follows a disciplined process:
Each sub-requirement often maps to a specific design element: • Validation steps → Guard clauses or validator classes • State changes → Domain entity methods • Side effects → Domain events or direct calls • Error handling → Exception classes and handlers • Cross-cutting concerns → Interceptors, decorators, or aspect-oriented patterns
Let's decompose the "Reserve a Book" requirement completely:
FR-009: Members can reserve books currently borrowed by others
Not all requirements are equally important. In LLD interviews and real projects, time is limited. You must prioritize which requirements to address first and which can be deferred or simplified.
A classic prioritization technique that categorizes requirements:
| Category | Meaning | LLD Interview Approach |
|---|---|---|
| Must Have | Core functionality without which the system is useless | Design these first and most thoroughly. They define your core classes. |
| Should Have | Important functionality expected in a complete system | Design after core is solid. Show awareness but may simplify. |
| Could Have | Nice-to-have features that enhance the system | Mention during discussion. Design may note extension points. |
| Won't Have | Out of scope for current iteration | Explicitly state exclusions. Shows scoping discipline. |
In LLD interviews, explicitly state your prioritization:
"For the core design, I'll focus on the Must-Have requirements: book management and borrowing. I'll design the system to be extensible for reservations and notifications, but I'll detail those only if time permits."
This demonstrates maturity and pragmatism—interviewer-winning qualities.
Another useful distinction separates core requirements (essential for MVP) from extended requirements (complete feature set):
Functional requirements don't just inform design—they directly generate design artifacts. Understanding this mapping accelerates the transition from requirements to implementation.
| Requirement Element | Design Artifact | Example |
|---|---|---|
| Primary entity nouns | Domain classes/entities | Book → Book class with properties |
| Action verbs | Service methods or entity behaviors | Borrow → BorrowingService.borrowBook() or Member.borrow(book) |
| Business rules | Validation logic, policy classes | Max 5 books → BorrowingPolicy.canBorrow(member) |
| State changes | State machine patterns, status enums | Book status → BookStatus enum + state transitions |
| Relationships | Associations, aggregations | Member borrows Books → Member has list of Borrowings |
| Events/Notifications | Domain events, observer pattern | Overdue notification → BookOverdueEvent + handlers |
| Search/query operations | Repository methods, query objects | Search by title → BookRepository.findByTitle() |
Professional requirements management maintains traceability—the ability to trace from requirement to design element to code to test. While full traceability may be overkill for LLD interviews, understanding the concept strengthens your design thinking.
12345678910111213141516171819202122
## FR-005: Members can borrow available books ### Design Elements- **Service:** BorrowingService.borrowBook(memberId, bookId)- **Entity:** Borrowing (links Member, Book, with dueDate)- **Validation:** BorrowingPolicy.validateBorrowing(member, book)- **State Change:** Book.status transitions from AVAILABLE to BORROWED- **Event:** BookBorrowedEvent raised for downstream processing ### Key Classes Involved- Member (borrower)- Book (item borrowed)- Borrowing (the transaction record)- BorrowingService (orchestrates the operation)- BorrowingPolicy (encapsulates business rules) ### Tests Required- testBorrowBook_Success- testBorrowBook_BookNotAvailable- testBorrowBook_MemberAtLimit- testBorrowBook_BookNotFound- testBorrowBook_ConcurrentBorrowingEven experienced designers fall into requirement-related traps. Awareness of these pitfalls prevents costly mistakes.
Assuming you understand requirements without validation. In interviews, always restate your understanding: "So the system needs to support X, Y, and Z. Is that correct?" This catches misunderstandings early and shows communication skill.
Functional requirements are the foundation upon which all design decisions rest. Mastery of requirements gathering separates architects from coders.
What's Next:
With a solid understanding of functional requirements, we turn to their equally important counterpart: non-functional requirements. These define how well the system performs its functions—speed, reliability, scalability, security, and more. Together, functional and non-functional requirements provide the complete picture needed for robust low-level design.
You now understand how to identify, extract, analyze, decompose, and prioritize functional requirements. This skill forms the foundation for every design decision you'll make. In the next page, we explore non-functional requirements—the quality attributes that separate good systems from great ones.