neutral words (super wip, but why not write in public)

a rant about how people talk about programming and game design, filled with strawmans of the programming community. please send any angry complaints about this essay to my feedback form

When you get into almost any technical-ish art form, you start to become aware of lots of somewhat-subjective-but-also-technical words that are used to describe artistic work in a neutral manner.  They are describing a property of work which may be good or bad, depending on context, but which definitely concretely describe something. You could do blind tests, and experts would use the same words about the same pieces of art. The easiest way to introduce these is examples.

  • In typography, we might refer to rhythm and modularity, which are respectively properties of the variation in letter spacing and variation in stroke thickness. Both are fundamentally visual/artistic things, but people can recognize them.

  • In mixing, we might refer to a mix as separated or glued, which are two almost-opposite terms relating to how distinguishable different stems are audibly. In mastering, you might hear the word warmth a lot, which definitely relates to lower-mid frequencies, but is still really requires some level of human judgement.

  • In photography, which I know very little about, there seem to be a huge number of these. Some of the more common neutral words are concrete and can be turned into sliders in photoshop, but many are more subjective. Density comes to mind as a somewhat subjective one.

  • My friend says porosity is a good one for architecture, which is about how spaces transition between each other. Everyone knows what’s porous and what isn’t, but it’s hard to make a slider for it.

  • I feel like ceramics, glass-blowing, dance, sculpture, painting, film, and many more must have hundreds of these, so send them to me if you read this!

So far, all pretty obvious, right? But a thing I want to emphasize is when artists talk about these things amongst themselves, they are truly using them in a neutral way, despite the fact some have positive connotations. Sure, porosity is often good, but among architects, it more “serves a purpose in a certain situation”. It is somewhat counter to a feeling of privacy in a home, for example.

Well, here’s my question: why can’t programmers talk like this amongst ourselves, when it comes to code? Before you sensibly object, let me start by stating: many things in programming are not very subjective. These include: space/time complexity, real space/time performance, utilization, correctness, whether people use it, and many more things. And often, when it comes to programming, these concrete metrics are the important things. At my work, these are what I prioritize. (Indeed, I tend to agree with Casey Muratori and Jon Blow that many too many people are ignoring these things totally, which frequently makes “old” programming languages better. But that’s a whole different essay…)

The issue is that because of these “objective” things, a fair number of programmers start to think in black or white. They think everything is like this. And it turns out there are a lot of things which are not inherently good or bad, but programmers fail to use neutral words about. Even if they use seemingly neutral words, they use them very non-neutrally.

Here are some examples of describing programming languages with supposedly neutral words.

  • Functional: this is a great neutral word. Except almost no-one uses it neutrally. Functional is presented either as “slow and abstract” or “the programming method of the gods.” Spoilers: it is neither. It is a frequently useful paradigm, that sometimes should be ignored for performance reasons.

  • Type-safe: this is an interesting one. People almost always present type safety as good. I love type-safe programming. I agree. But then… why the hell do so many people like Python? Because type safety is not always good. It’s a neutral word, but people only use it to mean “good”.

  • Low-level: maybe C-like is a better phrase here. Web developers think this is old-fashioned idiocy, and Jon Blow thinks it’s the only remotely sane way to program. Not all that many people are neutral on it.

In my opinion, these should all be neutral words, but to many programmers they’re just not. They’re marmite: loved or hated. As programmers, we’re dogmatic when we use them. So first of all, that’s dumb. (In general when it comes to programming languages, it often feels like developers are thinking: I want to use Rust, how can I build my system around rust? Rather than: this system needs these subjective neutral qualities, Rust is a probably good call. This is also dumb, and I think partially a function of this lack of neutral thinking.)

But perhaps more interestingly, there are a whole series of things about which programmers barely even have these words. These are questions of programming style. Now, to be honest, I’ve not read many books on programming style. I don’t tend to think they’re very good. But I have at least briefly looked at Clean Code and The Pragmatic Programmer, for the sake of this essay. And as far as I can tell, these are basically just lists of things to do; some of them are truly idiotic, as qntm points out in this essay, but even ignoring the stuff that is just self-contradictory, these books strike me as immature, and lacking basically any neutral words to describe programming style.

