Skip to content
← Posts

July 23, 2026/1010 words/5 min read

Learning the Layer Underneath the Code

Finishing OSTEP.

I've been using computers for most of my life, writing code for a decent chunk of it, but until fairly recently I could not give you a satisfying explanation of what an operating system actually does.

I knew the vocabulary, of course, but mostly as labels for things happening below my code. Threads explained the worst bugs, and the file system took the blame when permissions stopped making sense. That was enough to get me through years of building websites and running a homelab. I spent far too much time in a terminal and even stumbled through some Rust without needing much more. You can get surprisingly far several floors above the machinery. I only had to take the lift down when something was on fire.

The problem was that I kept wanting to go one floor lower.

That was how I ended up with Operating Systems: Three Easy Pieces open in yet another tab. OSTEP is a free operating systems book by Remzi and Andrea Arpaci-Dusseau, organized around virtualization, concurrency and persistence. The book makes you use those ideas in homework and little simulators before dropping you into proper projects. Calling those three pieces "easy" is obviously academic humour, but I respect the confidence!

This is the sort of thing I usually just get wrong. I download the material and make an ambitious plan, then after reading eighty pages in one evening, I demote the whole project to a bookmark. We can turn curiosity into curriculum with frightening speed, and curriculum is much easier to abandon. This time I treated it as a course and did the work.

Reading something gives me the very convincing feeling that I understand something, especially while the explanation is still sitting in front of me. Then I close the chapter and the whole mental structure I build collapses like a cheap tent. OSTEP made that pitfall much harder. Before showing me an answer, it would ask me to predict what a scheduler would do or trace an address translation. The simulators could print the answer too, but I had to resist reaching for that flag. It was less comfortable than highlighting a paragraph, which is probably why it worked.

The homework repository is full of small programs that model one narrow piece of an operating system at a time. Changing the random seed gave me a new result to work through on paper before I asked the simulator to check it. That loop is really damn unforgiving! There was no room for the thing I usually go for, the "yeah, yeah, I get the idea" routine I do when a technical explanation feels plausible. The simulator caught me whenever I guessed which process ran next or mapped a page to the wrong address.

The projects begin with small C and Unix exercises, but before long you are building programs like shells and web servers, then you're working inside the operating system itself. I eventually made it into xv6, the small teaching operating system, without my brain feeling like it's running out of disk space. The projects took far longer than the reading, but I remember the things I broke and fixed much better than the pages I read.

My routine around the whole thing was deliberately simplistic, I'd just read a chapter, then write down its central question in my own words before touching the homework. If there was a project for it, I'd build that too. Uncharacteristic to me, I also refused to make a schedule heroic enough to become a future source of guilt. A week might produce three chapters and a program, or I had time for only one page table that I finally understood. Both counted though! And eventually they added up.

I also decided AI could explain an error, but it could not do the exercise for me. That boundary was slightly artificial, and I argued with myself about it every time some C program spent an evening segfaulting. I already have tools that can produce working code much faster than I can, but I wanted the model in my head more than I wanted passing tests.

The course replaced a lot of the OS magic with policy. The operating system shares the processor and decides which program runs next, so a computer appears to do a dozen things at once. Then with help from hardware, it gives each program the illusion of a clean, private stretch of memory. Persistence was much harder to picture. A stable file sits on blocks and metadata, with caches and recovery machinery between it and all the ways a machine can stop at the wrong moment.

Every programmer I know with a computer science degree worked this material years ago, to various degrees of completion. For years, virtual memory meant that programs somehow got their own memory and I did not have to think too hard about it. Following an address through a page table made the trick much less magical, it also showed me how much machinery I had been relying on without understanding it.

Finishing the course also changed the wayfailures look. "Busy" no longer feels like an acceptable explanation when a machine slows down, and "two things happened at a bad time" no longer covers a race condition. When a database says data reached disk, I understand some of what has to survive caches, reordering and power loss for that promise to hold. The containers I use constantly at home are less mysterious, now that I can trace how the operating system isolates a process and manages its resources.

I finished as the same product nerd who likes building small things, and there is still no practical scenario in which someone should let me redesign a scheduler. Errors from that layer just now connect to something sturdier than a search result I once skimmed or an answer from Claude. I have to say, I am also much less easily impressed by magic.

Over those months, I lost several evenings to C and took the "three easy pieces" joke personally.