A project-based road from first principles to a deployed, production-shaped service. Every stage ends with something running that you built — no tutorials to copy, only briefs to fulfill. Walk it in order: each project leans on the muscles the previous one built.
Obey the form exactly. Repetition builds the instincts that improvisation later relies on. In this stage you build small things completely, by hand, without frameworks doing the thinking for you.
Before writing a server, be able to narrate one. Write down — on paper or in a doc — every step between typing a URL and seeing a page: DNS, TCP, TLS, the HTTP request line, headers, the response, rendering. Then explain where a backend lives in that chain and what it can and cannot see. When you can tell the story without looking anything up, this step is done.
Session stores, caches, header lookups, database indexes — the backend runs on O(1) lookups. Prove the instinct on the classic pairing problem.
Solve it →Persistence without a database — the foundation every database is built on.
Frameworks hide the protocol. Build one server without them so nothing about HTTP is ever mysterious again.
Adapt what you practiced to problems that no longer fit the template. Real frameworks and real databases enter here — but you now know what they are doing underneath.
A database index is a search tree kept sorted so lookups stay logarithmic. Watch insertion keep order, then watch AVL rotations buy the balance that makes query times predictable.
Open visualization →Migrations, build steps, service startup order — all the same problem: can these dependencies be satisfied, and in what order? Solve it once as a cycle-detection problem and you'll recognize it forever.
Solve it →The bread-and-butter service, done properly end to end.
Two requests, one shared row, no locking — this bug is invisible until real traffic arrives. Reproduce it on purpose, then fix it properly.
The feature every service needs and most tutorials teach badly.
Job schedulers, retry backoff, load balancers — anything that answers "what's next?" efficiently is a heap. Watch sift-down maintain the invariant that makes extract-max O(log n).
Open visualization →The moment a request does slow work inline, you need this. Every real backend grows one.
Design from first principles — the form is now yours. In this stage nobody hands you the shape of the solution; the brief describes a problem and a bar to clear.
Every read hitting the database doesn't scale. Put a cache in front of the hottest read path — and handle the part everyone gets wrong: invalidation.
Sliding windows, overlapping request bursts, merged quota periods — rate limiting is interval arithmetic. Sharpen it on the canonical merge problem before building the real thing.
Solve it →Middleware that protects everything behind it — and a claim you have to back with numbers.
You can't SSH in and attach a debugger to a service that's already crash-looping at 3am. Logs and metrics are the only view you get — make them good enough to actually use.
Small enough to finish, deep enough to be real. This is the step that turns the path into a portfolio piece.