Most candidates walk into a system design interview and immediately start listing features.
“Users can post. Users can follow. Users can like.”
That’s not wrong - it’s just shallow. It tells the interviewer you understand the product, not that you can design a system. At the senior level, the expectation isn’t a feature list. It’s a system contract - a precise, scoped set of behaviours that drives every architectural decision that follows.
The first five minutes of your design interview - the requirements phase - is where you win or lose the round. Get it right, and every component you draw has a reason to exist. Get it wrong, and you spend 35 minutes defending an architecture that solves the wrong problem.
Why Most Candidates Get This Wrong
There’s a pattern that plays out hundreds of times:
Interviewer: “Design a notification system.”
Candidate: “Okay, so users can receive notifications. They can mark them as read. They can see a list of notifications.”
Then they jump to the architecture. High-level diagram. Kafka somewhere. A database. Done.
The problem? They never asked:
- Who sends the notification - the user, the system, or an external service?
- Is the notification real-time (push), or is polling acceptable?
- Can a single event trigger notifications across multiple channels (push, email, SMS)?
- Are notifications personalised? Batched? Deduplicated?
- What happens if a notification fails to deliver - retry? Dead letter? Silent drop?
These aren’t edge cases. These are the questions that determine whether you need a simple queue or a multi-channel orchestration engine. The architecture is completely different depending on the answers.
Senior engineers don’t list features. They interrogate the problem space until the system’s boundaries are unambiguous.
The Mindset Shift: FRs Define the System’s Contract
A functional requirement isn’t “what the system does.” It’s what the system promises to do, under what conditions, for whom.
Think of FRs as the public API of your system - not the REST endpoints, but the behavioural guarantees. Every FR should answer three implicit questions:
- Who is the actor? (End user, admin, internal service, cron job)
- What is the action? (Create, read, update, delete, trigger, subscribe)
- What are the constraints? (Ordering, uniqueness, idempotency, visibility, timing)
When you frame FRs this way, you stop listing features and start defining behaviour. And behaviour is what drives architecture.
A Framework for Listing FRs
Here’s a framework that works. It’s not a rigid template - it’s a thinking tool. The goal is to systematically cover the problem space without missing the things that matter.
Step 1: Identify the Core Use Case
Before listing anything, state the single most important thing the system does. One sentence. No “and.”
- URL Shortener: “Convert a long URL into a short, unique alias that redirects to the original.”
- Chat System: “Deliver a message from one user to another in near real-time.”
- Rate Limiter: “Enforce a maximum number of requests per client within a sliding time window.”
This is your north star. Every FR you list should either directly enable this or be a necessary extension of it.
Anti-pattern: Starting with “Users can sign up and log in.” Authentication is almost never the core use case. Don’t lead with it unless you’re literally designing an auth system.
Step 2: Walk the User Journey, Not the Feature List
Don’t brainstorm features in isolation. Instead, trace the end-to-end journey of the primary actors.
For a notification system:
- An event occurs (someone likes your post)
- The system determines who should be notified
- The system selects the channel (push, email, SMS, in-app)
- The system constructs the message (template, personalisation)
- The system delivers the notification
- The user receives and interacts with it (read, dismiss, click through)
- The system records the delivery state (sent, delivered, read, failed)
Each step in this journey is a candidate for an FR. But more importantly, each step surfaces questions you need to ask the interviewer.
“Should the system support multiple channels per event?” - This determines whether you need a channel router.
“Can a user configure notification preferences?” - This adds a preference service and a filtering layer.
“What happens at step 6 if the user is offline?” - This determines your delivery guarantee model.
Step 3: Separate What the System Must Do from What It Could Do
This is where senior candidates distinguish themselves. You should explicitly categorise your FRs:
Must Have (P0) - Without these, the system doesn’t fulfil its purpose.
Should Have (P1) - Important for production readiness, but the core works without them.
Could Have (P2) - Nice to have, mention them to show breadth, then park them.
Example for a URL shortener:
| Priority | Functional Requirement |
|---|---|
| P0 | Given a long URL, generate a unique short URL |
| P0 | Given a short URL, redirect to the original long URL |
| P1 | Short URLs expire after a configurable TTL |
| P1 | Users can create custom aliases (vanity URLs) |
| P1 | Analytics: track click count per short URL |
| P2 | Users can update the destination URL without changing the alias |
| P2 | Bulk URL shortening via API |
Then tell the interviewer: “Let’s focus on P0 and P1 for the design. Happy to revisit P2 if we have time.”
This does two things: it shows you can scope, and it buys you permission to ignore complexity that doesn’t add signal.
Step 4: Ask the Constraint-Revealing Questions
The best FRs come from the questions you ask, not the ones you answer. Here’s a set of high-signal questions organised by category:
Data flow:
- Is this read-heavy or write-heavy?
- Does the user need to see their own writes immediately (read-after-write consistency)?
- Is the data append-only or mutable?
User model:
- Is there a single user type, or are there distinct roles (buyer/seller, viewer/creator)?
- Can actions be performed on behalf of another user (delegation, admin override)?
Scope and boundaries:
- Is this a standalone system, or does it integrate with existing services?
- Which parts are we designing vs. assuming exist (auth, payments, storage)?
Ordering and uniqueness:
- Do events/messages need to be processed in order?
- Do we need idempotency (retrying the same action shouldn’t create duplicates)?
- Is there a uniqueness constraint (one like per user per post)?
Delivery guarantees:
- Is at-least-once delivery acceptable, or do we need exactly-once?
- What is the acceptable latency for the primary operation?
Don’t ask all of these mechanically. Pick the ones that are relevant to the problem, and use them to refine your FRs. The interviewer will fill in gaps, and every answer sharpens your architecture.
Step 5: State FRs as Precise Behaviours, Not Vague Features
This is the difference between a junior and a senior FR list.
Vague (junior):
Users can send messages.
Precise (senior):
A user can send a text message (up to 10 KB) to another user. The message must be delivered in order within a conversation. The sender should see the message as “sent” immediately (optimistic UI), and the recipient should see it within 500ms if online. Offline recipients receive the message upon reconnection.
The precise version contains four architectural signals:
- Size constraint (10 KB) → affects storage and transport
- Ordering guarantee → requires sequence numbers or timestamps per conversation
- Optimistic UI → client-side state management, eventual consistency
- Offline delivery → message persistence, delivery queue, presence tracking
You don’t need to write an essay for each FR. But each one should be specific enough that two engineers reading it would design roughly the same system.
Full Example: Design a Feed System
Let’s walk through the framework end to end.
Interviewer: “Design a social media feed - like Twitter’s home timeline.”
Step 1: Core Use Case
“Show a user a chronologically ordered stream of posts from people they follow.”
Step 2: User Journey
- User A creates a post
- Post becomes visible to User A’s followers
- Follower (User B) opens their feed
- System assembles and returns a ranked/ordered list of posts
- User B scrolls, triggering pagination
- User B interacts with a post (like, reply, share)
Step 3: Prioritised FRs
| Priority | FR |
|---|---|
| P0 | A user can create a text post (up to 280 characters) |
| P0 | A user can follow/unfollow other users |
| P0 | A user’s home feed shows posts from users they follow, in reverse chronological order |
| P0 | Feed supports cursor-based pagination (fetch next N posts) |
| P1 | Posts can include images (up to 4 per post) |
| P1 | A user can like a post; like count is visible on the post |
| P1 | Feed updates in near real-time - new posts appear without requiring a manual refresh |
| P2 | Feed ranking: posts may be ranked by relevance instead of strict chronology |
| P2 | A user can repost (share) another user’s post |
| P2 | Replies and threads |
Step 4: Constraint-Revealing Questions Worth Asking
-
“How many users are we designing for? Millions of followers per user (celebrity problem), or mostly small graphs?” → This determines fan-out strategy: fan-out-on-write vs. fan-out-on-read.
-
“Should the feed be strictly chronological, or are we incorporating ranking/ML?” → Strict chronology is a sorted merge. Ranking requires a scoring service and probably a precomputation layer.
-
“When User A posts, how quickly should it appear in User B’s feed?” → Seconds (near real-time) → push model, WebSockets. Minutes (acceptable lag) → pull model, caching.
-
“Can a user delete a post? If yes, does it disappear from all feeds retroactively?” → Soft delete vs. hard delete. If retroactive, every cached feed is potentially stale.
-
“Is there a concept of private accounts or blocked users?” → Adds a visibility filter layer to feed assembly.
Step 5: Refined P0 FRs (Stated Precisely)
-
Create Post: A user can publish a text post (up to 280 characters). The post is immediately visible on their profile and begins propagating to followers’ feeds.
-
Follow/Unfollow: A user can follow another user. Following is unidirectional. Unfollowing removes future posts from the feed but does not retroactively remove past posts.
-
Home Feed: A user’s home feed returns posts from all followed users, ordered by creation time (newest first). The feed is eventually consistent - a new post may take up to a few seconds to appear.
-
Pagination: The feed supports cursor-based pagination. The client provides a cursor (last seen post ID + timestamp), and the server returns the next page. Page size is configurable (default 20).
Notice how each FR now contains enough detail to directly inform component design:
- FR 1 tells you the write path and fanout trigger
- FR 2 tells you the social graph storage requirements
- FR 3 tells you the consistency model and read path
- FR 4 tells you the pagination strategy and API contract
Common Anti-Patterns
1. The Feature Dump
Listing 15+ features with no prioritisation. The interviewer doesn’t want a PRD. They want to see that you can scope aggressively and focus.
2. The NFR Leak
Mixing non-functional requirements into your FR list. “The system should handle 10K requests per second” is an NFR (scalability), not an FR. Keep them separate. State FRs first, then pivot to NFRs (latency, throughput, availability, consistency).
3. The Assumption Trap
Assuming constraints without confirming. “Let’s assume we need exactly-once delivery” - don’t assume. Ask. Assumptions are fine when you state them explicitly and the interviewer doesn’t push back.
4. The Kitchen Sink
Designing for every possible extension upfront. “We should also support video posts, stories, disappearing messages, and monetisation.” No. Scope to P0, design for P0, extend if time permits.
5. Skipping FRs Entirely
Jumping straight to architecture. “Let me draw the high-level diagram.” This is the biggest red flag at the senior level. It signals you’re pattern-matching from a memorised solution, not reasoning from first principles.
The Checklist
Use this as a mental checklist before you say “Okay, let me start designing.”
- Core use case stated in one sentence
- Primary actors identified (who uses the system?)
- User journey traced end to end (happy path)
- FRs prioritised into P0 / P1 / P2
- P0 FRs are precise - they specify behaviour, not just capability
- Constraint-revealing questions asked (data flow, ordering, delivery, scope)
- Assumptions stated explicitly (what you’re choosing not to design)
- FRs and NFRs separated - you know which is which
- Scope confirmed with the interviewer - “Let’s focus on P0 and P1”
- Every FR maps to an architectural decision - if it doesn’t drive the design, it doesn’t belong
Closing Thought
The requirements phase isn’t a warm-up. It’s not the “easy part” before the “real” design begins. It is the design. Every box you draw, every queue you add, every database you choose exists because a functional requirement demands it.
Get the FRs right, and the architecture writes itself. Get them wrong, and no amount of clever component design will save you.
Spend the first five minutes like they matter more than anything else. Because they do.
Comments