Casey Muratori is a game programmer and creator of Handmade Hero who writes about API design, performance, and code structure.
Commenters repeatedly recommend his 'Semantic Compression' post for structuring low-level code and credit him with coining immediate-mode GUIs.
What asiachick wrote below.
Muratori has demonstrated to me one time too many that he hasn't a got a clue about the things he's talking about.
To be precise: He may or may not have a clue about some things he's talking about, but I don't know enough about them to form an opinion. But in more than one occasions he went on to talk (sometimes at great length) about things where I know he's mostly or completely wrong in what he said.
I don't have a way to know the scope of these things, the things he doesn't know or understand yet talks about. Maybe it's just when it comes to "systems programming". Maybe it's everything that isn't game design and programming. And maybe he's wrong about games too. As I said, I don't know enough to judge everything he says, but the things I was able to judge convinced me not to trust him and his opinions.
And since I can't set the scope safely, I have to not trust him regarding everything.
For example, while his post[1][2] on ETW being "the worst API ever made" is slightly amusing and has _some_ good points, it mostly demonstrates:
(a) Inability or unwillingness to read the documentation. It would have saved most of his problems. But let's say that to criticize the _design_ of an API we can disregard that for a moment.
(b) Inability or unwillingness to pick the right tool for the task or pure trolling.
(c) Worst of all: Complete lack of understanding of the goals, purposes, limitation, design goals and tradeoffs of the system.
You can't…
The issue with those books is that they don't have any concrete data that affirms that they are worth following. And, in fact, that style of code is largely to blame for why modern software feels so sluggish. They often reduce performance by 10x if not 100x or worse. I like this video on the topic for reasons not to follow SOLID principles[0]. Muratori also has an excellent talk on writing APIs that are flexible and performant[1]. As for books on understanding the hardware performance, Computer Systems: a Programmer's Perspective, is the best example (not the international edition though, according to the author's recommendation).
I'm not aware of any architecture books recommended by anyone that cares about performance unfortunately. Most high performance software is written iteratively, meaning they aren't assuming a code structure from the start. Andreas Fredriksson, a lead engine programmer at Insomniac Games, has an excellent quote on how he writes high performance software[2]:
> Work backwards from hard constraints and requirements to guide your design. Don’t fall into the trap of designing from a fluffy API frontend before you’ve worked out how the thing will handle a worst case. Don’t be afraid to sketch stuff in while you’re proving out the approach.
> The value is what you learn, never the code. Hack it and then delete the code and implement “clean” or whatever you need. But never start there, it gets in the way of real engineering.
> As an industry we spend…
My personal experience is that it depends on the context.
Writing new functionality is usually easy if it's self contained. If I know what inputs I will have and what outputs I want, then I generally have a pretty solid idea of how to derive one from the other before the first keystroke.
But if I find that the new functionality is turning into an internal API that will be consumed in multiple places for multiple use cases, things aren't so obvious anymore. You have a combinatorial explosion of design parameters: not just inputs, outputs, and algorithm, but also issues like ownership of data, ownership of the stack, which inputs are supplied at which point in the process, when is it legal to consume outputs and in what ways, push vs. pull interface, two functions for similar functionality vs. one with a flag. When the design parameter space gets this large, it's hard to reason about it ahead of time, and sometimes the most straightforward API doesn't reveal itself until you write code that uses it and realize that there's needless boilerplate or inconsistency that opens up room for logic errors. Then you go back and refactor to eliminate that. Casey Muratori calls this iterative process semantic compression [1]. I don't agree with all his software development takes, but I think he hits this one pretty squarely on the head. The key insight is that an experienced programmer can write good code on the first pass, but it usually takes a second pass to write great code.
[1]…
“OOP” is one of those terms (like most terms) that have a narrow meaning and a broad meaning, and either proponents or detractors can use one of them in arguments:
• OOP, narrow sense (emphasis on “object”): data-with-associated-functions, encapsulation, etc.
• OOP, broad sense (emphasis on “oriented”): organizing your program around objects that model the nouns in the problem domain, “everything is an object”.
A (satirical) illustration of the latter is in the first few paragraphs of https://caseymuratori.com/blog_0015 (from 2014), which gives an example where, to write a payroll system, you first start by designing classes for “Employee”, “Manager”, etc.
A (non-satirical) illustration is in the infamous “TDD Sudoku” series of blog posts (follow the links from http://ravimohan.blogspot.com/2007/04/learning-from-sudoku-solvers.html or https://news.ycombinator.com/item?id=3033446) where (in contrast to Norvig's program which just solves the problem) the TDD/OOP proponent ends up with a “class Game”, “class Grid”, “class Cell”, “class CellGroup” (with derived classes “Row”, “Column”, and “Square”), but ends up nowhere. (From Seibel's post: “…got fixated on the problem of how to represent a Sudoku board. […] basically wandered around for the rest of his five blog postings fiddling with the representation, making it more “object oriented” and then fixing up the tests to work with the new representation and so on until eventually, it seems, he just got bored and gave up,…
This is an interesting article, but seems to fail to complete the point being made. Yes, having a very flexible API that has lots of possible entry points and extensions is useful to experts, but risks overwhelming those new to the API, especially if they are also new to the domain. Likewise having a convienent, inflexible API can lead to short term adoption at the expense of long term commitment.
Despite making both of these points, and even then going as far as to say you can package a more flexible API into less flexible but more immediately convienent parts arbitrarily, it doesn't quite complete the point by indicating what you really want to aim for is a layered API that allows you to start off with a convienent, high level wrapper and as you need more flexibility, peel off that layer specifically in the place you need it. As ever, talking in the abstract about such things make them seem easier than they are, but still a worthwhile goal.
It's slightly surprising the post doesn't quite make this point, considering that they directly link to Casey Muratori's talk on exactly this as a footnote: https://caseymuratori.com/blog_0024.
Separately, I also find it interesting that there are domains that seem to be deliberately eskewing the layered approach within a single API in favour of requiring separate users to write the higher level convience libraries. Notably some of the modern graphics APIs, including WebGL and WebGPU, which provide the 'lower level' access to…
Author of the article here:
I highly recommend reading the previous article to this one posted (Pragmatism in Programming Proverbs) to get a better understanding of what I am expressing, since "The Essence of Programming" is a sequel to that article. I originally wanted to write the previous article in normal prose article, regarding the topic of "Pragmatism in Programming", however I thought I’d experiment in style by writing in a proverbial style.
> The fact that it happens to execute without bugs and produces the correct output is far less important than the code being readable, comprehensible, and consistent as part of the larger system.
I partially disagree with this. If the code executes without bugs (very rare) and produces the correct output, then that code solves the problem. The next task is to make it readable, comprehensible, and easy to maintain whilst not trying to introduce other bugs.
I recommend reading Casey Muratori's article on "Semantic Compression" https://caseymuratori.com/blog_0015
This article is a good overview of the idea I am trying to express in this reply. It's very important to get things working BUT then actually improve it, don't just stop there!