跳至內容

To Read or Not to Read Code? The Dilemma in the Age of Vibe Engineering

Vibe engineering is a development methodology where humans define intent, constraints, and verification loops, leaving coding agents to execute bulk implementations. The new dilemma it brings is: when AI generates code far faster than humans can read it, how much code do we still need to review in order to remain responsible for the delivered outcome?

When I saw recent posts by Uncle Bob (Robert C. Martin), author of Clean Code, my immediate reaction was: "Wait, even the master of clean code is telling us not to read code?" The headline was certainly catchy. But after reading through the entire thread and background context, I realized the real challenge lies elsewhere: rather than agonizing over a binary dogma of "to read or not to read," the real question is—what evidence are we prepared to use to replace human eyes?


When the Author of Clean Code Says He Doesn't Read Code

The spark occurred in July 2026, when Uncle Bob wrote a reply under Ori Pomerantz's post on X. He mentioned that he now deliberately avoids reading implementation code written by coding agents, because manually checking line by line completely cancels out the productivity gains brought by the agent.

Ori Pomerantz posted on X expressing hesitation about letting Claude edit files directly, stating 'Since I am responsible for the code, I must understand it,' and sharing his entry year into tech as 1983; Uncle Bob replied below stating he started coding in the late 1960s—far senior—and his current strategy is to not read agent-written code at all, relying instead on unit tests, Gherkin tests, QA procedures, quality metrics, and mutation testing to constrain the agent.

As a side note, the two veterans opened by comparing their years in the industry: one mentioned starting in 1983 and asked if that made him old, while the other pulled out credentials from the late 1960s to top him. (Hilarious. That interaction alone was worth screenshotting.)

Hearing this from a master who advocated code purity for decades had instant dramatic impact. But if you stop reading here and throw your copy of Clean Code out the window, you have fallen for clickbait. In the exact same reply, he emphasized that he dares not to read code because he built an extremely strict series of checkpoints around the agent: unit tests, Gherkin acceptance tests, QA procedures, coverage and complexity metrics, and even mutation testing. He described this process of letting the agent iteratively correct itself until passing all checks as to run the gauntlet.

He elaborated in subsequent follow-ups that even the unit tests and QA procedures themselves are generated by agents. He does not review unit tests, but he samples or fully inspects Gherkin specs and QA procedures depending on task criticality, while regularly conducting manual testing himself. (Note: As some follow-up replies are not easily linkable directly on X, these details are cross-referenced and interpreted from ExplainX's summary and Rapha Moura's article.)

In fact, as early as April 2026, Uncle Bob made a similar declaration responding to a question from the Wookash Podcast. Back then, he wrote directly: "Humans are slow at code," arguing that humans in the AI era should shift toward higher-level management, focusing on test coverage, module coupling, cyclomatic complexity, and mutation scores.

Notice the difference? Uncle Bob hasn't abandoned quality. What he is doing is converting checks previously handled by human eyes into mechanical, automated constraints.

However, is putting all our faith in automated test gauntlets truly bulletproof? Before we rush to throw traditional code reviews into the bin, we need to clarify a few terms commonly used in these discussions.

Disentangling Vibe Coding, Agentic Programming, and Vibe Engineering

Whenever people talk about writing code with AI, many throw around the label "vibe coding" indiscriminately. But lumping all AI-assisted development into one bucket causes technical discussions to quickly devolve into talking past each other.

The first term is Vibe Coding. Andrej Karpathy introduced this concept in February 2025. He described a state of completely "forgetting that code exists"—hitting Accept All, ignoring diffs, copying error messages back into the model, and letting AI make random edits until the code runs. Karpathy explicitly clarified that this extreme hands-off style is best suited for weekend throwaway projects where breaking things doesn't matter.

