Back to blog

You Are the Bottleneck Now

Marius Horatau
Written by
Marius Horatau
Published on

AI can generate code faster than most developers can evaluate it. The risk isn't only bad output. It's losing the understanding you need to tell good code from plausible code.

You Are the Bottleneck Now

There was a time when the bottleneck in software was the computer.

Compilation took time. Deployments took time. Provisioning took time. A lot of that waiting was simply inefficient, but it also left room to read documentation, trace a stack, and stay with a bug until the system made sense.

That is no longer how much of the work feels. A coding agent can produce an implementation, an explanation, and two alternatives before I have finished reviewing the first diff. The limiting factor is often my ability to evaluate what it produced: to connect the change to the rest of the system, notice a broken assumption, and decide whether passing tests are actually testing the right thing.

The job is shifting from producing every solution yourself to directing and evaluating solutions produced elsewhere. That can be a real productivity gain. It also changes where the difficult thinking happens, and makes it easier to keep moving before you understand what you are shipping.

Working memory is limited

Working memory is the small amount of information we can actively hold and manipulate while reasoning. Nelson Cowan’s influential account puts the capacity-limited focus of attention at around four chunks under controlled conditions [1]. That is an estimate within a model, not a claim that the brain has four fixed slots. Capacity varies with the task, prior knowledge, rehearsal, and how effectively information can be grouped into meaningful chunks.

The practical constraint is familiar even if the exact number is not. Reviewing an AI-generated change can require you to keep track of:

These are not seven independent objects sitting in seven literal slots. They are competing demands on attention. The more unfamiliar the system is, the harder they are to compress into a useful mental model.

That model matters because code review is not pattern matching. A diff can look conventional and still violate an assumption elsewhere in the system. Tests can pass because the failure mode was never represented. An explanation can sound coherent while describing behaviour the code does not have.

When review capacity falls behind generation capacity, it is tempting to substitute signals for understanding: the diff looks tidy, the test suite is green, and the model sounds confident. None of those signals is useless. None proves that the change is correct.

Progress can outrun understanding

I find the prompt-response loop difficult to resist. I ask for a change, something appears, and I get an immediate sense of movement. If the first answer is not quite right, another prompt is cheaper than sitting with the uncertainty.

I do not have evidence that this is addiction in the clinical or neuroscientific sense. What I can observe is the habit it encourages in me: when progress arrives in small, frequent increments, a difficult problem with no immediate feedback starts to feel unusually slow. Reaching for another prompt can become the default even when the useful next step is to read the code or reproduce the failure myself.

The risk is not that prompting feels good. It is that the feeling of progress can arrive before the understanding that normally justifies it.

Not all friction is useful

Slow compilation is not inherently educational. Neither is memorising syntax or writing familiar scaffolding for the hundredth time. Removing that work can leave more attention for architecture, debugging, and product decisions.

The distinction I care about is between friction that consumes time and effort that builds a mental model. Reading an unfamiliar call path, forming a hypothesis about a failure, and testing that hypothesis are slower than accepting a generated patch. They are also how I learn what the system will do outside the happy path.

Early research supports concern here, but it does not justify saying that AI inevitably makes developers worse. In a small randomized study of 52 mostly junior software engineers learning an unfamiliar Python library, participants with AI assistance scored 17 percentage points lower on a later mastery test than participants who coded by hand [2]. The study used a constrained task and a sidebar assistant rather than an agentic coding workflow, so it should not be treated as a universal result. It also found an important difference within the AI group: participants who asked conceptual questions and used the tool to build comprehension retained more.

A separate CHI 2025 study surveyed 319 knowledge workers about 936 examples of AI-assisted work [3]. Higher confidence in the AI was associated with less self-reported critical-thinking effort, while higher confidence in the person’s own ability was associated with more. Because the study was based on self-reports, it cannot show that AI caused either outcome. It does show that verification does not happen automatically just because a human remains in the loop.

