loading...
Cover image for Get Hired: The System Design Interview, Explained

Get Hired: The System Design Interview, Explained

techdebtor profile image sam ・8 min read

I had a revelation while job searching. It seems like all software engineer interview prep focuses on coding interviews, but the money is in the system design interview. Here's why: Coding interviews tend to be pass/fail because you either got the solution or you didn't, but system design interviews are graded on a spectrum because they're more open-ended.

Put in a different way, the system design interview distinguishes junior engineers from senior engineers. Coding interviews prove that you know how to write code; system design interviews prove that you know how to build software. Something interesting I noticed while interviewing for a senior full-stack engineering role was that not every company tested for data structure and algorithm knowledge, but every company tested me on system design in their on-site interview. System design interviews are important.

And tbh, I think they're cool. Don't get me wrong, I've had some bad system design interviews (which I will gladly πŸ‘ go off πŸ‘ about in the comments if anyone asks), but I've had some good ones, too. I've had a few interviews where designing actually felt fun and collaborative.

So I want to walk you through a system design question I would ask when I interviewed engineers for my old team. I'll show you what separates junior engineers' answers from senior engineers' answers. And I'll give recommendations on how to prepare for an interview. If anything below is unfamiliar to you, don't panic - I drop some links at the bottom where you can learn more.

Overview

First up, what is a system design interview? A system design interview is an interview where the candidate is asked to design software end-to-end. In its most basic format, the prompt is something like, "Design Twitter." and the candidate has an hour to draw up how they'd design Twitter, including its data model and API. Some interviews are guided - the interviewer will draw an existing architecture on the board and the candidate will expand on the design. But often, the candidate starts from nothing and builds up a product over the course of the interview.

But what does it mean to design software end-to-end? This is what separates junior engineers from senior engineers. When you're new to software engineering, your perspective is smaller, so you'll naturally focus in on implementation details - you may spend the majority of your time talking about your app's class structure and data model. A senior engineer will cover those, but they will also talk about operational concerns like database replication schemes and load balancers. The difference is in scope.

How to Answer a System Design Question

Here's my method to answering a system design question:

  1. Clarify the question and the scope.
  2. Draw out the most basic infrastructure you can.
  3. Define the API between server and client.
  4. Define the database schema.
  5. Optimize for performance and availability.

Your needs will vary depending on the format of the interview, but if you're not given much structure, this checklist is a good place to start. Let's see what this looks like in practice.

Example Question: "Design Facebook Messenger."

Why did I pick this question? My old team at Salesforce asked this question because our product was a less well-known messenger, and we expect senior engineers to come in with a basic knowledge of how chat apps work. If the candidate was unfamiliar with Facebook Messenger, we would give them an overview of how the app functions and let them know what functionality we were interested in seeing them design.

1. Clarify the question and the scope.

The first question out of your mouth should be, "What features should I focus on?" Following that, you should ask, "How many users should I expect to have?" The answer to these questions will guide your design. The features will guide your API and database design, and the scale will determine what the best way to optimize will be.

For this question, we'll say we're targeting sending 1,000,000 messages per second and the features we want to focus on are sending and receiving text messages and viewing chat history. We'll say you can send and receive messages to anyone on the app and your chat history should persist indefinitely.

2. Draw out the most basic infrastructure you can.

A diagram with a server, database, and two clients

Every problem will have at least a server, a client, and a database. In this particular problem, there will be two clients using a server as a middleman to chat, and there will be a database attached to the server to store things like user information and message history.

This step lays the foundation of your whole diagram. It may seem trivial to draw such a small diagram, but your interviewers will understand you much better if you're able to point to a diagram when talking about how data flows in your system.

One important decision you need to make at this stage: Will you be using a SQL database or a NoSQL database? Be prepared to discuss the tradeoffs you made in your decisions. You could certainly use a NoSQL database here, but this design will be using a SQL database because we want to relate all messages back to account IDs.

3. Define the API between server and client.

We said that we'd first focus on sending and receiving messages. So what does the flow for that look like?

User A sends a message to the server, which forwards it to User B

User A sends a message to the server. The server then forwards the message to User B. User B receives the message and it renders in their client.

We can take this verbal description and turn it into pseudocode.

//client pseudocode

function sendMessage(message) {
  //REST call to post message to our backend server
}

function receiveMessage(message) {
  //we can receive the message via long poll, web socket, or server-side event
  //once message is received, render it to the screen
}
//server pseudocode

public void passMessage(message, userA, userB) {
  //receive the message from User A via a REST post 
  //store the message in the database
  //post the message to User B
}

Your interviewer may have specific scenarios they want to build on here. One follow-up question I'd often ask would be, "What would you do if a message failed to send?" You can then amend your existing API methods to include an exponential retry, or you could add retrying messages as a feature with its own API methods. After you've finished one feature (messaging), you can repeat the process for the next (viewing chat history).

4. Define the database schema.

One thing I want to emphasize throughout this whole process is keeping it simple. At every step, you're trying to get down the minimum viable product. The database schema is no different.

Here's what a simple database schema for a messenger looks like:
A database schema defining User and Message entities

There's a User entity that holds a user ID and a name, and a Message entity that holds a message ID, the sender's user ID, the recipient's user ID, the message timestamp, and the message body. Notice how I didn't write down any data types? This is a strategy you can use to keep the discussion high-level. If the interviewer cares, they'll ask, and then you can talk through what data type each column should be. But if they don't care, then they won't ask, which will save you from having to make a bunch of technical decisions.