The second term is Agentic Programming. Martin Fowler introduced this distinction in his column. He observed that in agentic programming, while humans no longer type most of the code, engineers still care deeply about system architecture and code quality. Humans shift from typists to supervisors, continuing to inspect code reviews, test results, and monitoring metrics.

The third term is Vibe Engineering. Simon Willison coined the term vibe engineering in October 2025 to fill the professional gap on the other end of vibe coding. He emphasized that senior engineers using LLMs at high velocity remain fully accountable for production software. This includes automated testing, upfront planning, documentation, version control, preview environments, and code review. Willison also acknowledged in a 2026 update that Agentic Engineering might become the more common term in the future.

To use a food delivery analogy: vibe coding is like ordering food based purely on photos without caring how the kitchen runs; agentic programming checks the restaurant's hygiene ratings and ingredient lists; while vibe engineering establishes end-to-end food safety testing, workflow controls, and retains the ability to trace origins and compensate customers if food poisoning occurs.

In this article, vibe engineering carries a specific working definition: human engineers primarily define intent, boundaries, risks, and verification loops, letting agents execute bulk implementation; humans then determine code review depth based on the strength of available evidence.

Human engineers feed intent, boundaries, risk parameters, and verification loops into an agent implementation engine, which outputs code in bulk; verification results flow back along feedback loops as evidence to the engineer, while a dashboard on the right shows that stronger evidence allows code review to be more focused, while weaker evidence demands deeper inspection across more code layers.

Here comes the core question: since we remain accountable for production, why is the traditional defense line of "line-by-line code review" beginning to falter?

Why We Used to Read Code

Think back to why teams mandated Code Reviews before AI became ubiquitous.

Many assume code reviews exist solely to "catch bugs," but that is only a small fraction of their purpose. Traditional code review operated as a multi-functional team health mechanism, fulfilling five distinct roles:

  1. Correctness and Security: Uncovering logical flaws, missed edge cases, memory leaks, and potential security vulnerabilities.
  2. Architecture and Maintainability: Checking module coupling, naming clarity, and readability for future maintainers.
  3. Shared Mental Model: Keeping team members aware of recent changes and maintaining collective familiarity with the codebase.
  4. Knowledge Transfer and Mentoring: Senior engineers passing down domain experience through comments; junior engineers learning team practices by reading.
  5. Accountability and Decision Log: Leaving a trace in version history proving that a change was thought through and approved by another human.

It resembles airport security. The X-ray scanner (automated testing) quickly detects contraband metal, but security officers on site are still required to verify identity, handle exceptions, evaluate suspicious behavior, and assume final accountability.

Automated testing primarily provides evidence that "behavior is correct." It cannot automatically inherit social functions such as knowledge transfer, architectural aesthetics, and team alignment. The renowned computer scientist Grady Booch pointed out in a discussion regarding Uncle Bob that while metrics like test coverage increase confidence in functionality, they cannot alone rule out security flaws, dead code, loss of future readability, or improper architectural decomposition.

If code review serves so many vital functions, why is everyone urgently searching for alternatives today?

Why Line-by-Line Code Review Is Breaking Down

The reality is simple: the speed of AI code generation has completely overwhelmed the reading bandwidth of the human brain.

Imagine a factory conveyor belt speed suddenly accelerating ten-fold while quality inspectors still have only two eyes. What happens next?

When an agent produces thousands of lines of changes in seconds, the traditional pull request and asynchronous code review workflow immediately becomes the bottleneck of the entire development cycle. Thoughtworks observed in their series on code quality in the AI era that waves of AI-generated changes are plunging traditional PR reviews into severe review fatigue.

Faced with massive diffs, do human engineers read more carefully? In practice, mental exhaustion leads to rapid page scrolling, ending with a superficial "LGTM" click.

This "pretend review" is far more dangerous than openly admitting "I didn't read the implementation, but I trust the tests." It creates a false sense of control, giving the impression that someone is guarding the door when people are merely going through the motions.

