J
Jonathan Blow
number-none.com · Personal blog · on HN since 2008
Jonathan Blow, the game developer behind Braid, hosts programming notes on game code, graphics and math, plus a John Carmack essay on inlined code.
What HN saysHN mainly links it for Carmack's inlined code essay, cited in debates favoring long linear functions over many small ones.
119HN people shared it
91linked it in comments
41stories submitted
2.1Kstory points
3 months agolast shared
2008people per year2026
Most-shared posts
- 1John Carmack on Inlined Code64 people · 887 points · first shared 2014 · 260 comments on HN
- 2John Carmack on inlined code (2014)29 people · 952 points · first shared 2016 · 389 comments on HN
- 3Braid Particle System Revision (part 1)6 people · 11 points · first shared 2016 · 1 comments on HN
- 4Mipmapping, Part 1 (2001)3 people · 4 points · first shared 2013 · discussion on HN
- 5Understanding%20Slerp,%20Then%20Not%20Using%20It3 people · first shared 2021
- 6Braid Code Cleanup (part 1)2 people · 176 points · first shared 2016 · 97 comments on HN
- 7Braid Cleanup (part 4)2 people · 16 points · first shared 2016 · 1 comments on HN
- 8Fast-Forwarding LCGs2 people · 2 points · first shared 2016 · discussion on HN
- 9An Introduction to the Rush Language (1994) [pdf]2 people · 1 points · first shared 2020 · discussion on HN
- 10Index2 people · first shared 2013
- 11Jonathan Blow is cleaning up Braid's codebase, 95 to 69 KLoC in 3 days1 people · 3 points · first shared 2016 · discussion on HN
- 12Game Prototypes1 people · 2 points · first shared 2013 · discussion on HN
- 13Why the Inertia Tensor Is the Inertia Tensor1 people · 2 points · first shared 2016 · discussion on HN
- 14Braid Code Cleanup (part 3)1 people · 2 points · first shared 2016 · discussion on HN
- 15The Inner Product1 people · 2 points · first shared 2014 · discussion on HN
What HN people wrote when they linked it
mananaysiempre · 2025-01-26
To have a compositor not introduce a frame of latency more or less requires it to race the beam, which has definitely been suggested[1], but you can see how it’d be difficult, and so far no operating systems have tried as far as I know. And as for good frame pacing support in UI toolkits (and not just game engines), well, one can dream. Until both of these are in place, 2.5±0.5 seems to be the hard limit, the question here is more where the Mutter is losing another frame (which even the greats tell us[2] is not hard to do by accident).
[1] https://raphlinus.github.io/ui/graphics/2020/09/13/compositor-is-evil.…
[2] http://number-none.com/blow/john_carmack_on_inlined_code.html
whstl · 2024-01-06
Yep. Long functions can be easier to read and simpler to follow than multiple methods, if they're well documented.
Carmack has a good essay about it.
http://number-none.com/blow/john_carmack_on_inlined_code.html
tlarkworthy · 2023-09-15
John carmack said much the same and I have been following it ever since. Of course linear code is easier to read, if follows the order of execution. It minimizes eye saccades.
Some code needs to be non-linear for reuse. Then execution is a graph. If you code does not exploit code reuse from a graph structure, do not bother introducing vertexes where a single edge suffices.
http://number-none.com/blow/blog/programming/2014/09/26/carmack-on-inl…
ZephyrBlu · 2023-02-18
I like Carmack's approach to functions the best:
"If a function is only called from a single place, consider inlining it.
If a function is called from multiple places, see if it is possible to arrange for the work to be done in a single place, perhaps with flags, and inline that.
If there are multiple versions of a function, consider making a single function with more, possibly defaulted, parameters.
If the work is close to purely functional, with few references to global state, try to make it completely functional.
Try to use const on both parameters and functions when the function really must be used in multiple places.
Minimize control flow complexity and “area under ifs”, favoring consistent execution paths and times over “optimally” avoiding unnecessary work."
http://number-none.com/blow/blog/programming/2014/09/26/carmack-on-inl…
Verdex · 2021-07-26
False.
Bryan Cantrill (OS developer who used to work at sun microsystems) talks about how the C macros are great [1].
John Carmack talks about how long functions can be better than short ones [2].
Every piece of advice that I've heard has had a contradiction coming from a preeminent developer.
To be fair, yes, people do agree on bad practices. They are just often wrong. People agreeing that something is true doesn't make it that way.
[1] - I believe that he mentions that here however, I'm not sure. I have heard him mention it in more than one video. https://www.youtube.com/watch?v=LjFM8vw3pbU
[2] - http://number-none.com/blow/john_carmack_on_inlined_code.html
ratww · 2021-05-26
> I think the best compromise is small summary comments at various points of functions that "hold the entire thought".
I think this is the best, honestly, it reaps most benefits of small single-use functions, without compromising readability or requiring jumping.
This is also how John Carmarck recommends in this popular essay: http://number-none.com/blow/john_carmack_on_inlined_code.html
gameswithgo · 2021-01-23
When you get into more "low level" domains, huge single files are more common. Some feel there is a correctness justification, being able to follow the code from top to bottom rather than jumping around, see: http://number-none.com/blow/blog/programming/2014/09/26/carmack-on-inl…
Personally I think it just doesn't matter. 50k lines of code is 50k lines of code. Whether it is in one file or 10 or 100, only changes whether you jump around via a file tree or other editor tools.
There are some practical problems when you get too huge though, like not being able to view the thing in github!
reuben_scratton · 2019-06-24
John Carmack's thoughts on this topic are worth a read: http://number-none.com/blow/blog/programming/2014/09/26/carmack-on-inl…
modeless · 2016-08-28
I think there is a growing rebellion against the kind of software development "best practices" that result in the kind of problems noted in the article. I see senior developers in the game industry coming out against sacred principles like object orientation and function size limits. A few examples:
Casey Muratori on "Compression Oriented Programming":
https://mollyrocket.com/casey/stream_0019.html
John Carmack on inlined code:
http://number-none.com/blow/john_carmack_on_inlined_code.html
Mike Acton on "Data-Oriented Design and C++" [video]: https://www.youtube.com/watch?v=rX0ItVEVjHc
Jonathan Blow on Software Quality [video]: https://www.youtube.com/watch?v=k56wra39lwA
pistachiopro · 2015-09-27
Game designer Brian Moriarty's 2002 Game Developers Conference talk discusses Masquerade quite a bit and I think does a good job of viscerally conveying its appeal. The text of the talk is here: http://ludix.com/moriarty/psalm46.html , but I think it's worth listening to the original recording, which you can get here: http://number-none.com/blow/media/psalm_46.mp3
cellularmitosis · 2024-08-06
If you think these things are considered harmful, I'd encourage you to read "John Carmack on Inlined Code" http://number-none.com/blow/john_carmack_on_inlined_code.html
"The flight control code for the Armadillo rockets is only a few thousand lines of code, so I took the main tic function and started inlining all the subroutines. While I can't say that I found a hidden bug that could have caused a crash (literally...), I did find several variables that were set multiple times, a couple control flow things that looked a bit dodgy, and the final code got smaller and cleaner."
If Carmack finds value in the approach, perhaps we shouldn't dismiss it out of hand.
Also worth noting his follow-up comment:
"In the years since I wrote this, I have gotten much more bullish about pure functional programming, even in C/C++ where reasonable... When it gets to be too much to take, figure out how to factor blocks out into pure functions"
jeffomatic · 2023-04-14
This is an old debate and yet one that is difficult to think through. I share your experience of having trouble convincing someone else not to combine things too hastily. Partly it's a "my gut feel is different to yours" situation, but I often don't have the confidence that I could articulate my reasoning without indulging in a wordy lecture on minutiae.
Lately I have been fixating on the following line of thinking: the unit of deduplication--usually a function, but sometimes even bigger--is the same thing as the unit of abstraction. When you dedupe, you've also given birth to a new abstraction, and those don't come for free. Now there's a new thing in the world that you had to give a name to, and that somebody else might come along and re-use as well, perhaps not in a context where you originally intended. The new thing is now bearing the load of different concerns, and without anyone intending it, it now connects those concerns. The cost of deduplication isn't just the work of the initial refactor; it's the risk that those future connections will break something or make your system harder to understand.
This reminds me of another famous Carmack pronouncement about the value of longer functions [1], which I think has some parallels here. In the same way we're taught to DRY up our code, we're taught to break up long functions. I sort of think of these two things as the same problem, because I view their costs as essentially the same: they risk proliferating new and…
nyanpasu64 · 2022-05-22
I'd love a tool that would observe my code during runtime - capturing all inputs and outputs from every function, as well as the value of each variable at each point in the execution flow, and the call graph. Because this would probably incur a performance hit, I'd want to have the option to toggle it on/off.
After execution, I can scroll through a tree of called functions and convert it into permanent "implementation documentation" (saved in a document I can annotate eg. with data flow, and edited when the code itself changes), helping me understand both the structure and dynamic control flow of code I'm learning or relearning after months of absence. I currently do this manually in Google Doc bullets, in order to make sense of legacy code whose control flow is fragmented into many function calls I must piece together mentally (as described in http://number-none.com/blow/john_carmack_on_inlined_code.html), and as a starting point for restructuring types and function graphs.
dgb23 · 2022-05-10
John Carmack has written about it and agrees with you with the caveat that functional programming alleviates or even eliminates this kind of issue. AKA if your extracted procedures are just functions, then it can improve your code. And since this is Elixir we are looking at presumably mostly functional code.
http://number-none.com/blow/blog/programming/2014/09/26/carmack-on-inl…
I want to add a third condition that makes this decision easier IMO, because I think it is insufficient to say "if it is a pure function you can extract it". It can often be the case, but it can also lead to what you describe regardless.
It is insufficient if the extracted function is just a one-off helper. The remaining downstream code should read as an _abstracted_ form. Meaning the naming of the functions is clear, uniform and in the best cases they represent a domain layer: A mini-language that communicates clearly what is going on, but draws away from the details. And most importantly it should follow John Ousterhout's proposed rule about interface surface to implementation depth ratio, which should be kept as small as possible.
To the example: I don't think the amount of cases handled should have any implication on extracting functions here (as mentioned in the example). It would still be clearer to just return the data directly. Nothing is gained until the body of the functions themselves have enough _depth_ to provide a useful abstraction, the function names would naturally…
jakevoytko · 2021-09-30
Developers end up at local maxima because a whole bunch of practices add up to a working system. It's a mistake to champion any single practice without understanding how it fits into an ecosystem: time budget, testing, language features available, efficiency, tolerance for errors, imposed deadlines, third-party technical ecosystem, etc. It's all about the system where they all work together.
To truly suggest something as a best practice, you need to understand what it requires from the technical and social environment around it, and when it applies and doesn't apply. We're nowhere near that level of discipline as a field. This lack of discipline is why we wince when we hear that a startup is implementing something like voting machines: we know the financial incentives that lead to startups focusing on speed, and we can imagine the discipline that voting systems require. We know there's a mismatch between the social environment and the likely project management approach. But we're blind to the social and technical requirements that allow other practices to work well. When is it appropriate to use inheritance? Someone will inevitably say, "You shouldn't use it?" Why does it work so well in Rails?
IMO it's how developers like John Carmack[0] and Martin Fowler[1] can make opposite arguments about things like the benefits of having code inline or in functions. These two opinions work in conjunction with their environments; maybe video game and aerospace coding requires budgeted…
albertzeyer · 2021-08-26
So this article concludes that starting with a certain project size, over-engineered code is easier to work with than under-engineered code, and scales well when the projects grows (even "linear with the size").
But what this article is actually about is about entanglement of individual parts. Under-engineered implies spaghetti code with lots of entanglement. Over-engineered code does have the minimum needed amount of entanglement.
Of course this is right on the topic of entanglement.
But this is not so much my understanding of the terms over-engineered vs under-engineered.
I understand over-engineered as having too much abstractions. And those can turn out to be the wrong abstractions when they are actually used, which then requires more work to refactor this.
I understand under-engineered as having too little abstractions, and having build in some assumptions which might hold for one use case but not anymore for others. This can also require some effort to fix this.
In practice, this is also a continuum, and you might even have both things mixed.
And when actually writing some new code, it is often hard to know the right amount of complexity.
This is why the overall quality greatly improves when you do a couple of iterations of rewrites from scratch. Because you keep improving on just the right needed abstractions.
Related:
http://number-none.com/blow/blog/programming/2014/09/26/carmack-on-inl…
https://github.com/Droogans/unmaintainable-code
danShumway · 2021-05-26
> But as we get closer to 100 lines I doubt that it's more understandable and readable to have it all in one big blob of code.
Well, but that's exactly what I'm pushing back against. I think the rule of 30 is often a mistake. I think if you're going out of your way to avoid long functions, then you are probably over-abstracting your code.
I don't necessarily know that I would inline a quicksort function, because that's genuinely something that I might want to use in multiple places. It's an already-existing, well-understood abstraction. But I would inline a dedicated custom sorting method that's only being used in one place. I would inline something like collision detection, nobody else should be calling that outside of a single update loop. In general, it's a code smell to me if I see a lot of helper functions that only exist to be called once. Those are prime candidates for inlining.
This is kind of a subtle argument. I would recommend http://number-none.com/blow/john_carmack_on_inlined_code.html as a starting point for why inlined code makes sense in some situations, although I no longer agree with literally everything in this article, and I think the underlying idea I'm getting at is a bit more general and foundational.
> Do you think that inlining the partition function would make this easier or harder to read?
Undoubtedly easier, although you should label that section with a comment and use a different variable name than `i`. Your secondary function is just a…
MaxBarraclough · 2021-05-25
Carmack's writing on the proper length of functions (although he expresses it in terms of when to inline a function): http://number-none.com/blow/john_carmack_on_inlined_code.html.
2014 HN discussion: https://news.ycombinator.com/item?id=8374345
A choice quote from Carmack:
> The function that is least likely to cause a problem is one that doesn't exist, which is the benefit of inlining it. If a function is only called in a single place, the decision is fairly simple.
> In almost all cases, code duplication is a greater evil than whatever second order problems arise from functions being called in different circumstances, so I would rarely advocate duplicating code to avoid a function, but in a lot of cases you can still avoid the function by flagging an operation to be performed at the properly controlled time. For instance, having one check in the player think code for health <= 0 && !killed is almost certain to spawn less bugs than having KillPlayer() called in 20 different places.
mrec · 2020-08-04
I think mostly because having scads of clever conditionals all over the place greatly increases the risk of subtle and hard-to-reproduce bugs. From a 2007 Carmack email [1] :
> The way we have traditionally measured performance and optimized our games encouraged a lot of conditional operations -- recognizing that a particular operation doesn't need to be done in some subset of the operating states, and skipping it. This gives better demo timing numbers, but a huge amount of bugs are generated because skipping the expensive operation also usually skips some other state updating that turns out to be needed elsewhere.
> We definitely still have tasks that are performance intensive enough to need optimization, but the style gets applied as a matter of course in many cases where a performance benefit is negligible, but we still eat the bugs. Now that we are firmly decided on a 60hz game, worst case performance is more important than average case performance, so highly variable performance should be looked down on even more.
There was fascinating breakdown [2] of a single GTA V frame about five years back. It was a real eye-opener for me - whole full-screen rendering passes for things like water reflection and refraction when there isn't even any water visible in the scene.
[1] http://number-none.com/blow/john_carmack_on_inlined_code.html
[2] http://www.adriancourreges.com/blog/2015/11/02/gta-v-graphics-study/
gilbetron · 2019-01-27
I love when developers make food analogies, they almost always show their ignorance of cooking, and sometimes of software development. After 30+ years of software development, I always read the actual code to find out how software works. "CombineIngredients" is useless and honestly quite horrific. Instead of "simplifying" it is obfuscating. The details of cooking are in the function. I don't need to see "PreheatOven" at the same level as "CombineIngredients". One of my favorite posts on this subject is: http://number-none.com/blow/john_carmack_on_inlined_code.html
Tucking away code in a function serves a purpose, and that purpose is not to make the highest level function hold no detail. Like cooking, software is about the details, so don't hide them from me. I can't stand the "Russian Doll" approach of a function that just calls another function that just calls another function that just ... Nothing improves the understandability of 10 lines of code than spreading it across a 10 functions often in different files /s
Great abstractions exist, but very few abstractions are great.
jeremiep · 2016-10-09
Nothing unusual there.
It looks like its built on top of irrlicht which probably brings in its own framework view of the world to begin with.
200+ lines functions happen MUCH MORE than you think in AAA code; why split a function if there's going to be a single static caller. John Carmack himself wrote about it a few years ago: http://number-none.com/blow/john_carmack_on_inlined_code.html
All the traits you list are superficial compared to getting the thing working and performing well in the first place :)
Heck these are the sort "clean code" practices which make your debug build run at 5 FPS (I've seen worse :). Indirections and conditionals and noise everywhere.
These get stripped in release (hopefully) but the catch is that you end up stepping in optimized code cause 5FPS can't get you where you want to test. Having all that nice cleanliness in a debug build you won't use isn't a great way to end up developing after 5 years of piling stuff up :)
Besides, you can design your systems so that they're both fast and simple; data-driven design is one such approach. Mike Acton talked about it a lot as well: https://www.youtube.com/watch?v=rX0ItVEVjHc
doty · 2016-07-19
From http://number-none.com/blow/blog/programming/2016/07/07/braid_particle…
The game Braid originally shipped to the world in 2008, and after some ports in 2009, I have only worked significantly with the code on a few occasions. But I want to maintain this game indefinitely into the future; in the back of my mind, there have always been some clean-ups that I have wanted to perform on the code. Often when shipping a game, the best answer to a problem isn’t evident, and we are under time pressure, so we solve the problem in some way that is sufficient but sub-optimal. Other times, we need to design the game to meet technical constraints of systems we want to deploy on, but as the years go on, these systems become irrelevant, so the code can be cleaned up. I figured it would be interesting to talk about some of these things in a blog (and the blog will help motivate me to think about these situations and clean some of them up!)
yoklov · 2015-05-03
Worth keeping in mind that you don't always want to split something into a separate function. When you split out a function, you should be asking yourself if you're actually simplifying something, or if you're just sweeping the complexity under the rug. If the person reading the first function will typically need to see the definition of the helper, the helper's definition is non-obvious, and the helper wouldn't be used elsewhere, it's probably not worth splitting out.
Another important consideration is whether or not the code block you split out makes any assumptions about the current state of the program (or object or whatever), and if those assumptions not being met would result in non-obvious bugs. (If this is true, you should probably wait until there's actual duplication somewhere before splitting the function out, IMO.) This is obviously not an issue with pure functions, but for most programs, most functions aren't pure.
See http://number-none.com/blow/john_carmack_on_inlined_code.html for further perspective on this.
jan_Inkepa · 2025-12-18
I'm actually a fan of his game/prototype Painter from 2006 - was just talking about it today.
http://number-none.com/blow/prototypes/index.html
It's very different from his more recent stuff, but charming.
vanschelven · 2025-11-28
And here's John Carmack on the subject of 1000s of lines of code in a single function: http://number-none.com/blow/blog/programming/2014/09/26/carmack-on-inl…
embedding-shape · 2025-10-31
I don't think this is the first time Carmack been talking about functional programming and against mutability, here is some of his thoughts from 2014: http://number-none.com/blow/john_carmack_on_inlined_code.html
Just because someone is expressing a thought after you or others have already thought about it, doesn't mean they're trying to push it as something new and exciting, it's just another perspective.
nake89 · 2025-10-20
John Carmack wrote about inlining code: http://number-none.com/blow/john_carmack_on_inlined_code.html
thot_experiment · 2025-02-06
Agree, people underestimate the cost of interfaces that don't sit exactly where they need to sit (which is almost always the case)
http://number-none.com/blow/john_carmack_on_inlined_code.html
ilrwbwrkhv · 2024-12-22
Yes public "deep" methods. But even private methods I have been more conservative.
It is after all an API for you!
Basically the idea that you shouldn't have long methods is something I don't believe in anymore. Even Carmack made a similar point: http://number-none.com/blow/blog/programming/2014/09/26/carmack-on-inl…
bsder · 2024-10-28
Carmack is probably the only one who sticks out as he wasn't rich, connected or have early access.
Gates had super-early access to computers via his prep school. By the time he left high-school, he probably had more computer experience than almost all college graduates.
Jonathan Blow spent almost 5 years at Berkeley and hooked up with the Tcl guys (Adam Sah sticks out). That's practially a graduate degree. see: http://number-none.com/blow/papers/rush_tcl94.pdf
Markus Persson--(By 1994, Persson knew he wanted to become a video game developer, but his teachers advised him to study graphic design, which he did from ages 15 to 18. ... He never finished high school, but was reportedly a good student.) That's hardly a high school dropout. And, IIRC, studying something like graphic design in the system in Sweden is akin to an apprenticeship, no?