Table of contents
Open Table of contents
We are the humans in the loop

AI has won.
We live in an age of fuzzy development, where AI can generate 95–100% of the code in a feature. A person typing code word after word is no longer simply programming. He is “trad-coding.”
For a person who deeply loves the act of programming, from design to implementation, this understanding is accompanied by heartache and a vague sense of confusion as to the source of the heartache.
There is the fear of being replaced, which gets talked about a lot, but it is easily assuaged by the thought-terminating cliché that:
AI won’t replace you, a developer using AI will.
It is hard to disagree with this formula. But like all clichés, its appeal lies in reducing something complex to something neat, leaving the important nuances behind.
Two thoughts cut deeper to the core of the issue:
-
Solving a bug isn’t satisfying anymore.
-
Writing code by hand that compiles without bugs is becoming a lost art.
The Bitter Lesson
To lay out the case for the skeptics, the argument was already formalized in a short article called The Bitter Lesson back in 2019.
The lesson is that methods which scale with data and compute eventually outperform methods built from hand-crafted human knowledge.

The caveat is that this mainly holds when a problem can be clearly defined, tested, and scored.
Compute is not a universal master key. It does not readily solve ambiguous goals, expensive real-world feedback loops, or problems where a single failure is catastrophic.
But software is unusually vulnerable to the Bitter Lesson.
Code can be generated, executed, tested, rejected, and regenerated quickly. The feedback loop can be automated. Software development is already engineered to somewhat resemble a game.
So the programmer’s role shifts from designing solutions to designing environments in which solutions can emerge. We provide examples and simulations, turn the knobs, test the result, reject its failures, and ask it to try again.
We are effectively stuck in a loop of perpetual review, holding responsibility for work we are progressively less involved in creating.
We are the humans in the loop.
You don’t need to learn how to use AI
The bar for knowing how to use AI is knowing the English language.
Prompt engineering is bullshit.
The harness will become outdated when the next model comes out.
Just figure out what you want and tell him to do it. He is smart enough to understand you if you are smart enough to explain yourself.
Obviously, some models and tools are better than others. There are a few cool tricks and some genuine productivity boosts. But the learning curve plateaus quickly.
Most of the advantage comes from providing context, not fine-tuning the magical wording of a prompt. The gains from prompt optimization are hard-won and meagre compared to simply explaining the system and the problem.
If you are using an established model and not training one, there is no substantial new art here comparable to learning programming, operating systems, databases, networking, or any other technical domain.
We should grieve trad-coding
Yes, we should adapt, but we can only move on after grieving for the world that coding was.
There was satisfaction in hunting down a bug and finally understanding it, in laboring over an implementation for hours until it finally compiled, and in becoming fluent enough in a codebase that the code came flying out of your fingers. Some of this satisfaction is disappearing, and it is not merely the result of fearing unemployment. A craft that shaped the way many of us think is changing into something different.
A junior developer starting now is therefore encountering a new set of problems. AI makes him immediately productive, but that only makes his real problem clearer: learning how to think. In a way, beginners now need traditional programming education more than ever. You cannot learn a language by watching someone else speak it, and you cannot learn programming by only reading code that has already been completed.
Fuzziness isn’t new
In particle physics, researchers generally do not announce a discovery until the evidence is so strong that the result would appear randomly about once in 3.5 million attempts. In psychology and many other fields that study people, a result has historically often been called statistically significant at a threshold closer to one in twenty.
Some domains are more predictable than others, and the human domain has always been fuzzy.
The real issue is not that AI is fuzzy. Managing people is also inherently fuzzy. Human beings have always delegated work through incomplete instructions, made assumptions, misunderstood intent, and produced surprising (and sometimes alarming) results. This isn’t catastrophic in itself. The problem is what happens when fuzziness is combined with detachment.
Slop before AI
![]()
Zig creator Andrew Kelley wrote about Bun’s engineering culture and said that its founder was already writing slop “well before he had access to LLMs.” There is no shortage of pre-AI slop:
- The Meta metaverse, with billions poured into a universe populated by uncanny floating torsos
- Corporate presentations
Under a more rigorous definition, slop does not require AI: slop is the appearance of activity without the presence of thought. AI simply reduces the friction of producing it.
Corporate culture and slop go together like peanut butter and jam because corporations are attracted to things that are measurable and scalable.
Soul, Style, and Substance
For those allergic to the word “soul,” it is sometimes helpful to use the word “brand,” which is what I would do if I were not allergic to the word “brand.”
Branding is concerned with appearance, and I acknowledge that appearances often matter more than reality. But if you enter life with that approach, eventually you become all appearance. The way to avoid that is by caring about the substance and making sure the people in your organization are rewarded for caring about the substance.


