Common System Design Interview Mistakes: Newsletter Subscription Question
Through this article, I will walk through a system design question I often ask senior software engineers, highlighting the common mistakes they make, which might lead to failing the interview.
We’re building a single-page web app where users can subscribe to a mailing list by entering their email. After subscribing, they’ll receive a weekly newsletter.
Mistake #1: Jumping into solutions
The first mistake some candidates make is jumping into a solution without clarifying both functional and non-functional requirements. For a senior software engineer, this is usually a red flag; senior engineers are expected to clarify the problem statement and customer needs, then translate them into requirements. The interviewer would expect the candidate to ask questions such as, but not limited to:
- How many users do we expect to use the application?
- What is the accepted latency?
- Can a user unsubscribe from the mailing list?
- If a user is already subscribed, should the application show them an error message?
- Do we need to support personalized newsletters, or is everyone receiving the same email?
- Will we need a reporting mechanism, such as what articles did a particular user receive? For a specific article, to how many users was it sent?
- Do we have an email service already built?
Interviewer: We are expecting 400K users/hour during working hours, it should be around 1k users/hour afterward. If a user is already subscribed, it would be nice, but not required, to show them a message saying “you are already subscribed”. Once a user hits the subscribe button, they should receive a response within 300ms. For now, let’s just focus on the subscription functionality, taking into consideration that the system will be extended later to send newsletters and pull different reports.
Mistake #2: Not conducting a proper analysis
After clarifying the problem statement, some candidates might come up with a system design they believe will work based on their experience, and it might. However, they often fail to explain the reasoning behind their choices. A candidate should calculate how many resources such a system would require, rather than suggesting a fixed number. A good answer might be: since we expect 400k subscriptions/hour, translating to 111TPS, and the accepted latency of 300ms, I’ll benchmark how many subscription requests a server can handle to complete without exceeding the 300ms latency. Let’s assume the benchmark results in 80TPS with a latency below 300ms, which means we will need two servers during peak hours, and one server only afterward. But wait…
Mistake #3: Thinking short-term and not considering cost and scalability
What if the traffic increases to 600K/hour? Will adding more servers handle it? How will the system scale up or down based on the traffic? Do you anticipate any scaling issues, such as the database, or unnecessary cost?
Building a scalable and cost-efficient system requires an understanding of the technology to use. Based on the requirements, the number of servers needed is dynamic, so having two servers running all the time is wasteful. An auto-scaling group not only enables scalability, it also improves reliability, if a machine goes down for any reason, a new one should be automatically spun up. Moving to a horizontally scalable DB should remove bottlenecks and ensure scalability. However, a NoSQL DB might not be the best fit for the functional requirements, especially for reporting, and a sharded RDBMS will add operational burden. A hybrid approach could be one solution, where a NoSQL DB could be used to validate, add a new user and return the result. It would be a good option based on its performance and horizontal scalability. While adding a user to a RDBMS could happen asynchronously, which will be used later for reporting and building relations.
Mistake #4: Failing to provide alternatives and highlighting trade-offs
Remember the requirement … If a user is already subscribed, it would be nice, but not necessary, to show them a message saying … If we can remove this requirement, we could simplify the system design by making it asynchronous. The trade-off is that the user will not know that they are already subscribed. But do they really need to know? If we just remove this requirement, we can achieve horizontal scalability through AWS Lambda, scale up to 10K TPS limited by API gateway, which translates to 36 million per hour, and simplify the design by removing the NoSQL DB. Coming up with alternatives and trade-offs requires an understanding of and negotiation around the business requirements with the interviewer. Failing to present alternatives may suggest that the candidate is reluctant to explore technologies outside their current expertise. Senior engineers are expected to embrace continuous learning and show willingness to explore new solutions.
Mistake #5: Forgetting operational excellence
Building a working system design is not enough; it also has to be easy to maintain and show practicality. A design with many components might be difficult to maintain and monitor, even if it offers high performance, scalability and low cost, always try to simplify your design whenever possible. Both adding a dead letter queue and enabling RDS Multi-AZ deployment, which will trigger automatic fail over to a standby RDS instance without manual intervention, would make the system more resilient. Sending logs to CloudWatch or any other monitoring service and building alerts on top of specific metrics enhances monitoring. It's important to be concrete in the metrics you want to define, which demonstrate your experience working on production systems. For example, if subscriptions SQS has < X visible messages or API gateway returned 4xx or 5xx Y times during 10 minutes, maybe something went wrong and someone needs to look into it.
Building robust systems requires a deep understanding of both the technology and problem statement, while considering factors like performance, scalability, reliability, extensibility, security and operations. Senior software engineers play a key role in setting the technical direction forward for their teams. They should be able to identify multiple design options, clearly articulate trade-offs, and evaluate the consequences of their decisions.