Prompting Is Programming

The other day I watched a friend of mine, an Ivy League-educated professor in the liberal arts, work with Claude. The conversation went in circles, and they never articulated what their goal was. Each reply from Claude was reasonable given what it had been told, and each one was a little off from what my friend actually wanted, so they’d nudge it, and it would drift somewhere else. This is one of the smartest people I know, and I was watching them struggle with a tool that has completely reshaped the way I build software.

That interaction came to mind when I was reading about how industries outside of software aren’t seeing productivity gains from AI. Marketers, analysts, managers, and operations folks get some help drafting emails and summarizing meetings, then spend the time they saved cleaning up plausible-looking output that doesn’t quite do what they needed. The org-wide productivity gains that were promised mostly haven’t materialized. For software engineers, the change is night and day. I basically stopped writing code within a few weeks of Opus 4.5 shipping, and nearly every engineer I know has a version of that story.

The usual explanations are that the models were trained on mountains of code, that code is verifiable because it either compiles and passes the tests or it doesn’t, and that the AI labs poured their best tooling effort into coding agents because their own employees are engineers. All of that is true. None of it fully explains the gap, because I’ve watched other engineers, and experienced it myself, get great results out of these tools on tasks that have nothing to do with code, like planning a trip, restructuring a budget, or drafting a grant proposal.

My theory is simpler. Prompting an AI well is programming. The mental work is the same; only the syntax changed. Engineers are good at it because they’ve spent years doing it, and most other people haven’t done it at all.

Consider what goes through your mind when you write a function or class. You decide what the inputs are and where they come from. You decide exactly what the output should look like. You break the problem into steps small enough that each one is obviously right. You think about the edge cases: the empty list, the missing field, the user who does something you didn’t expect. You decide how you’ll know it works. None of that is about typing semicolons, and all of it is what separates a good prompt from a bad one. A starting state and a goal state are the first things a programmer writes down, even if only in their head. They were exactly what was missing from my friend’s session.

A non-programmer asks the agent to “put together a report on Q3 sales.” An engineer, without really thinking about it, asks a different question: which data, in which file, broken down by what, compared against what baseline, in what format, and what should happen with the two regions that reorganized mid-quarter? The engineer isn’t smarter. My friend could run circles around most engineers I know intellectually. The engineer has just had the precision beaten into them by a compiler.

Every programmer spent years being told, instantly and without mercy, that the computer does what you said rather than what you meant. Non-programmers have spent their careers communicating with humans, who fill in the gaps with shared context and common sense, and who come back with a clarifying question when they’re confused. An LLM also fills in the gaps, but it fills them with the most plausible guess and rarely asks. A vague prompt doesn’t throw an error. The model hallucinates what you meant, hands back something that looks about right, and leaves you to discover where it isn’t. An engineer’s instinct is to distrust output that looks about right. Most people’s instinct is to accept it.

The gap gets wider when the output is wrong. An engineer debugs. They form a hypothesis about which part of their instructions led the model astray, change that one thing, and run it again. A non-programmer tends to reroll the same prompt, append “please be accurate,” or conclude that the tool doesn’t work. They’ve never had to build the habit of treating a bad result as information about their own input.

This complicates something I wrote in May. I argued that domain expertise is the real moat, and that a domain expert with an agent can be startlingly effective because they know what right looks like. I still believe the oracle matters. But knowing what right looks like is a judging skill, and it only kicks in once the agent has produced something worth judging. Getting it there is a specifying skill, and that one is computational. When I look at the non-engineers who really are getting enormous value from these tools, they almost always have a programmer’s brain hiding under a different job title: the finance person who builds elaborate spreadsheets with lookup tables, the ops manager who writes their own Zapier flows, the researcher who wrangles data in R because nobody else would. They were programming all along. They just didn’t call it that.

Which brings me back to my friend. They didn’t need a better prompt template or a list of magic phrases. They needed the habits any second-year computer science student has without thinking about them: say what done looks like before you start, break the work into pieces small enough to check, and when the answer comes back wrong, ask what in your own instructions sent it there. None of that requires knowing a programming language. It does require years of being corrected by a compiler, and most brilliant people have never spent a single afternoon on the receiving end of one.

Natural language programming was sold as a way to let everyone program. So far it mostly lets people who already think like programmers do it faster, in English.