Low Level Design (LLD) or Object Oriented Design (OOD) interview tests your ability to translate high-level requirements into detailed class structures, methods and their interactions using object-oriented design principles.
This article will guide you through a step-by-step approach to answer LLD interview questions effectively using an example problem: Design Stack Overflow.
Step 1: Clarify Requirements
The first step in a LLD interview is to understand the requirements and use-cases.
Start by asking questions to understand what's required:
What are the core features we need to support?
Are there any specific features we should prioritize?
Who are the primary users of this system?
What actions can users take?
Are there any specific constraints or limitations?
Do we need to handle concurrency?
Do we need to handle errors, edge cases, exceptions, and unexpected input?
For our Stack Overflow design, we might ask:
Do we need comments on questions and answers?
Should we implement tagging for questions?
Should we design the voting system for questions and answers?
Should we include a search functionality for questions and answers?
Should we limit the length of questions?
Let’s assume the interviewer wants us to focus on:
Users can post questions, answer questions, and comment on questions and answers.
Users can vote on questions and answers.
Questions should have tags associated with them.
Users can search for questions based on keywords, tags, or user profiles.
The system should assign reputation score to users based on their activity and the quality of their contributions.
📣 Become a Better Software Engineer - CodeCrafters.io
CodeCrafters is a YC backed platform that offers a unique, hands-on approach to practice complex programming challenges like building your own Redis, Git, SQLite, Bittorrent client and more from scratch.
Step 2: Identify Entities
After you are clear with the requirements, break down the problem and identify the core entities or objects you need to have in the design.
Core entities are the key objects or concepts around which your system is built.
These entities will become the classes in your object-oriented design. Think of them as the nouns in the problem description.
For Stack Overflow, different entities we can have are:
Step 3: Class Design
After identifying the core entities, the next step is to design the classes, enums and interfaces that will represent the entities in your system.
3.1 Define classes and relationships
Translate entities into classes and come up with a list of attributes you want to have in those classes.
If your design consists of multiple classes, figure out how would they would relate with each other.
In our Stack Overflow example, here are some of the relationships between classes:
A
User
can ask manyQuestions
, provide manyAnswers
and add manyComments
.A
Question
can have manyAnswers,
Comments, Tags
andVotes
.An
Answer
can have manyComments
andVotes
.A
Comment
is composed within aQuestion
or anAnswer
.A
Tag
is composed within aQuestion
.
You can draw a UML class diagram to illustrate the relationships between classes or code the class structure directly in an object oriented programming language of your choice.
Note: Drawing UML diagrams in a LLD interview is not mandatory but it’s good to check with the interviewer.
If you want to learn about UML class diagrams, check out this article:
Here’s how we might define classes, their list of attributes and relationships:
3.2 Define interfaces and core methods
After you've outlined the classes, their attributes and the relationship between classes, the next step is to define interfaces and core methods in each of the classes.
These methods encapsulate the actions or behaviors that each class is responsible for. Essentially, they are the verbs associated with your entities.
Since both Question
and Answer
classes need to support comments and votes, we can define interfaces for these features.
Here are the interfaces we can have in our design:
Commentable: Defines the contract for objects that can receive comments (eg. Question, Answer).
addComment(comment): Adds a comment to this object.
getComments(): Retrieves all comments for this object.
Votable: Defines the contract for objects that can be voted on.
vote(): Registers a vote on this object.
getVoteCount(): Retrieves the total vote count for this object.
Each class need to have methods for the tasks it can perform.
Here are the core method for Stack Overflow classes:
User
Class:askQuestion(title, content, tags): Creates a new question asked by this user.
answerQuestion(question, content): Creates a new answer by this user for the given question.
addComment(commentable, comment): Adds a comment by this user to a question or answer.
updateReputation(value): Updates the user's reputation score.
Question
Class:addAnswer(answer): Adds an answer to this question.
addComment(comment): Adds a comment to this question.
vote(user, value): Registers a vote on this question.
addTag(user, value): Adds a tag to this question.
Answer
Class:addComment(comment): Adds a comment to this answer.
vote(user, value): Registers a vote on this answer.
markAsAccepted(): Marks this answer as accepted.
I have left the setter/getter methods to keep it short.
3.3 Define a central class
We don’t want to manipulate classes in our design directly from outside, that’s why we need a central class that provides a unified interface for interacting with the system.
This simplifies the API and makes it easier to use and understand the system as a whole.
For our Stack Overflow design, we can create a class called StackOverflow that will serve as the central coordinator for the entire system. It manages the creation, retrieval, and interaction of all major components.
Here are some of it’s key responsibilities:
We can have following core methods in the StackOverflow class:
createUser(username, email): Creates and registers a new user in the system.
askQuestion(user, title, content, tags): Allows a user to ask a new question.
answerQuestion(user, question, content): Allows a user to answer an existing question.
addComment(user, commentable, content): Allows a user to add a comment on an existing question/answer.
voteQuestion(user, question, value): Registers a vote on a question.
voteAnswer(user, answer, value): Registers a vote on an answer.
acceptAnswer(answer): Mark an answer as accepted
searchQuestions(query): Searches for questions based on a query string.
getQuestionsByUser(user): Searches questions added by a user.
StackOverflow class implementation: Java, Python
Step 4: Implementation
Once you have defined the class structure, it’s time to start implementing the full solution.
4.1 Follow good coding practices
While writing the code for a LLD interview problem, you should try your best to follow good coding principles like:
Use meaningful names for classes, methods, and variables.
Focus on simplicity and readability.
Favor composition over inheritance to promote flexibility and avoid tight coupling.
Avoid duplicating code or logic.
Use interfaces to define contracts and enable loose coupling between components.
Only implement what is required.
Strive for modularity and separation of concerns to make the codebase maintainable and scalable.
Apply design principles and design patterns wherever necessary.
Make your code scalable so that it performs well with large data sets.
4.2 Implement necessary methods
You may not have enough time to implement all the methods. Check with the interviewer to understand which methods are important for the interview.
If the expectation is to demo and test the code, you can create a separate demo class like StackOverflowDemo
You can find the implementation of Design Stack Overflow in Java and Python here.
4.3 Address concurrency
In a system that serves multiple users simultaneously, we may need to handle race conditions and other concurrency related issues.
Check with the interviewer if you need to handle concurrency in the design.
Here are few strategies to address concurrency:
Use synchronization mechanisms to ensure that only one thread can access a shared resource at a time.
Use atomic operations that are guaranteed to be executed as a single, indivisible unit.
Use immutable objects where possible to eliminate the risk of concurrent modifications.
Use thread-safe data structures that handle synchronization internally.
For Stack Overflow example, here are few concurrency considerations:
Voting System: Implement atomic operations for vote counts to prevent race conditions.
Comment System: Use a thread-safe data structure for storing and retrieving comments.
User Reputation: Use synchronization when updating user reputation to ensure consistency.
Step 5: Exception Handling
The problem may require you to handle errors, edge cases, exceptions, and unexpected input.
For the Stack Overflow example, here are some of the scenarios which you may want to handle in your design:
What if a user tries to vote on their own question/answer?
What is a user tries to vote multiple times on the same content?
What if a user posts a question with empty title or content?
Can the user reputation go negative?
Final Note
These steps should guide you to remain on track and cover the different aspects when answering a LLD interview problem.
But you may skip some of these due to limited time in interviews.
It’s always a good idea to check with the interviewer on what all is expected from the design.
You can find the implementations for Stack Overflow and other popular LLD interview problems in this GitHub repository.
Thank you so much for reading.
If you found it valuable, hit a like ❤️ and consider subscribing for more such content every week.
If you have any questions or suggestions, leave a comment.
Checkout my Youtube channel for more in-depth content.
Follow me on LinkedIn and X to stay updated.
Checkout my GitHub repositories for free interview preparation resources.
I hope you have a lovely day!
See you soon,
Ashish
Thanks for sharing the valuable content bro 🙌🏻🙌🏻
I have gone through Code of StackOverFlow. I just wanted to add a suggestion for your StackOverflow class.
Instead of writing all methods below inside StackOverflow class, Create a Multiple Class such as UserService, QuestionService, VotingService , etc.
By moving these methods to respective class , it will be more modular, extensible.
UserService
createUser(username, email): Creates and registers a new user in the system.
getQuestionsByUser(user): Searches questions added by a user.
QuestionService
askQuestion(user, title, content, tags): Allows a user to ask a new question.
answerQuestion(user, question, content): Allows a user to answer an existing question.
addComment(user, commentable, content): Allows a user to add a comment on an existing question/answer.
acceptAnswer(answer): Mark an answer as accepted
Voting Service
voteQuestion(user, question, value): Registers a vote on a question.
voteAnswer(user, answer, value): Registers a vote on an answer.
SearchService
searchQuestions(query): Searches for questions based on a query string.
@Ashish , Let me know if i am thinking in right directions ??