The evidence is still early and narrow. My conclusion is narrower too: AI use can reduce learning when it replaces the work that would have produced understanding. How you use the tool matters.

Cognitive debt

I think of the missing understanding as cognitive debt.

Technical debt leaves a codebase harder to change later. Cognitive debt leaves the developer or team without the mental model needed to change it safely. The feature can work, the pull request can merge, and the gap may remain invisible until the next change or production failure.

I felt this on a side project where I had used AI heavily to build an authentication flow: OAuth, session management, and token refresh. It shipped and worked. Months later, I needed to extend it and realized I could not hold the flow in my head. I was reading my own codebase as if I had inherited it, reconstructing decisions I had accepted without properly making them.

The problem was not that AI had written some of the code. The problem was that I had treated working output as evidence that I understood the system. When I returned to it, I could not predict how the flow would fail or identify which assumptions were load-bearing without doing the original learning late.

That is why the debt compounds. If you skip building the model for one change, the next related change is harder to evaluate. More of the new output looks plausible because there is less internal knowledge to compare it against. Eventually the team depends on the tool not only to produce changes, but to explain a system nobody present understands well.

Evaluation is engineering work

In The Illusion of Building, I argued that writing code was never the hardest part of software engineering. The harder work is understanding systems: how components interact, which assumptions are load-bearing, and how behaviour changes under pressure.

AI does not make that work optional. It moves more of it into planning, review, verification, and debugging. The CHI study found a similar shift in its participants’ accounts: critical thinking moved toward verifying information, integrating responses, and maintaining responsibility for the task.

That shift can be useful. An experienced developer can give an agent better constraints, reject a locally correct change that does not fit the system, and focus attention on the decisions with the highest cost of failure. Someone without the same context may produce code just as quickly while needing much longer to establish whether it is safe to ship.

This is especially important in security-sensitive code. An authentication change is not complete because the happy path works. You need to know which identity is trusted at each step, where authorization is enforced, how tokens expire and rotate, and what happens when requests arrive out of order. Generating the implementation does not remove the need to answer those questions.

How I manage the bottleneck

I still use AI heavily. I am not trying to preserve manual work for its own sake. I am trying to keep the parts of the work that update my understanding.

These are the practices I use:

Choose the mode before prompting. If the code is familiar and repetitive, I am comfortable delegating the implementation. If I am learning a system or changing a security boundary, I ask for explanations, alternatives, and questions before I ask for a complete patch. The goal changes from producing code to building enough context to judge the code.

Review the reasoning, not only the diff. Before accepting a change, I make sure I can state what behaviour changed, which assumption makes the solution valid, and how the tests would fail if that assumption were wrong. If I cannot answer those questions, the green test suite is not enough.

Start debugging from evidence. I reproduce the failure, inspect the relevant state, and write down a hypothesis before asking the model to fix it. AI can help test that hypothesis or identify paths I missed, but I do not want its first explanation to become my observation.

Limit parallel work to what I can review. Five agents completing five related changes at once do not create five times the useful progress if I can only evaluate one carefully. I pause or sequence work when the review queue starts turning into a skim queue.

Leave a record of the understanding. For unfamiliar or high-consequence changes, I record the decision, its main assumption, and the evidence that supports it. A short note or focused test is more durable than a chat transcript and gives the next person something concrete to challenge.

These checks cost time, but they are not a retreat from AI-assisted development. They are the work that makes delegation safe.

AI can produce more code than I can evaluate. That makes my attention a real bottleneck, but not one I should try to remove completely. Some work needs my attention because accountability, system context, and judgment have not been delegated with the typing.

The goal is not to prove that I can work without AI. It is to make sure I can still explain, change, and debug what I ship.

Next up

The Illusion of Building

AI makes it dramatically cheaper to produce software that appears to work. But 'building an app' and 'engineering a system' are two different activities that people keep confusing, and the gap between them is where most of the actual work lives.

© 2026 Uphack.io ✦ Theme inspired by Aria

RSS Theme