Apple and Microsoft are useful examples here: Apple products tend to feel as if somebody had an opinion. The hardware, software, packaging, shops, typography, and language belong to the same universe.
Microsoft products often feel like they were negotiated between several departments. Microsoft Teams might contain every feature requested by every enterprise customer, but the experience of using it can still feel tedious, clunky, and indifferent to the person using it.
The ability of a company to develop a soul or a style depends on whether the people inside it are allowed to care. Most organizations will gladly say that they want passionate employees who take initiative and bring their full selves to work, but passion is inconvenient because people who care deeply tend to develop opinions.
A manager does not need to explicitly repress this behaviour. It is enough to respond to an unfamiliar idea by asking why time is being wasted on it, or to reward predictable delivery while treating experimentation as a deviation that requires justification. People eventually learn how much of themselves the organization is actually willing to accept, and the result is a quiet reduction of effort and care.
Against tickets
Tickets are useful representations of work, but they are not the work itself. You can open ten pull requests, resolve forty tickets, attend six meetings, and still do nothing that mattered that day. The problem begins when the representation is easier to evaluate than the underlying reality, because from that point onward the organization naturally starts optimizing the representation.
The previous paradigm for mismeasuring developers was commits; the new paradigm is tokens. Both measure volume, not because it corresponds particularly well to value, but because it is easy to count.
It is the corporate equivalent of assuming that the loudest person in the room is the smartest. We already know that the person with the most useful thing to say might listen more than he talks, doubt himself, or spend more time understanding the problem before announcing anything. In the same way, the most important contribution to a system might be a decision that prevents six months of unnecessary work, and it may produce no impressive activity graph at all.
To know whether an engineer is good, you have to work with him closely, observe how he makes decisions, and remember whether those decisions aged well. This knowledge is incredibly specific to a person, a team, and a system, which is why companies naturally fall back on more easily measurable metrics.
Nuts and bolts!
Music is a useful metaphor because it is emotional and immediate when you hear it, but becomes extremely technical when studied closely.

Take a tritone substitution in harmony. In one sentence, it sounds dry: replacing a dominant chord with another dominant chord a tritone away because they share important voice-leading tendencies. But when you hear it, it has colour, tension, and movement. The boring technical detail is not separate from the feeling - it is part of what creates it.
Programming is similar. Some details look obscure or overly specific from the outside, but some of those details build the structures through which you understand everything else. The hard part is knowing which nuts and bolts are trivia and which ones change the shape of the whole system.
You become your tools
You become the tools you work with. Their syntax becomes the shape of your thoughts, and eventually you no longer translate every intention into a sequence of explicit technical decisions - you think in code.
A musician does not think, “I will now lower the third scale degree to create a minor quality.” He hears it. A good pianist does not calculate the distance between every key before moving his hand, because the keyboard has become ergonomic and incorporated into his body. This freedom does not come from ignoring technical details, but from passing through them so many times that they no longer stand between intention and action.
This is the path Robert Greene describes in Mastery: first there is apprenticeship, with its observation, repetition, boring fundamentals, and submission to the reality of the craft. Only later does knowledge become intuition, allowing the person to improvise and break rules without becoming arbitrary.
The same is true for programming languages, but it is also true for the particular systems in which we work.
Become the system
A great owner goes so deeply into the nuts and bolts of a system that it becomes part of the way he thinks. He knows its history, its architecture, its weak points, its failure modes, and its strange exceptions. Over time, he no longer has to reconstruct its entire model whenever something happens because its model already exists inside him, allowing him to recognize which details matter, trace failures across boundaries, and improvise within constraints.
This is a deeper meaning of ownership than responsibility for outcomes. Responsibility can be assigned on an organizational chart, while this kind of ownership has to be acquired through prolonged contact. The owner becomes capable of changing the system freely because he has first submitted himself to understanding it. His judgment begins to shape the system, while the system reshapes the way he thinks, until it becomes difficult to draw a clean boundary between the tool and the person operating it.
This is almost a spiritual relationship, but it has extremely practical consequences. The person who has become part of the system will usually be the person best equipped to understand what broke, where it broke, and why. More importantly, he can see what the system could become, because technical fluency gives him the same freedom that fluency gives an artist inside his medium.
Think in code
The danger is not that AI writes code - the danger is that we stop thinking in code. If our work moves entirely from JavaScript, Python, SQL, Git, Docker, and shell commands into English, then English becomes the only layer in which we can reason, and we gradually lose contact with how the system actually operates.
This does not mean writing everything by hand. AI is useful for repetition, boilerplate, refactors, documentation, and scaling an implementation once its shape is understood. But we should remain close enough to the machinery that we still think in functions, inputs, outputs, state, queries, data structures, files, diffs, and failure modes.
Syntax still matters, although concepts matter more. In the age of AI, an obsession with fundamentals becomes extremely valuable. You do not need to memorize every command or flag, but you must know which concepts exist and what kinds of problems they solve. Otherwise AI becomes mystification, producing solutions you approve only because they have been presented confidently.
Leket, Shichecha, and Pe’ah

I am going to slightly abuse three agricultural mitzvahs and turn them into rules for development.
-
Leket: Do not automate every small piece of work that falls in front of you. Small functions, scripts, bugs, and investigations may not be economically important, but they are where fluency is maintained. Occasionally picking them up yourself keeps the machinery in your hands.
-
Shichecha: Sometimes forget to use AI. Begin with the problem before opening the agent, even if only long enough to form your own model, draw the system on paper, or follow the first part of the stack trace.
-
Pe’ah: Leave a corner of the field for yourself. There should be some part of the system that you understand deeply enough to reproduce: one core path or module. You do not need to write the entire codebase by hand, but somewhere within it there should be a place where the machinery is genuinely yours.
This matters because the human-in-the-loop world is mostly passive. We supposedly approve, but most of the time we are reading, and completed work always appears easier to understand than it was to create.
Software engineering, insofar as it continues to deal with large and complex real-world problems, will need people who are deeply engaged with systems even when they did not write most of the code. They must be capable of tracing the machinery, understanding its constraints, and identifying the assumptions that hold it together. The goal should not be to preserve the motions of trad-coding after its economic value disappears, but to preserve the kind of mind that programming created: one that can enter a system, absorb its structure, and eventually move through it with freedom.