Handmade Hero fatigue
Yesterday I decided I want to give up on Handmade Hero in a controlled manner. For the purposes of this piece, I wanted to look up, when did I start the series, and it turns out I started exactly a year ago today (2nd August 2025)! (It took me a few days to get around to editing the piece, hence it’s published later.) So, I am announcing I am taking a break and discussing why it’s the right move.
Watching Casey, in the 92nd episode, scale and rotate a quad yesterday was entertaining and actually it made me a bit sad deciding to stop watching, as he seemed really excited to scale and rotate a bitmap, but honestly, I stopped following the code. And I stopped, because I didn’t follow along and it just simply got too confusing. And I didn’t follow along, because at the time, I was awaiting a treatment for a condition I was living with for a long time and just wanted to at least watch some serious programming instead of doing nothing.
To be fair, people who were inspired by Handmade Hero often say they just watched a few dozen episodes and then started doing their own thing. And this is what I want to do. I’ve had the playlist tab open for a year now and it’s time to let go and continue working on the renderer. There is no substitute for real code written by yourself. No amount of Handmade Hero will make you a programmer, we agree on that, don’t we? So it’s time to thank Casey for making the show, get to the basement and lift code myself.
Now, before I leave it at that, I need to say, Handmade Hero is the best resource available if you want to learn to program. I remember coming across it and I did have a feeling this is good, but I thought for some reason that this is unnecessarily low level and that for my purposes, I’d be better off with something else. Well, there are two problems with that mindset. First, there’s NOTHING ELSE even remotely comparable to Handmade Hero. And you know I mean business when I start spewing all caps. Maybe Casey’s Computer, Enhance! program, but that’s paid (Handmade Hero is available for free and if you want the source code, it’s gonna set you back a measly $15) and if I understand it correctly, it expects you to apply it to your workflow—it doesn’t come with a substantive project. And to address the other point, C is actually the highest level language available. This is gonna need a separate paragraph, sigh.
Look, it’s fine to have a framework. Or you know, a library. But here’s the cold hard truth: computers run (predetermined) instructions. No amount of magic will help you program faster or better or whatever else is the fantasy, if you don’t understand the fundamentals. To illustrate the ridiculousness of modern programming discourse, consider any application that doesn’t run in a loop—or in other words, has a predetermined lifetime (e.g. a compiler or static site generator). On one hand, modern programmers still push this idea, that HW will compensate for bad programming (they don’t call it bad programming, but anyway), while at the same time refusing to use the modern HW to make programming simple. Specifically, I refer to the dreaded manual memory management. If I want to take source as input and get an executable as output, necessarily I have to pull all the source into memory, run arbitrary compute and after I have written the result to disk, all my memory is now garbage (and the OS can clean it up for me for free). So, you can allocate and never free, because … If you don’t get it, I’m not gonna waste my breath.
When I asked an LLM how much RAM I would need to compile the Linux kernel as a single translation unit, it said I should be fine with 32GB RAM, if no optimizations are turned on. That means it’s perfectly viable to do it in debug for the biggest project you can think of! I guess Linux would still have to do something else, as I anticipate you do want to turn on optimizations eventually, but that’s like the biggest project you can think of. For just about anything else, if you have problems, you need to engineer your pipeline better. Jon Blow’s Order of the Sinking Star (last time I checked ~300K loc) does this no problem. If a commercial grade video game can compile in <3 sec as a single translation unit (target is ~1/3 sec, as Jon wants to hit 1mil loc/sec), ordinary everyday programmers should not think of splitting the project into smaller chunks. I didn’t run the numbers, but maybe if you want to statically generate a major news outlet (e.g. the Guardian), then you might need to start worrying about managing memory, as ostensibly, there might be more content accumulated over the years that you simply can’t fit in memory in one go, but if you think about this for one second, you realize how stupidly simple the manual memory management would be in this case.
Since I’m in a full rant by now, I will address the other kind of application as well—applications that run in a loop (e.g. a web server or a video game). Well, video games famously refuse to give up the manual memory management. And generally, the prevailing view is that this kind of application requires performance and you can’t get performance without manual memory management. What I find strange is that nobody seems to think that all applications should run at the highest performance possible. Now, famously, Go is very successful in web server space and while it allows messing with pointers to some degree, it comes with a garbage collector. So, what do we gain from managed runtime in the web server space? Well, the server needs to listen, which would require something in memory which you would never free, as freeing it would mean the server no longer listens (and is therefore offline). No manual memory management necessary here. If you get a request, you need to run an arbitrary compute in response to the request. Aha! Jerry, you can’t predict how much memory I will need to process the request and I can get a theoretically infinite number of them, so here’s where GC will help us, right? No. Once you get a request, it basically starts its own universe (as it’s likely on a separate thread anyway) and guess what. When you’re done responding to the request, you can destroy all memory associated with the request, something so easy to do, that inventing a GC here makes no sense, especially since one line of code also means drastically better performance, as there’s no runtime, constantly checking whether there’s garbage in memory. I have a feeling I already had this quote here, but I like it so much, that I’ll have it again: “I removed garbage collector from my language, but I also removed the garbage generator, so it’s fine.” — Jon Blow
Okay, let’s not forget we are trying to explain why I think C is the highest level language available. Well, the problems with C often boil down to manual memory management. But hopefully, you saw above, that manual memory management is actually simple, if you have gigabytes of memory, and when you need performance (like in video games), you simply don’t have any other choice than doing all the work yourself (this is so universally accepted, that I didn’t cover video games). And this is exactly what you will find, when you tune to Handmade Hero. If Handmade Hero were written in Go, syntactic differences aside, all of the code would be the same. If you want to load a bitmap, you still have to read the header, allocate a buffer (man, I was surprised and confused when Go made me allocate memory for maps with make—isn’t that supposed to be handled for me?) and load the contents into it. And again, because we live in the future, Casey just allocated a 4GB chunk of memory and if you load a bitmap representing a hero, like you want to have the hero available for as long as the game is running. So we load it and never free. In the times of the past, maybe you’d want to keep in memory the current level, because you don’t have gigabytes of memory, but Handmade Hero can all fit in memory, so why not just put all the assets in memory? So you get the same convenience as in Go, but you’re faster. And remember, if you’re working on an ambitious project that outgrows memory available, you have to start doing it manually anyway!
In other words, watching Handmade Hero, it made me realize that the “high level language productivity” is a lie. And it is a lie, because all the steps needed to achieve your goal are the same, whether you program in C, Go, Java or OCaml. And the reason I would pick Go over C for a web server is not that I don’t have to manage memory manually (which you have to do anyway, make is literally malloc), but because it has a suitable, mature standard library well-fitted for the task. Do you know why Python is so popular? Believe it or not, it’s because it has a vast and convenient standard library. You do know that most of the real code in Python is actually C, right? You just call it from an environment where you don’t need so many curly braces.
Anyway, let me thank Casey again, as this was well worth my time and it put me on a correct course. Thank you Casey. And I was sorry to hear you hated the series before you met people whom you inspired at the first Better Software Conference in 2025. Without Handmade Hero, who knows how long it would take me to discover the truth. But I had an opportunity to see the truth with my own eyes on the show and I am grateful. As I said, it is now time for me to get my hands dirty, before I can continue watching the show meaningfully again. I only wish I saw those 92 episodes earlier, so I could have moved on sooner.