A junior backend developer posted to Hacker News this week with a question that resonates across the web development community. After spending years learning to build applications, they realized that modern frameworks and abstractions have made "making apps" straightforward. What inspires them now is the lower level: multiplexers, terminal emulators, event loop libraries, compilers, programming languages. They want to build those things but have no idea where to start.

The abstraction ceiling

The web development stack is designed to hide complexity. Frameworks handle routing, ORMs handle database queries, and cloud platforms handle deployment. A junior developer can build a functioning application without ever thinking about memory allocation, system calls, or how their event loop actually works. That is the point of the abstraction. It is also, for developers who find the lower layers interesting, a ceiling.

The poster's realization is common. Once you can build the thing you set out to build, the question shifts from "how do I make this work" to "how does this actually work underneath." Web development does not teach you how a compiler parses source code, how a terminal renders text, or how an event loop multiplexes file descriptors. Those topics live in systems programming, and the skills that make you productive in web development do not automatically transfer.

Why books and tutorials are not enough

The poster explicitly rules out books, tutorials, and continued web dev work as paths to systems programming knowledge. That instinct is correct, though for reasons worth explaining. Systems programming is a practice-heavy discipline. Reading about how an event loop works is not the same as implementing one that handles thousands of concurrent connections without dropping data. Reading about compiler theory does not teach you how to handle operator precedence, error recovery, or code generation for a real instruction set.

The gap between understanding a concept and being able to build something with it is wider in systems programming than in web development. In web development, you can follow a tutorial and have a working API endpoint in an hour. In systems programming, you might spend a week just understanding the problem domain before writing a single line of code that does what you intended.

What actually works

People who have made the transition from web development to systems programming tend to follow a few patterns. The most common is building something small and concrete that requires systems-level knowledge. Not a tutorial project. Not a textbook exercise. A real tool that solves a real problem, even if that problem is tiny.

Writing a terminal emulator teaches you about character encoding, escape sequences, process management, and signal handling. Building a simple event loop teaches you about file descriptors, non-blocking I/O, and epoll or kqueue. Writing a basic compiler teaches you about parsing, abstract syntax trees, type checking, and code generation. Each of these projects forces you to confront the operating system directly rather than through a framework's abstraction layer.

The second pattern is reading source code of tools you already use. Open the source for a terminal emulator like Alacritty or Kitty. Read how an event loop library like libuv or asyncio under the hood actually works. Look at how a small compiler or interpreter handles parsing. The code is the documentation, and real implementations contain decisions and tradeoffs that no tutorial covers.

The third pattern is learning a systems language seriously. For most people moving from web development, that means Rust or C. Rust gives you memory safety without a garbage collector and forces you to think about ownership and lifetimes. C gives you direct access to system calls and memory layout with nothing in between. Both languages require you to understand what the computer is actually doing, which is the point.

The transition is slower than web development

Web development rewards fast iteration. You change a line of code, refresh the browser, and see the result. Systems programming does not work that way. A compiler bug might manifest as a segfault with no useful error message. A concurrency issue might appear once in a thousand runs. A memory corruption bug might take hours to surface. The feedback loop is longer and the debugging tools are different.

Developers who successfully transition tend to accept this pace shift. They build smaller projects with narrower scope. They learn to use debuggers, profilers, and tracing tools instead of relying on print statements. They read error messages carefully instead of pasting them into search engines. These habits are not optional in systems programming. They are the job.

The barrier is not as high as it looks

The poster says they have "no clue how to build any of that stuff." That is the normal starting point, not a permanent condition. The concepts underlying multiplexers, event loops, compilers, and terminals are not secret. They are well-documented and have been implemented thousands of times. The difficulty is not in the ideas. It is in the practice of applying them, which only comes from building things and breaking them.

The most useful advice for anyone in this position is to pick one project, accept that it will take longer than expected, and build it anyway. A terminal emulator. A simple compiler for a toy language. An event loop that serves HTTP requests. The project does not need to be original or ambitious. It needs to require you to think at the systems level instead of reaching for another abstraction.