Classic design · Mid
Online judge (LeetCode)
Classic interview design. Key points: sandbox, job scheduling, and rankings and leaderboards.
Short answer
Classic interview design. Key points: sandbox, job scheduling, and rankings and leaderboards. The classic exercise is designing a platform like LeetCode, which helps engineers prepare for coding interviews and hosts periodic coding contests. The user sees the list of problems, opens a problem and writes the solution in several languages, submits the code and gets immediate feedback, and follows a…
01 · CONTEXT
An online judge at modest scale
The classic exercise is designing a platform like LeetCode, which helps engineers prepare for coding interviews and hosts periodic coding contests. The user sees the list of problems, opens a problem and writes the solution in several languages, submits the code and gets immediate feedback, and follows a live leaderboard during the contests.
The non-functional requirements shape the design: prioritize availability over consistency, guarantee isolation and security when running user code, return the submission result within five seconds, and scale to contests with one hundred thousand users.
According to Hello Interview's analysis, the real platform has a few hundred thousand users and about four thousand problems. Compared with most design exercises, it is a small-scale system, and that should weigh on the choices.
02 · MODEL AND API
Entities, endpoints, and a simple architecture
Three entities are enough. The problem stores the statement, the test cases, and the expected output; the submission stores the submitted code and the result of running it against the test cases; and the leaderboard stores the contest rankings.
The API follows the requirements one by one: a paginated list of problems, reading a problem with the starter code in the requested language, submitting a solution, and a paginated read of a contest's leaderboard.
For a small system, the analysis argues for a simple client-server architecture, even monolithic, because the cost of managing several services is not worth it. To store the problems, it chooses a NoSQL database like DynamoDB, since there are no complex queries and the test cases can be nested as a subdocument of the problem.
03 · EXECUTION
Where to run untrusted code
Running the submission is the point where the case gets interesting. The naive option, running the code inside the API server, is described as an enormous security risk. In addition, the code runs in the same process as the server: if it hangs, it takes the server down with it.
| Option | What it offers | Main limit |
|---|---|---|
| Virtual machine | Isolated environment on top of the server, which can be restarted if something goes wrong | Consumes many resources and is slow to start |
| Container | Shares the host kernel and isolates the application's processes; it is lighter and starts faster | Isolates less than a virtual machine and requires careful configuration to avoid escape to the host |
| Serverless function | Small, stateless, and event-triggered; the provider scales with demand | Cold start adds latency on the first request, and resource limits affect heavy executions |
The analysis chooses containers, one for each supported language and reused across several submissions instead of creating a virtual machine per submission. It prefers them over a serverless function because it does not expect great variation in submission volume and wants to avoid cold-start latency.
The client sends the code and the problem identifier to the API server, which forwards them to the container of the chosen language.
The executor manages the language container, which runs the code in an isolated environment.
The executor triggers the container synchronously, waits for it to finish, and reads the output; the container itself makes no outbound calls.
The API server writes the submission result to the database and returns it to the client.
04 · SANDBOX
Hardening the container
Containers share the host kernel, so configuration determines security. The analysis lists additional measures, summarized below.
| Medida | Efeito |
|---|---|
| Read-only file system | Code is mounted read-only; output goes to a temporary directory that is deleted shortly afterward |
| CPU and memory limits | If the limits are exceeded, the container is terminated, preventing resource exhaustion |
| Explicit timeout | Kills any process that exceeds a predefined limit, which also helps meet the five-second response requirement |
| No network access | The container's network is disabled; on AWS, VPC security groups and NACLs restrict traffic except for essential connections |
| Restricted system calls | seccomp limits the system calls the container can make, so the host is not compromised |
05 · SCALE
Submission spikes: queue and containers
The analysis's math starts from a peak of ten thousand submissions, each running about a hundred test cases, with a conservative assumption of one hundred milliseconds per case. That gives one million test cases, or one hundred thousand seconds of execution, and about 1,667 cores to finish within a minute. The source itself notes that in practice most cases finish in 10 to 50 ms.
Scaling vertically does not solve it: the largest AWS instance types reach a few hundred vCPUs, and a large, expensive machine would sit idle most of the time.
The solution is to scaling horizontally the containers for each language, with auto scaling groups adjusting the number of instances to demand. The only considerable risk is overprovisioning, which the source treats as manageable, since the cloud makes it easy to scale capacity up and down.
The analysis also proposes a managed fila between the API server and the containers: the API enqueues the submission and the containers pull items as they become available. Execution can take several seconds because the code runs against hundreds of test cases, which fits the long-running task pattern, in which the API immediately returns a job identifier and background workers do the slow work.
The client sends the code to the API server, which puts the submission on the queue instead of running it right away.
The executors pull submissions from the queue as they become available. The queue helps manage load and allows retries if a container fails.
When the executor gets the result, it notifies the application server.
The server updates the database and the cache at the same time.
Since the queue made the system asynchronous, the client polls for the result at intervals, every second in the source's proposal; the endpoint fetches the submission from the database.
Some candidates propose a persistent connection, such as WebSockets, to avoid polling. The source says it would work, but adds complexity and is not needed with polling every second.
06 · RANKING
Live ranking without taking down the database
The source defines the contest as ninety minutes long with up to one hundred thousand users. Scoring is the number of problems solved, and in case of a tie, the time to complete all ten problems counts.
The naive version queries the contest's submissions, groups by user, and sorts by the number of distinct problems solved, and the client repeats the request every few seconds. The analysis itself warns that this puts significant load on the database.
| Abordagem | How it works | Main limit |
|---|---|---|
| Polling with a database query | On each poll the server queries the database, sorts the users, and returns the top | High database load and latency that grows with the number of users |
| Cache with periodic refresh | A cache such as Redis holds the ranking and is refreshed periodically from the database | The data is only as fresh as the cache refresh, and the client still has to poll |
| Redis sorted set | The database and the sorted set are updated on each processed submission, and the server returns the top from memory | Polling delay of about five seconds, acceptable for most users |
In Redis, the ranking lives in a sorted set with one key per contest: the value is the user identifier and the score is the total or the solve time. When a submission is processed, the set is updated with ZADD, and the top is read with ZRANGE in reverse order, with scores.
The client requests the contest ranking and repeats the request every five seconds.
The server reads the top directly from the in-memory sorted set, with no expensive database queries.
When a submission is processed, the database and the sorted set are updated.
The client receives the first pages of the top and fetches the following ones as it scrolls. The analysis prefers polling over WebSockets, which would be overkill for the modest number of users and the acceptable delay, and even suggests varying the interval, polling more often near the end of the contest.
07 · TEST CASES
One test suite for any language
Writing test cases per problem and per language would be a maintenance nightmare. The solution is to write a single set per problem, runnable in any language, with a standard serialization format and a test harness per language that deserializes the input, passes it to the user's code, and compares it with the expected output.
For a binary tree, for example, the analysis serializes the input into an array via level-order (BFS) traversal, and each language needs a harness able to rebuild it before calling the user's solution.
08 · WRAP-UP
Simplicity with a path to grow
The source describes a very simple system as the ideal, without over-engineering, but with a clear path to scale if needed. At the senior level, it expects you to discuss the pros and cons of container, virtual machine, and serverless function and justify the choice, and to move beyond drawing boxes and explain how to actually run the test cases.
Frequently asked questions
What is Online judge (LeetCode)?
Classic interview design. Key points: sandbox, job scheduling, and rankings and leaderboards.
What does the Online judge (LeetCode) design cover?
It is organized in these sections: An online judge at modest scale, Entities, endpoints, and a simple architecture, Where to run untrusted code, Hardening the container, Submission spikes: queue and containers, and Live ranking without taking down the database.
How long is Online judge (LeetCode) and what level is it?
It takes about 14 minutes to read and is rated Mid level.
Now design it yourself
Run this case as an interview in the System Design school: you make the decisions, the tutor challenges them and you see how your design scores.