CodeDrill
Imagine a Computer Science department runs a practice site, CodeDrill, for its programming courses (intro, data structures, etc.). It is like LeetCode, with problems from those courses. An instructor adds a problem: a description, the header of a Java method to write, and a set of tests. A student opens the problem, writes the method in the browser, and submits it. CodeDrill runs the method against the tests and shows the student which tests passed. The tests are hidden. The student sees each test’s name and whether it passed, but not its input.
Nadia is studying for the data structures midterm. Nadia opens problem 14, “Balanced Brackets”. It asks for a method that says whether every bracket in a string is closed, and closed in the right order:
public static boolean isBalanced(String s)
Nadia writes the method and submits it. Nadia’s client sends:
POST /problems/14/submissions HTTP/1.1
Content-Type: application/json
{
"language": "java",
"code": "public static boolean isBalanced(String s) { ... }"
}
The server runs Nadia’s code against the problem’s 12 tests, saves the submission as submission 8812, and responds:
HTTP/1.1 201 Created
Location: /submissions/8812
Content-Type: application/json
{
"id": 8812,
"problem": 14,
"compiled": true,
"tests": [
{ "name": "empty string", "passed": true },
{ "name": "nested", "passed": true },
{ "name": "closed in the wrong order", "passed": false },
...
]
}
The submission is a resource, so Nadia can read it again later at /submissions/8812.
A monolith application
CodeDrill has a client, which runs in the student’s browser, and a server, which we call the application. The client reads a problem with GET /problems/14 and sends a solution with POST /problems/14/submissions. The application handles every request to the REST API, reads and writes the database, and runs the code. CodeDrill is a monolith: the application is deployed as one unit on one server. The database is on a second server.
graph TD
B[Client in Nadia's browser] -->|REST API| APP[Application server]
APP --> DB[(Database server)]
To run Nadia’s code, the application compiles Nadia’s method. Then, in a separate process on the same server, it calls the method on each test’s input and compares what the method returns with the test’s expected value. A correct solution finishes its tests in about a second. So the application stops the process if it runs longer than 5 seconds. That leaves room for a slow but correct solution, and a method with an infinite loop does not run forever.
Requirements
Two requirements matter in this chapter:
- Problem response time: the response to a request for a problem, such as
GET /problems/14, arrives within one second. - Submission response time: the response to a submission, with its results, arrives within 10 seconds.