WTF does code quality mean when humans stop reading the code?
I have been using AI to write code since GPT and Claude 3.5 Sonnet made it useful enough for real work.
For a long time, I used it as a copilot. I wrote the code, made the decisions, and asked the model to complete functions, explain unfamiliar parts, or help when I got stuck.
Around November 2025, that changed.
I started delegating entire tasks. Describe the outcome, let the agent inspect the codebase, review the plan, then watch it build. Our whole team moved in roughly the same direction. We were vibe coding more than using AI as autocomplete.
The effect on throughput – obviously – was immediate.
We went from an average of 10 merged pull requests per developer per month to 24. It felt like the models had reached a point where writing code by hand no longer made much sense.
Looking back, I think I was half right.
Opus 4.5 was an inflection point for me, and probably for a large part of the market. The quality of generated code improved a lot. Models could understand larger codebases, follow existing patterns, and complete tasks that would have required much more supervision a few months earlier.
They got good enough to make the code run. We mistook that for software that was ready to ship.
LLMs write software like extremely confident junior developers
I mean the behavior more than the technical ability.
When I started programming, I wanted to put my ideas online. Security, bugs, and maintainability felt like problems for later. Getting the thing to work was enough.
Then I discovered Clean Code, SOLID, design patterns, and all the usual books. I learned the vocabulary. I could explain why code should have clear boundaries and why abstractions should make future changes easier.
Applying any of that to a real codebase was much harder.

I knew what good engineering was supposed to look like, but I lacked the experience to recognize when each idea mattered. Sometimes I ignored patterns that would have helped. Other times, I applied every pattern I knew to a problem that needed two functions and a database column.
I call that version of myself the confident junior.
Current coding models behave in a similar way. They know the patterns and can produce a clean implementation. They also produce that implementation with the same confidence when the requirement is wrong, the architecture makes no sense, or the task should never have existed.
The output looks finished. The uncertainty that produced it is hidden.
If you leave the entire software development process to the model, with no automatic checks or human validation, you have effectively handed the product to a developer who writes code very quickly, sounds certain about every decision, and will never be on call for the result.
That can work surprisingly well on personal projects. Most of mine had no real users, so the consequences were small. Production software with thousands of weekly users gives you much less room to be casually wrong.
Code that runs is a very low bar
A model receives a task and tries to close it. That behavior is useful, but closing the task and solving the right problem are different things.
Imagine asking an agent to add two-factor authentication.
A simple implementation might be enough for the current product. The model can easily return multiple classes, interchangeable providers, strategy patterns, configuration layers, and extension points for use cases that nobody has requested.
The pull request may look impressive. The tests pass. The architecture is easy to defend because every abstraction has a familiar name.
You still end up maintaining a system designed for an imaginary future.
Models are very good at solving requirements that exist inside the prompt. Software quality often depends on information outside it.
A billing rule may live in an old migration. A customer exception may only be understood by the person who handled the incident two years ago. A function that looks unused may support a workflow in another service. The codebase contains some of this context, but much of it lives in decisions, incidents, and knowledge spread across the team.
The model cannot investigate a risk it has no reason to suspect.
Experienced engineers do this constantly. They know which innocent-looking changes tend to break production. They ask why a strange condition exists before deleting it. They recognize that a request has been translated into the wrong technical solution.
That judgment rarely appears in a prompt.
Does maintainability still matter if agents maintain the code?
Once we stopped reading most of the code we shipped, I started asking myself a slightly uncomfortable question: did code quality die?
A large part of maintainability used to be associated with human readability. We wanted the next developer to understand the code without spending three days reconstructing every decision behind it.
But what if the next developer is an agent?
If a bug appears, I can ask the agent to investigate it. If a feature needs to change, the agent can read the repository, find the relevant code, and write the patch. Maybe ugly code no longer matters as much when humans are no longer doing most of the reading.
For a while, I thought that might be true.
Then we started having quality problems.
We were shipping much more code, and parts of the system became difficult to understand and debug. Using agents did not remove that difficulty. The agents struggled with the same areas we did.
Our first response was obvious: add more tests.
That helped a lot. But it also exposed another issue. The code was coupled and duplicated, which made isolated tests difficult to write. We could test a user flow, but testing the behavior of individual parts required either large setups or heavy mocking. Even with more tests, some bugs continued to escape.
I suspect this is part of the reason E2E testing has become such a large part of the AI coding conversation. When the internal structure becomes difficult to trust, testing the behavior visible to the user feels like the safest option.
E2E tests can tell you that something broke. They usually give the agent much less help in understanding where or why it broke.
Duplication made the situation worse.
LLMs duplicate code without shame. If copying an existing block is the fastest way to complete a local task, they will often do it. One implementation becomes two, then each copy changes in a slightly different way.

The next agent has to decide which version contains the real business rule. Sometimes it fixes one copy and leaves the others untouched. The code still passes the immediate test while the system becomes harder to reason about.
We eventually found bugs that the agents could not debug reliably. The result changed between runs, the behavior crossed several coupled modules, and no single part of the system clearly owned it. The agent would fix one symptom, run the code again, and receive a different signal.
In some cases, it was struggling with a structure another agent had created.
That experience changed my understanding of maintainability.
Readability helps humans reduce uncertainty. Agents need structure for a similar reason. They work better when behavior has a clear owner, dependencies are explicit, results are deterministic, and failures can be observed close to their source.
Technical debt still makes sense under this definition.
A shortcut becomes debt when it makes a future change harder to understand or verify. The cost may appear as developer hours. It may also appear as repeated agent runs, larger context requirements, incorrect patches, or a human eventually stepping in because the agent can no longer tell which behavior is intentional.
I still do not know whether the old practices are the complete answer.
Some conventions were built around human cognitive limits and may become less valuable. Other practices describe properties that help any system reason about code. Low coupling, explicit boundaries, testability, deterministic behavior, and a single source of truth still seem to matter when an LLM is doing the maintenance.
My current definition is incomplete, but it is closer to what we have experienced:
Code quality is how easily humans and agents can build justified confidence in what the software does and change it without introducing behavior they do not understand.
AI makes specification and validation more valuable
As implementation gets cheaper, more engineering work moves into deciding what should be built and proving that the result is safe to ship.
This has changed how I work with coding agents.
I ask them to state their assumptions before making larger changes. I prefer the smallest implementation that solves the known requirement. New abstractions need a current use case, rather than a possible one.
I also want deterministic systems checking nondeterministic output. Type checks, automated tests, security scans, and company-specific rules should catch as much as they reasonably can before a human reads the diff.
Human review then has a clearer job. The reviewer can focus on business context, hidden dependencies, and the cost of owning the change later. These are areas where a model working from a local task has the least information.
The metrics need the same adjustment.
Merged pull requests tell us how much code entered the system. They do not tell us whether we delivered twice as much value. We also need to look at review time, rework, escaped defects, rollbacks, and how often a “finished” task returns a week later.
I am still vibe coding. Going back to writing every line by hand would make little sense. The models are too useful, and they keep getting better.
I have stopped treating code generation as the whole engineering job.
Better models produce plausible code faster and in larger amounts. That increases the value of validation. Someone still has to decide whether the code deserves to exist and whether the team is willing to own its consequences.
AI changed who reads and writes most of our code. The properties that make software understandable and safe to change still matter. We are still figuring out which old practices survive, but the problems they were trying to solve are still here.