← Blog

Code is thought written down

24 June 2023 · 4 min read · Nasim Akhtar

Code is thought written down so precisely that a machine can act on it. That is the whole claim of this post. Everything else follows from taking it seriously.

Two readers at once

Most writing has one reader. Code has two. The machine needs every step spelled out with no room for doubt. The person who opens the file next month needs to know why the steps are there.

So every name is a choice of words. Every function is a decision about where one idea ends and the next begins. Every module is a claim about how the problem splits apart. You can make the machine happy and leave the person lost. Most bad code does exactly that.

The attention it asks for

Good work in code asks for the same thing as sitting still and watching your breath: steady attention. You hold the whole system in your head and still notice the off-by-one in line 40. Lose either and the work goes wrong.

It also rewards coming to a problem fresh. The pattern that solved the last bug is the first thing you reach for. Sometimes it is the wrong thing, and you only see that if you look at what is actually in front of you.

Debugging is checking your own beliefs

A bug is the gap between what you thought the program did and what it does. Fixing it is mostly a matter of finding which belief was wrong.

The steps are plain:

  1. Look at what is happening, not what should be happening.
  2. Trace how it got there, one cause at a time.
  3. Name the assumption that failed.
  4. Test the new understanding before trusting it.

A loop runs forever. You expected it to stop. You trace it back and find the belief underneath: this array always has at least one element. It doesn't. It can be empty. The code was never the real problem. The mental model was.

That is why debugging teaches more than it seems to. Each fix leaves you with one fewer false belief about the system — and a question about which others are still in there.

Reading code is reading a mind

Open someone else's code and you see how they think. Here are two people solving the same problem:

# Someone who thinks in pipelines
def process_data(raw_input):
    return (raw_input
            .clean()
            .validate()
            .transform()
            .aggregate()
            .format())

# Someone who thinks in state machines
class DataProcessor:
    def __init__(self):
        self.state = InitialState()

    def process(self, input):
        self.state = self.state.handle(input)
        return self.state.output()

Neither is wrong. The first sees data flowing through stages. The second sees a system moving between conditions. You learn more about a teammate from an afternoon in their code than from a week of meetings.

What makes code good to read

Programmers call code "beautiful" and mean something real by it. When I try to pin it down, I get four things:

  • The intent is obvious. You know what it is for before you know how it works.
  • The parts fit. Nothing feels bolted on from a different design.
  • It does a lot with little. No step you could delete.
  • It reads in one pass. Your eye doesn't have to jump back.

When code gets all four right, it feels like there was no other way to write it. That feeling is the test. If you can picture a cleaner version, the code isn't done.

Many minds, one codebase

Linux, React and Rust each hold the thinking of thousands of people who mostly never met. No single one of them could have built the whole thing. The code is where their ideas meet, get argued over and settle.

That only works because code forces the ideas into a form others can check. Vague thinking doesn't compile.

Why it matters now

We now hand more of this work to machines that write code too. That makes the human side matter more, not less. A program still has to say clearly what someone meant, or nobody — person or agent — can work with it later. I write more about where that goes wrong in The AI agent illusion.

Write code for the person who reads it next. The machine will cope.