System design questions are usually open-ended. As long as your approach is reasonable and you’re able to compare pros and cons of different options, your performance can’t be bad. Below are the systematic approach for answering system design questions.
Gather Requirement
Design questions are intentionally vague in order to test whether you’ll make assumptions or if you’ll ask clarifying questions. Ask clarifying questions like
- Who is going to use it?
- What are the use cases ?
- What does the system do?
- How many users are there? List the user roles (e.g., buyer, seller, poster, viewer, developer, manager).
- What are the inputs and outputs of the system?
User cases indicate the main functions of the system. Constraints list the scale of the system such as requests per second, requests types, data written per second. Gather requirements and scope the problem and discuss assumptions. Clarify the scalability requirements. Estimate the number of daily active users and then estimate the daily or hourly request rate. For example, if a search service has 1 billion daily users, each submitting 10 search requests, there are 10 billion daily requests or 420 million hourly requests.
Question like “Design a parking lot.” doesn’t say much about the problem. So you have to start defining the scope of the system. What part do I need to design? What kind of functionalities are expected to be? How big is the parking? What kind of cars are going? Will allow motorcycles? You should inquire who is going to use it and how they are going to use it.
As the developer, always take the time to understand why the client wants to do something to make sure you can give them what they really need. A common trap many developers fall into is having a dozen semi formed ideas about the cool features their app could have, versus nailing down what it really needs to do. List down functional requirements. Defining requirements, has nothing to do with object orientation. The requirements shouldn’t contain words like inheritance, or abstraction, or even class, or object. Those are details that we’ll get to later.
Non-functional requirements describe required characteristics of the application, rather than features. They describe the ilities (refers to a set of fundamental qualities that a system or platform should exemplify), like maintainability, reliability, usability, and availability.
You don’t need to be exhaustive and have answers for everything up front. On the first pass, only focus on capturing the absolute minimum set of requirements. Not the things are optional, or nice to have, or your dream features. Just the bare necessities, your minimum viable product. If the first pass at requirements isn’t perfect, that’s okay, you can update the requirements later if needed. The goal at this point is to get something written down and that could be as simple as bullet.
Finding Use cases
After hashing out the feature requirements that say what the system or application must do, it’s time to shift focus towards the user and how they accomplish a particular goal. One way to capture that is as a use case. At the very least, a use case needs three essential things
- A title that describes a goal
- The person who will interact with the application to achieve that goal, referred to as a primary actor
- The execution flow, or steps needed to accomplish the goal, the success scenario here.
Some people define broader and smaller use cases as a way of tying things together. A simple casual use case can have multiple scenarios. You should focus on the main successful scenario. But when necessary you can describe the alternate paths or extensions. Just focus on the typical situation that would occur, what you’d want to do with those situations.
Actors are all of the humans that could interact with and use the program. Not just humans, any external entity that acts on the system is an actor, including other computer systems. It’s common to put the primary actors on the left hand side, those are the ones that initiate any of the use cases. And the secondary actors on the right hand side, the actors that take more of a reactive role.
In the below use case diagram of a ticket booking system, the system is represented by boxes containing many different use cases. The primary actor is the customer and the secondary actor is the administrator. The customer initiates the use cases, such as booking, browsing and cancelling flights, while the administrator initiates the use cases, such as updating flight records, but is considered a secondary actor in the cancel flight use case, as she is only helping to complete the use cases initiated by the customer.
In summary, usecase diagrams to represent the connections between user and data and illustrate various system components and the data processing that occurs between them.
Phase 1:
- Draw a box to represent each type of user.
- Draw a box to represent each system that serves the functional requirements.
- Draw the connections between users and systems.
Phase 2:
- Break up request processing and storage.
- Create different designs based on the non-functional requirements, such as real-time versus eventual consistency.
- Consider shared services.
Phase 3:
- Break up the systems into components, which will usually be libraries or services.
- Draw the connections.
- Consider logging, monitoring, and alerting.
- Consider security.
Phase 4:
- Include a summary of our system design.
- Provide any new additional requirements.
- Analyze fault-tolerance. What can go wrong with each component? Network delays, inconsistency, no linearizability. What can we do to prevent and/or mitigate each situation and improve the fault-tolerance of this component and the overall system?
Define Components and Connections
Outline a high level design with all important components, consider core objects in the system. Sketch the main components and connections. For example, suppose we are asked to do the object-oriented design for a restaurant. Core objects might be things like Table, Guest, Party, Order, Meal, Employee, Server, and Host. Analyze the relationships between the objects.
Describe Big Picture
Explain your overall approach to help interviewer understand what you’re trying to do. If your design includes 3 major components, describe them first. System design questions are quite broad, there are infinite technical details out there. Jumping into details too early may distract both the interviewer and yourself.
Start With Core Component
Start solving the problem with core component of the system. Compare different options to solve the problem. It’s better to briefly list several possibilities and analyse the trade-off.
Scale The Design
Identify and address bottlenecks, given the constraints. For example, do you need the following to address scalability issues
- Load Balancer
- Horizontal scaling
- Caching
- Database Sharding