5. Optimize for performance and availability.

So you've got a system written down now that can pass messages back and forth and store them. The next step is to identify system bottlenecks.

Our system will do two things: send and receive messages between users, and store and retrieve messages from the database. Let's examine how each of those operations could slow down, and what to do to fix it.

1. Sending and receiving messages

How are we going to handle sending and receiving 1,000,000 messages at once? As a rule of thumb, a single server can handle 50,000 connections at a time. This means we'll need 20 servers if we can process each message in under a second. In order to distribute requests evenly, we'll add a load balancer using a round robin algorithm to determine which client goes to which server.

Server pool architecture diagram

2. Storing and retrieving messages

Since we're writing every message to the database, we'll be doing 1,000,000 write operations per second. But what about our read operations? We will definitely need to retrieve messages from the database whenever a user loads a page. However, we shouldn't load all of a conversation history at once, as the query performance would be very slow. We should implement lazy loading so that we only retrieve a set number of messages upfront and then query for more as the user scrolls up into the conversation history.

With that in mind, let's say we anticipate 10,000 message reads per second as the user loads the page or scrolls up. This gives us a read:write ratio of 1:100, making it a write-heavy system. This tells us that we need to optimize for the number of concurrent writes. One solution would be to partition the database based on a hash of the message sender's ID and put the shards on different servers. This would reduce contention for database connections, as traffic would be distributed fairly evenly between shards. It would also keep message retrieval efficient, as each conversation would require you to go to exactly 2 shards to grab the entire conversation history.

Next Steps

In my experience, this is about as far as you'll get in a 60 minute interview. If you do have additional time, you could optimize for availability with database replication or you could add additional features to your design. For example, how would you implement a friends list within this system?

Resources

Here are some resources where you can learn more about the topics discussed above.

API Design

SQL vs. NoSQL

SQL Databases

NoSQL Databases

Database Sharding

Database Replication

Other System Design Interview Guides

Parting Advice

One difficult thing about system design interviews is that there's not just one correct answer. In many ways, system design is more of an art than a science. So the most important thing you can do in the interview is discuss tradeoffs. With every decision you make, you should explain why it's better than the alternatives.

If you're feeling overwhelmed, that's totally normal. System design is a broad field; it can feel like you're expected to know everything. However, the truth is there are a few core competencies you need to get good at and then you can build increasingly complex systems. As with any skill, you need to practice. As a thought exercise, try to figure out how you would design dev.to!

Discussion

pic
Editor guide
Collapse
knbrktl profile image
Kaan Bereketli

Thanks for the article. Loved how you kept it real. We'd like to read more from you.

Collapse
sophia_wyl profile image
Sophia Li

I’m learning front-end right now, and this makes me so excited to start learning back-end. Thanks for this awesome series! I hope there’s more :)

Collapse
kyleboss profile image
Kyle Boss

This is an amazing write-up! I've definitely noticed in upward-trend in this type of interview question yet not as many resources for it compared to the other types of interview questions (Big(O) notation, sorting, etc.)

"I've had some bad system design interviews" I am curious! What was the question and was there anything in particular that caught you off guard?

Collapse
techdebtor profile image
sam Author

Haha, okay, so this interview was with a major tech company in SF. The entire day ended up being one unfortunate situation after another (the interview was rescheduled the day of, I had no real lunch break, the interview was basically in a closet). The system design interview slot was an hour long. The interviewer was remote so I video chatted with her for quite a while about my previous experience. I don't think she was paying close attention to the time because finally after half an hour, she decided it was time to start the system design question. She wanted me to use some flow charting software I'd never used before to diagram my answer. Okay, sure, whatever, I'll figure it out.

So she asks me the system design question: Design Uber.
I ask, what features do you want me to focus on?
She says, all of them.
I clarify - you mean tracking drivers and riders, pairing them up, managing their accounts, processing payment...?
She says yes.
Uh, okay. I ask how many users we expect to have?
She says everybody.
I ask, everybody?
She says yes, everybody in the whole world will use this.

Well, here goes nothing. At the time, I hadn't quite figured out a good process for system design interviews, so I decided to start wherever I felt most comfortable. I've designed a lot of SQL tables at work, so I started with the database schema. I drew out the schema for the drivers and the riders while the interviewer watched me struggle with the diagramming software.

Then she asks, "Okay, how would you store credit cards?" I reply, "I've never worked on payments, so I don't know. I'd have to research it or ask someone with more experience in that domain for help." She replies, "Nope, you need to do something right now. How are you going to store them?" She offered no help whatsoever and I ended up drawing a database table that I knew was 100% wrong.

Then, she says, "Well, we only have five minutes left, and you haven't even gotten to the API yet. Write the API for pairing up rider and drivers." So I wrote something out. Then she says, "Now let's say some drivers keep cancelling rides. How would you punish those drivers?" Like, dude, what? Why is that the feature you pick to focus on?? Why didn't you just ask me to design the actual important features of Uber, like: matching drivers to riders, picking up a rider, navigating to a destination, and then dropping that rider off?

I didn't get that job, and the feedback I got was that I "didn't seem to understand databases." πŸ™„πŸ™„πŸ™„ I dodged a bullet tbh

Collapse
chair profile image
chair

Awesome stuff thank you!