This is precisely the dilemma Uncle Bob tries to solve: rather than letting humans perform degraded, fake reviews while exhausted, it is better to shift attention away from implementation details and build an extremely rigorous automated test gauntlet instead.

Where Uncle Bob Shifts the Trust

So what exactly comprises the Test Gauntlet that Uncle Bob claims can replace human eyes? Let's break down each gate, looking at what evidence it provides and where its blind spots lie:

AI-generated code moves along a conveyor belt through six automated verification gates—Unit, Gherkin, QA, Coverage, Mutation, and Metrics—before reaching the merge entry; business intent, boundary cases, weak assertions, performance/concurrency, and domain abstractions remain outside the beam of light as warning silhouettes, symbolizing that test gauntlets provide tiered evidence but cannot illuminate every blind spot.

Gate / ToolPrimary Question AnsweredWhat It Cannot Answer Alone
Unit testsDoes small-unit behavior match expected test cases?Is the overall business requirement correctly understood?
Gherkin testsDoes high-level observable behavior match spec statements?Did the spec miss critical corner or edge cases?
QA / Manual testDoes actual operational flow and UX match expectations?Long-tail anomalies and non-functional risks.
Test CoverageWhich code branches were executed during testing?Do test assertions actually verify correctness effectively?
Mutation testingCan the test suite catch deliberately injected code mutations?Performance degradation, memory leaks, and concurrency issues.
Metrics CheckAre cyclomatic complexity, module size, and dependencies within limits?Does the architectural abstraction fit the domain model?

The value of this approach is immense: it shifts expectations of AI from "hoping the agent writes code carefully" to "disallowing any merge until passing mechanical verification."

However, when we transfer all our trust to this test gauntlet, the most treacherous question of all emerges.

The Hardest Problem: When the Agent Acts as Both Player and Referee

If your unit tests, Gherkin specs, and even QA procedures are all automatically generated by the exact same AI agent, you run straight into software engineering's classic Oracle Problem: who verifies the verifier?

In plain terms, the player is acting as the referee. It is like a student writing their own exam, answering it themselves, and then grading it using their own answer key.

How does this setup fail in practice? There are three common failure modes.

The most frequent: the original requirements contain ambiguities. The agent misinterprets your intent while writing implementation, and naturally carries the exact same misunderstanding when generating tests. The implementation is wrong, the test is wrong, and when they run against each other, every light turns green. This is called Correlated Failure, and it is the hardest of the three to catch via post-hoc checks.

The second drama is familiar to anyone in corporate KPI culture: where there is a metric, there is gaming. When "90% coverage" becomes a hard gate for the agent, the LLM will happily produce tests that execute every line while carrying assertions so weak they check virtually nothing. Numbers look pristine, while actual protection approaches zero—a textbook demonstration of Goodhart's Law.

The last mode is more subtle. Models tend to be overly optimistic when evaluating their own output. Logic blind spots missed during code generation remain invisible during test generation. This is Self-grading Bias.

Therefore, verification independence actually exists on a spectrum. From least reliable to most reliable: Agent Self-grading < Context-isolated Reviewer Agent < Deterministic Tools (Linters/Compiler) < Domain Experts / Real Production Feedback

When tests and implementation originate from the same source, risk does not magically vanish—it merely shifts covertly from "the code was written wrong" to "the tests were also written wrong."

How do we break out of this black-and-white dilemma?

Code Review Isn't Binary: Attention Is a Funnel

Many discussions compress the debate into "reading code is reactionary, not reading code is progressive." But this false dichotomy crumbles in real-world software engineering.

I prefer to model review attention as a funnel: every change enters at the top, but not every change deserves to sink all the way to the bottom.

Paper collage and woodcut style illustration: A giant funnel constructed from torn paper edges and carved block lines, receiving floating paper sheets representing code changes at its widest opening, filtered through progressively narrowing screens where fewer sheets remain; only a few sheets reach the narrow bottom where a hand holds a magnifying glass to read line by line. Free of small table text, robots, neon glows, or circuit board patterns.

