One of the worst types of interviews for me is the system design. It feels overwhelming, even though i studied computer science, i took all the network and operating systems and DBMS courses. I have an idea on how to explain what a distributed system is. Put me in an interview, though, and sometimes my brain just goes blank.
So usually in these interviews you either get a screenshot or you're given a broad prompt like:
Design a notification system.
Design a URL shortener
Design netflix
On one hand, you're thinking that these systems took entire teams years to design. On the other, your brain is already jumping to WebSockets, caching, React state, API endpoints, databases, pagination, and whether you're somehow expected to know how many servers Instagram has.
Let's take a step back. Before deciding how we are going to build something, we need to know what we are building. So let me introduce you to.. functional requirements.
What are functional requirements?
Functional requirements describe what a system should allow its users to do. You have to clarify what the capabilities of the product is and how it should behave without knowing or specifying how these will be implemented.
Design a notification system for a web application
This is very broad, and give this prompt to 10 people and you'll get 10 different sets of requirements. So what a 'notification system' means? Are these notification real-time? Can users interact with them? Do we need to keep a history? Can users mark them as read? Do they disappear?
Before drawing a single architecture box, we need to establish the scope of the problem we are talking about.
A first set of functional requirements could be:
- Users can receive notifications.
- Users can view their notifications.
- Users can mark a notification as read.
- Users can mark all notifications as read.
- Users can navigate from a notification to a details page.
- Users can see how many unread notifications they have.
- Users can receive new notifications without manually refreshing the page.
Functional vs non-functional requirements
This distinction becomes particularly important in system design interviews.
- Functional requirements describe what the system does.
- Non-functional requirements describe how well the system needs to do it or the constraints under which it operates.
For our notification system, these could include:
| Functional requirement | Related non-functional concern |
|---|---|
| Receive new notifications | Updates should appear with low latency |
| View notification history | Large histories should load efficiently |
| Mark notifications as read | UI updates should feel immediate |
| See unread count | Count should remain consistent across the application |
| Open related content | Navigation should be reliable and accessible |
Accessibility, performance, reliability, scalability, browser support, and latency are usually concerns that influence our architecture without defining the product feature itself. Usually all of these are non-functional requirements.
Don't accept the prompt as the specification
One of the most important things to remember in a system design interview is that the interview prompt is usually intentionally incomplete. You don't get a specification, you have to deduct it with your interviewer. The most important thing in these type of interviews is to ask questions.
For example good questions in our example could be:
- What kinds of notifications are we supporting?
- Do notifications need to arrive in real time?
- Do users need access to their notification history?
- Can notifications be deleted?
- Do we need read/unread state?
- Should notifications synchronize across multiple tabs or devices?
- How many notifications might a user receive?
- Are we designing only the web experience, or mobile too?
If the interviewer tells you that notifications only need to update when the page reloads, your architecture will look very different from a system expected to deliver millions of real-time updates.
Make assumptions explicit
Sometimes the interviewer won't give you every answer, and leave it up to you. So at this point inevitable you will make an assumption. Make an assumption and say it out loud.
For example:
I'll assume we're designing the web notification center, notifications should arrive while the application is open, users can mark them as read, and we're not covering email or push notifications.
That single sentence dramatically reduces the problem scope.
Now instead of designing Every Notification System Known to Humanity, we're designing something concrete. This is one of the reasons functional requirements are so useful: they establish the boundaries of the system.
Requirements drive architecture
Once we understand the requirements, technical decisions start having a reason to exist.
Suppose one requirement says:
Users should receive new notifications while using the application without refreshing the page.
Now we have a technical problem to solve.
How our system can solve this concrete problem? We could consider:
- polling
- Server-Sent Events
- WebSockets
So, we didn't jump immediately to a conclusion to use Websockets? We derived it from a user requirement and the architecture followed.
Users can view older notifications.
Now we need to think about pagination and data fetching.
Users can mark notifications as read.
Now we need to think about mutations, optimistic updates, error handling, and synchronization.
Users can see their unread count throughout the application.
Now we need to think about where that state lives and how different parts of the UI stay consistent.
From requirements to frontend architecture
A useful way to think about the process is:
Functional requirements
↓
User flows
↓
Data model
↓
API contracts
↓
Client architecture
↓
State management
↓
Rendering & performance
↓
Accessibility
These aren't perfectly isolated steps. Real systems are messy, requirements change, and decisions influence each other. But we move from a non defined problem to an architectural decision.
Going back to our notification example: the user flow "click the bell, see 5 unread, mark one, count drops to 4" already forces a data model decision about where read/unread state lives, which in turn shapes the API contract and how the client keeps that count in sync. Each arrow in the pipeline above is really a question you're answering, not just a step you're passing through.
Functional requirements also protect your scope
System design prompts can become enormous very quickly.
For example:
Design Instagram.
What does that even mean? The feed? Posting photos? Stories? Profiles?
It's impossible trying to design all of Instagram in a 45-minute interview, despite what all the vibe coders tell you.
Perhaps we can agree with the interviewer that we are designing the home feed and narrow down the problem to:
- Users can view posts from accounts they follow.
- Users can continuously load older posts.
- Users can like a post.
- Users can open a post.
- Users can see new content when it becomes available.
And booom...now we have something we can actually design.
Start with "what", then design "how"
System design interviews aren't a competition to mention the largest number of technologies before the clock runs out. They're about making engineering decisions under incomplete information.
Functional requirements give those decisions context.
Suddenly, you're not designing Netflix anymore but a specific set of behaviours with specific problems to solve.
And once you know what you're building, reasoning about how to build it becomes a lot less scary.
At least that's what I'm trying to teach my brain before my next system design interview. 😅
Top comments (0)