Background
Design questions are an integral part of today's IT interview process. Design questions can generally be categorized into
- High-level design (HLD) - High-level architecture design of a system
- Low-level design (LLD) - Low-level class / Component design of the system
In High-level design, you would typically get a question to design a system like YouTube, Google Maps, or an e-commerce website, and you would provide the high-level architecture of the system, starting from the client all the way to backend systems that would process and return the request. Focus would be to solve functional use cases, but also address non-functional ones like scalability, availability, performance, etc.
In Low-level design, however, you will focus more on writing classes or components to solve the problem statement. For eg, let's say you are designing a Chess game, then you need to design a class for various components like the Board, Player, etc., along with methods/variables that will be used to implement interactions effectively. Focus would be on implementing the solution, but also sticking to design principles like SOLID.
In this post, we will look at what are some common things you look at in terms of approaching a high-level design question. We will look at a specific design question and see how we approach it based on various aspects we discuss here.
How to approach System design interview questions
1. Summarize the requirements of the System and clarify open questions
The 1st thing you should think about once you know the problem statement is to summarize the requirements of the System (functional and non-functional) and clarify open questions. Once the requirements are summarized, you can check with the interviewer if the list looks ok, if there is anything specific the interviewer wants to discuss, we add it to our list of requirements. This is very important to build the foundation of how you approach the question. This will help you with the following
- Understand all aspects of the problem that you are trying to solve
- You can refer to these when you are actually building your system to ensure you have addressed all the requirements you noted earlier.
- This shows you can systematically address the question and not jump to solutions.
Make sure when you are summarizing functional and non-functional requirements, also mention why you think a requirement is important.
Let's see some examples
- Let's say you are designing a YouTube video upload and viewing service.
- Functional requirements can be
- The user should be able to upload the video
- The user should be able to specify video metadata like title, description, thumbnail, etc.
- The user should be able to view the video
- The user should be able to generate the caption, etc.
- Non-functional requirements can be
- The system should be available & fault-tolerant (no downtime)
- The system should be able to scale with load
- The system should be performant (Less video processing time, less rendering time, etc.)
- The system should be durable (Video once uploaded should be persisted)
With summarization, make sure you ask open questions, e.g.,
- Do we want to support video streaming?
- What is the expected system load like? Designing a system for a global user base will require a highly scalable system.
- Do we want to consider front-end system design (UX experience) or just the backend design, etc?
2. Take time to think about your high-level approach and design
Once you clarify the requirements, you should take some time to think through what your approach should be to implement a design that solves the problem at hand (Do not jump to giving random suggestions - that's a red flag).
A few things you can think of
- What components will be involved in the design (API gateway, web services, persistent storage options, event-driven communication, etc), and how will they interact with each other?
- Go through your non-functional requirements and see what is needed to handle those. E.g., for scalability, you might need auto-scaling infrastructure, for availability, you might need a cluster of DB nodes, for performance, you might need in-memory caches, etc.
- You can also think about aspects like what APIs are needed, what API structure will look like, what are expected input and output of APIs are. If you have to store information, think about what the DB schema will look like.
- Think about what DB you need - Relational or non-relational, etc.
Standard components that you might need
- API Gateway: API gateway is probably the most common component in any architecture. API gateway is used for rate limiting, authentication, response caching, and data transformations.
- Microservices node cluster: Modern systems use microservices rather than a monolithic architecture. You would typically want autoscaling enabled so that you can scale the microservice nodes on demand. Instead of actual server nodes, you could have a serverless architecture like AWS Lambda.
- Storage: You need storage options. It could be a database(Relational or non-relational), storage service like S3, etc.
- Event-driven system: If you need an asynchronous workflow, then you need to decouple your microservice nodes from the component that will process your request, eg, image processing or video processing, which are expensive operations. For this, you can have a message queue system like Active MQ, AWS SQS, or Kafka.
- Caching system: To improve performance, you might want to have some in-memory caching system like Redis, memcache, etc.
- Cron jobs/ batch infra: For use-cases where you need a periodic job to run, you can use a cron-based scheduler or batch job infrastructure.
- Monitoring/Analytics systems: Depending on use cases, you might also need a monitoring setup like monitoring system health, system load, security alerts in cases like a DOS attack, etc. There could be an analytics requirement like monitoring logs, user access patterns, etc. Eg., AWS CloudWatch.
- CDN: Content delivery network or CDN is a set of servers at edge locations (near user locations) that are responsible for serving static content like CSS, images, etc., to reduce the latency.
Concepts that you need to consider for the design
- Authentication: As we saw above API gateway will handle authentication. You can have various authentication mechanisms like OAuth 2.0, JWT, etc.
- Relational vs No-SQL DB: You need to decide based on system requirements whether you need a relational DB like SQL Server or a non-sql DB like MongoDB or maybe something else. You can follow below general guidelines below to decide
- If you want to scale, like if you are dealing with big data, you would generally want to go to NoSQL, as relational DB might be difficult to scale. You can argue that you can have sharding to scale the DB, and while that is a valid point, it becomes difficult to scale relational DB after a threshold.
- If you do not have a fixed schema, then again, NoSQL is the way to go.
- If you need low latency, then again, NoSQL is the way to go.
- If you need ACID properties, then you should use a relational DB. For eg, if you are designing a payment system, you should use a relational DB because you need strong consistency. If you are ok with eventual consistency, you can go with NOSQL.
- If your access queries and patterns are not fixed, then NoSQL is probably a good choice; else if it is fixed relational DB might work out.
- CAP theorem: The CAP theorem, also known as Brewer's theorem, states that a distributed system can only guarantee two out of three properties: Consistency, Availability, and Partition Tolerance. This means that designers must make trade-offs when building distributed systems, prioritizing the most important guarantees for their specific needs.
- ACID properties: ACID is an acronym that stands for atomicity, consistency, isolation, and durability (ACID). Together, ACID properties ensure that a set of database operations (grouped together in a transaction) leave the database in a valid state even in the event of unexpected errors. Further, ACID transactions provide the level of transactional guarantees that many regulatory agencies require.
- DB concepts: If you do get into DB architecture discussions, you might need the following concepts handy
- Sharding
- Paritioning
- Indexes
- Batch writes
- Read replicas
- API design: You might have to design the APIs as well, for which you need to consider:
- API type (Socket communication / REST API's)
- Versioning
- Pagination
- API protocol (HTTP / HTTPS)
- API timeout
- Rate limiting, etc.
- UX concepts
- Server-side rendering vs client-side rendering: (If SEO, Search engine optimization, is a use case, then we need server-side rendering as 1st render should have all data, which is not the case with client-side rendering)
- Debouncing: Call the API or a function after a deal, so that if a user mistakenly clicks the submit button 3/4 times call is made only once.
3. Implement your design
Once you have thought about your design, you can start implementing it. You can do this over a whiteboard or a Word doc (whatever is available). You should consider following at this stage
- While suggesting a component, also give a reason why you think the component is suggested, and what use case it solves. Be as vocal as you can and constantly communicate your thought proceess.
- You can expect probing questions that will be asked to make sure you understand the depth of the solution you are suggesting. So, do not suggest anything that you might have heard but are not sure how it actually works, and help solve the user case at hand. You should be confident enough to back up your answers.
- Take pauses after periodic discussion to check if the interviewer has any questions about what has been suggested/discussed so far.
- Be prepared for course corrections. It can happen that the interviewer asks what you will do if the requirement changes, you should be able to course correct your approach to align with the new temporary goal set. This is again to understand that you can do necessary course corrections when needed.
4. Summarize your solution
Once implementation is done, go through your initial notes on functional and non-functional requirements and summarize how your system design handles them.
NOTES:
- Design discussion is all about open discussion, unlike problem solving, where you have a specific solution/ direction for the problem.
- There can be more than one solution to the problem, so just be honest, confident, and vocal about your answers. Justify and back up your answers.
- Never take assumptions or jump to solutions. Clarify all the questions upfront. If you are suggesting something based on some assumption, mention it upfront as well.
- Do not propose or suggest anything that you are not aware of or cannot justify. If you suggest something but cannot justify it, it will be considered a red flag. It's ok to say if you are not aware of something specific, like how DB indexes work or how sharding works.
Related Links
- ACID Properties in Databases With Examples (YouTube)
- sql vs nosql - how to choose for web dev (YouTube)
- Understanding the CAP Theorem: Balancing Consistency, Availability, and Partition (Medium)
- Strong Consistency vs Eventual Consistency(Medium)
- Amazon Lockers—High Level System Design (HLD)
- SOLID design principles
- SOLID principles in Object Oriented Programming (OSFG)