The widest top opening catches all incoming changes. At this layer, humans inspect only functional demos, log observability, and rollback mechanisms—skipping implementation reading entirely and delegating coarse guarding to automated gauntlets. Down one level, we sample test suites: inspecting Gherkin specs and test case completeness to ensure coverage targets meaningful behavior. Further down, contract layers are examined: Public APIs, database schema migrations, and module boundaries, while internal function implementations remain untouched.

As the funnel narrows deeper, fewer changes reach these levels. High-risk paths—trust boundaries, authentication, financial transactions, and complex algorithms—warrant line-by-line human inspection. The narrowest exit at the very bottom represents traditional code review: word-by-word diff auditing for syntax, style, and fine details. Human attention becomes exponentially expensive further down, so changes reaching the bottom should naturally be a small minority.

In the middle of the funnel sits an exception-driven valve: keep changes at upper levels by default, and escalate to deeper manual review only when automated gates report errors or when multiple agents produce conflicting conclusions.

Teams don't need to declare allegiance to either "code readers" or "non-code readers." Mature vibe engineering is about deciding which funnel layer a change belongs to based on its specific characteristics.

When to Read Less, and When to Read Deeply

How do we decide which layer of the funnel a pull request should sink to in daily development?

I suggest teams evaluate risk across four dimensions:

  • Blast Radius: Who is affected if it breaks? Internal developer tooling or the company's primary database?
  • Observability: Is failure easy to spot? Broken UI layouts are instantly obvious, whereas silent data corruption or race conditions are notoriously elusive.
  • Reversibility: How easy is recovery? Can it be toggled off immediately via a feature flag, or does it require an irreversible database migration?
  • Verification Independence: Were tests and specs written by domain experts, or generated from AI templates?

An engineer operating a review depth elevator based on four risk dimensions: Blast Radius, Observability, Reversibility, and Verification Independence: low-risk changes stop at surface-level Outcome-first (verifying results and rollback mechanisms); medium-risk enters Selective Review (sampling interfaces, data flow, and high-risk joins with a magnifying glass); high-risk descends underground into Deep Review (inspecting auth, payments, permissions, database migrations, and structural contracts line by line).

Based on these four axes, we can map development scenarios into a three-tiered intervention guide:

Review TierApplicable ScenariosPrimary Focus for Human EngineersUpgrade Trigger for Deep Review
Green: Outcome-first (Minimal reading)Throwaway scripts, quick prototypes, low-risk internal admin UI, minor CSS tweaks.Spec requirements, interactive demo, basic test status.Failing test status, agent fix loops, unexpected expansion of change scope.
Yellow: Selective Review (Sampled checks)Standard product features, refactoring existing modules, well-tested business logic.API contracts, data flow, high-risk diff branches.Introducing new third-party dependencies, DB schema alterations, performance degradation.
Red: Deep Review (Mandatory line-by-line)Authentication, financial transactions, access control, data migration, security boundaries.Line-by-line code, threat models, architectural design.Strictly forbidden to downgrade unless supported by long-term production evidence.

The core philosophy of this matrix is clear: Code review is a risk control tool; treating it as a test of professional ethics misses the point entirely.

When changes fall in the green tier, empowering automated gauntlets unlocks immense productivity; but when changes enter the red tier, mindlessly clicking Accept All is simply planting landmines for your future self.

The Engineer's New Role: Managing Evidence and Maintaining Understanding

When we delegate heavy typing and line-by-line auditing, do engineers become obsolete?

Quite the contrary. The engineer's role is evolving from "code producer" to "boundary definer and evidence manager."

This evolution elevates a crucial new capability: Context Engineering.

Thariq Shihipar of the Claude Code team shared a fascinating observation in July 2026. When testing newer model generations, they removed over 80% of system prompts in Claude Code, yet coding evaluation benchmark scores did not drop at all.