DRY is a great example of this. Both of these books are fairly fierce advocates of DRY, with Clean Code famously saying repetition “may be the root of all evil in software.” It is very far from a neutral word when it is used. It is uniformly positve. But is DRY good? I guess it’s useful, until you realize that your function or workflow needs to do slightly different things in two places, or on two different pieces of data. Then you end up trying to put some flags in, and it gets crazier, until you realize that actually this logic is pretty simple if you just hadn’t try to “not repeat yourself”, and maybe just done some data-oriented dispatching to different functions. Dockerfiles are like this for me. You can put logic in one Dockerfile for arm/x64 images, or be careful about a shared base image and only separate out a bit, and deal with all that crap. Or you can just have two different Dockerfiles for arm and x64, and maintain them both, because eventually they’re going to be substantially different anyway so… why bother with DRY? So DRY can be definitely be bad. But also: when I’m writing code for myself, I enjoy writing code that does stuff. I don’t enjoy refactoring code to make it less repetitive, or more abstract. So when it comes to writing code for myself, DRY is just… not my style.

Maintainability is another one I think about a lot. I often hear from Googlers that maintainability and readability is the most important thing in any codebase. But I’ve worked with some damn fast code that was a fucking nightmare to maintain. And it was great code because of how fast it was, when literally all the relevant OSS was slow as hell. Enjoyment-wise, it happens that I like writing maintainable and readable code. It’s how I write by default. But I know people that just like writing shit as fast as possible and never looking at it again. That’s cool too.

So the first point is DRY is situational. Maintainability is situational. Both are sometimes (even usually) a great quality of code, but occasionally they are an awful quality, because of the compromises you have to make. Abstraction is the same. “Clean” is the same. Much of “SOLID” is the same. But people who write about programming–perhaps as a function of Bob Martin–just like to talk in absolutes.

But the second (and perhaps more important) point is when it comes to your style–how you enjoy writing code, and how you appreciate code as an object in and of itself–these things are truly subjective. I like functionally written code. I like code with pointers. I like code that repeats itself. I don’t like Python, other than for leetcode. I don’t like abstraction at all. I’m not saying that I do or don’t do these for my job; I work in a start-up, and they pay me to write whatever code needs to be written in whatever language and style makes most sense for the company at that moment. I proudly don’t give a fuck in that context. But there are subjective styles of code that I enjoy and that I don’t, that I appreciate and that I don’t. And it’s weird that people are so religiously dogmatic about telling me what I should do, and what I should like. I love the fact that large parts of VVVVVV and Balatro–two fantastic games which both run on potatoes–are basically just giant switch statements. I like to think that’s not just the right way to code for Terry Cavanagh and LocalThunk. I like to think it’s how they enjoy writing code. The famous and beautiful fast inverse square root is also a wonderful example here. This code rules. It breaks every reasonable convention. The comments don’t help at all. It’s not maintainable. I guess it’s fast, but not on modern hardware. There’s a commented “2nd iteration” of Newton’s method. But god-damn, this code has style. Whoever wrote it definitely enjoyed it. That’s why there is // what the fuck? in a comment.

An interesting aside at this point (which you’ll sometimes hear if you bring this up) is that in programming, you have enough control of the code to refactor the code in order to make Bob Martin’s advice better advice in your situation. There’s a kind of meta-programming here where almost anything (or any style) can be made good advice (or good style) after the right refactor. This is kind of cool, and gets you into a whole bunch of interesting questions about something like “meta-style”. But in the real world, honestly: what developer has time to do this to every piece of code they write? I’d rather LocalThunk release his damn game rather than remove this beautiful thing. And outside of the world of games, I find system design is hard enough as it is. Modifying your system design to make a certain programming style more applicable is just… a lot. I also think I claim this argumentation also leads situations where you start compromising on system design or performance in order to accommodate your desired style, which is (as mentioned above), just not where you want to be. So in short: I’m not going to admit that Clean Code is good simply because “in theory, it could be good advice with enough refactoring, and if I didn’t mind making my codebase a little slower.” I don’t have time for that, sadly.

But getting back on topic, what does a mature version of "programming style” discourse look like? Well, I’m not sure. I’m pretty sure we’re not there. As I acknowledge in the sub-header, I’m straw-manning a lot of software engineers in this complaint. Having said that, I know that leather workers don’t go around saying their style is great and everyone else should use it. And F# and Clojure programmers genuinely seem to do that a lot. I think part of fixing this might just be teaching differently. Maybe we should have a class where people solve a problem in 4 different languages and styles, and reflect on what they’re good for or not good for. And what they enjoyed and didn’t enjoy.

TODO(knowlsie): Finish this? Polish this? Add the bit on game design you wanted?