Anthropic explained the underlying reason in a technical post: excessive prompts, repetitive rules, and overly detailed examples cause "overconstraint," forcing LLMs to waste attention determining which rule to follow. A superior approach provides clean tool interfaces, progressive disclosure, and explicit verification loops.

This finding carries a profound lesson: the engineer's new job is designing clean, powerful test harnesses. We must translate subtle business intent into specifications, bake impassable boundaries into execution environments, and trigger test and evaluation tools at the right moments.

At the same time, we must remain vigilant against a new form of technical debt: Cognitive Debt.

If a team goes long periods without any human reading or understanding the system's internal implementation, short-term feature delivery may continue, but collective mastery over the system will rapidly decay. When production outages strike or models get stuck in unresolvable logic loops, nobody will know how the underlying code actually works.

Upgrading from typist to supervisor sounds empowering, but a supervisor who cannot read blueprints and only watches progress lights won't automatically become an architect.

Shifting Review Upstream Before Work Begins: sdd-workflow

Having discussed the theory at length, I should lay my own implementation on the table.

I recently developed sdd-workflow specifically because I noticed AI agents were far too eager to rush out and modify dozens of files before I had fully clarified my intent.

The core logic of sdd-workflow (Spec-Driven Development) shifts human attention from "reading thousands of diff lines post-hoc" to "upfront review and phased authorization." Before touching any code, the agent must draft a Proposal covering problem definitions, change scopes, and acceptance criteria. Until a human reads and approves this proposal, the agent possesses zero permission to modify implementation files. Once implementation begins, it executes only one approved task at a time, updating status and evidence after every step.

The workflow also enforces strict boundaries on requirement changes: if requirements evolve during development, the agent is forced back into proposal revision and re-approval, preventing it from sneaking new demands into old authorizations. If state or evidence becomes ambiguous, the tool fails closed—automatically halting and handing control back to the human decision-maker.

sdd-workflow flowchart: Upon a requirement appearing, the agent drafts a proposal containing problem definition, change scope, and acceptance criteria; only after explicit human approval can implementation begin, and any modification requires returning to proposal revision for re-approval. During implementation, only one approved task is executed at a time while updating status and evidence; requirement changes trigger a mandatory re-approval flow, while ambiguous state or evidence causes a fail-closed stop handing control back to human decision-makers; upon task completion and passing human acceptance, the workflow archives.

The creation of this article itself was a self-referential case study:

I first had the Agent draft a proposal outline for this post, agreeing on argument structure, Uncle Bob's claim verifications, and risk table design before authorizing it to gather research and draft the text.

However, I must be completely honest: sdd-workflow addresses control flow, permissions, and evidence discipline; it cannot serve as a standalone proof of code correctness. No matter how well a proposal is written, the underlying business logic can still contain flaws. It provides a procedural skeleton that clarifies when to pause, what evidence to inspect, and who authorizes progress.

It does not solve every code correctness problem, but it ensures that "not reading line by line" no longer means "blindsided blind trust."

Conclusion: Place Rigor Where It Builds the Most Confidence

Returning to our starting question: in the age of Vibe Engineering, do engineers still need to read code?

My answer is: reading or not reading code should never be a permanent dogmatic stance, but a risk decision to be re-evaluated for every change.

When requirements are clear, evaluation tools are independent, outcomes are easily observable, and rollbacks take seconds, feel free to aggressively reduce line-by-line reading and dedicate energy to creative architecture. But when entering high-risk territory—security, financial transactions, personal data, or anything with catastrophic failure costs—the implementation must still be laid bare for deep review.

AI has made code production extraordinarily cheap, but engineering confidence has not dropped in price.

When we choose to read less code, we had better make sure we have built a trustworthy Gauntlet—and know exactly when to stop and read every single line when any gate fails.

💬 留言討論

Released under the MIT License.