Tech Debt Disguised as Best Practices
The most expensive code your agents write is clean, tested, documented and unnecessary. A working 2026 protocol for finding what to remove, before it hardens into architecture.
Agent code review is very good at inspecting what exists.
It catches null dereferences, races, incomplete error handling, suspicious control flow, missing tests, style violations, and patterns applied incorrectly. Give it a factory and it will inspect the factory thoroughly. What it rarely asks is whether the factory should exist at all.
That is not a small gap. It splits review into two different activities, and the tooling is overwhelmingly pointed at the first one.
Diff review privileges local evidence. Strategy needs counterfactuals: what if we did not build this? What is the smallest behaviour that satisfies the actual requirement? Which future are we paying for, and how likely is it? A reviewer that sees only the patch cannot answer those. A reviewer that sees the whole repository but no product context usually cannot either.
The dangerous output is not messy code
An ambiguous task goes in. What comes out is an interface, two adapters, a configurable policy, a plugin point, a retry harness, structured errors, telemetry hooks, and tests for every permutation. Everything is named well. Everything is documented. The suite is green.
The product needed one function.
It is harder to fight than ordinary debt, because every individual decision has a respectable justification. The interface improves testability. The config preserves flexibility. The retries improve resilience. The abstraction follows dependency inversion.
Review each choice on its own and the system wins every argument. Review the total and the design is absurd.
Which makes "best practices" the actual attack surface. A general coding model has seen thousands of examples where extensibility, configurability, abstraction and defensive handling were praised. It has not attended your planning meetings. It does not know the feature is an experiment, that only one backend will ever exist, or that this team values easy deletion over generality.
It is a context failure, not an intelligence failure
This is the part most people get backwards. More capable models do not automatically fix it — and under the wrong objective they make it worse. Ask for "production-ready code" and give a strong model more thinking time, and you get a more elaborate structure with a better defence prepared for it. The reasoning is not wrong. The objective is. Greater capability does not supply missing product context.
So the scarce engineering skill in 2026 is not generation. It is subtraction. And almost every tool we have points the other way — reviewers suggest additions, linters demand handling, coverage tools demand tests. As Saint-Exupéry put it:
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
What follows is the working 2026 toolkit for the taking-away half. Some of it is tooling, most of it is process, and none of it removes the human from the decision. I have written before about keeping the workflow itself simple and about review being automated while the decision is not — this is the sharper version of both.
1. Separate the reasoning from the editing
Aider's architect/editor mode splits one request across two models. The architect reasons about the problem and emits natural-language instructions. A separate editor model takes those instructions and produces the actual diff.
In its September 2024 architect-mode post, Aider reported that o1-preview as architect, paired with either DeepSeek or o1-mini as editor, reached 85% on its code-editing benchmark — a high on that benchmark at that time, with models that are now several generations old. Do not read it as an enduring leaderboard result. Read it as evidence that the split itself helps: each model got the job it was better at, open-ended problem solving on one side and reliable repository editing on the other.
The same shape now shows up everywhere as plan mode, ask-then-code, and hand-rolled two-model pipelines. Ask for a plan with edits disabled, review the strategy, then hand the accepted plan to an editing model and review the diff against it.
The value for our problem is the seam. It creates a moment where the strategy can be challenged before any code exists to make it feel inevitable, and it leaves behind an artifact that says what you meant to build.
Its limit matters just as much. Architect mode improves the translation from reasoning to edits. It does not give the architect taste. An architect model will happily propose four layers where one would do, and a good editor will implement that mistake beautifully. Treat the boundary as a review gate, not as evidence that architectural judgment has been automated. The related pattern of running two models over one branch is the review-side version of the same idea.
2. Switch phases on purpose, and change who is asking
Early implementation should be loose. Build enough to find the shape of the problem. Call the real API. Let awkward facts kill the clean design you imagined before contact with the code.
Then switch. The exploratory question is "can we make this work?" The subtractive question is "now that it works, what did we learn that lets us remove things?"
Do not ask the same agent to make that switch in the same session. Models are conditioned by the conversation they have already produced — earlier choices become assumed premises, and a review request produces local repairs that preserve them. It looks like the model is defending its work. Really, contextual consistency rewards justification over repudiation.
So: fresh context, and where practical an independent reviewer — a different model family diversifies the critique, though it does not make it wiser by default. Give it the requirement plus the code plus repository context, but not the authoring conversation. Then frame it adversarially rather than neutrally.
Assume this implementation is overbuilt. Identify behaviour, abstractions, configuration and failure handling that can be removed while still satisfying the stated acceptance criteria. For each removal, state what behaviour is retained, what interfaces disappear, and what risk it creates.
Demand concrete deletion proposals, not an essay about simplicity. A different model is not automatically wiser — its value is independence from the path that produced the code.
3. Invert the interview
Matt Pocock's /grill-me skill is the cleanest implementation I have found of a less common technique: stop prompting the agent for answers and make the agent interrogate you.
It interviews you in rounds, and the definition of a round is the good part — not an arbitrary batch, but the complete frontier of questions whose prerequisites you have already settled. Your answers unlock the next frontier. A published example ran roughly four rounds and 46 questions. It carries its state in the conversation and writes no files; what you keep is a clarified idea rather than an artifact.
It also does something I have not seen packaged elsewhere: it identifies ungrillable questions — decisions that discussion cannot settle because they need a prototype, a measurement, or contact with reality — and stops asking about them. Architecture arguments routinely disguise empirical uncertainty as opinion, and naming that category kills a lot of circular debate.
Why inverting the direction surfaces redundancy: forward prompting smuggles the solution into the request. "Build a configurable ingestion framework" already contains the framework. An interview instead asks how many sources exist today, which second one is actually committed, what differs between them, what has to be configurable without a deploy, and what it would cost to add the abstraction later.
Answers of "one", "none" and "about an hour" remove the justification for most of the design — and they are answers only you can give.
4. Use multiple lenses, and add the one nobody ships
A single reviewer asked to check correctness, security, performance, maintainability, testing, API design and simplicity will not distribute attention evenly. High-signal local defects crowd out strategic objections every time.
Qodo's PR review, per its February 2026 release, is described as running four specialised agents in parallel and then synthesising their findings. Whatever the product details, the shape is the point: specialisation gives each reviewer a narrow objective, so no concern disappears inside a generic prompt.
The lens missing from every product I know of is subtraction. I have not found a review product that ships subtraction as a first-class lens with its own mandate to propose deletions.
Constrain the subtraction reviewer: it may propose consolidation, inlining, deletion or postponement, and every proposal must tie to acceptance criteria and name the evidence that would make the complexity necessary later.
And when you synthesise, preserve the disagreement. If the correctness lens wants another recovery path and the subtraction lens wants the whole retry subsystem deleted, collapsing both into "improve error handling" throws away the only genuinely useful output of the review. That conflict is the decision. Give it to a human. My third-pass review structure exists for exactly this reason.
5. Retrieval is the actual review engine
Architectural review quality is won or lost before inference starts. A reviewer needs more than the changed lines:
Note this is not "put the whole repo in the context window" — more context often obscures the decision. The goal is the smallest evidence package capable of challenging the design. The history row is the one people skip and the one that pays: a new abstraction looks reasonable right up until the reviewer can see that its twin was deleted recently. I wrote about hitting the limits of this in the harness, loop and graph vocabulary.
Without called definitions, tests, history and the design artifact, a request for "deep architectural review" is badly under-informed. The model has nothing to be deep about.
6. Render the architecture so a human can object to it
The agent does not have to make the architectural decision to improve it. It can make the structure visible.
Generate dependency graphs, call graphs, module maps and diagrams from the code the PR touches. Show before and after. Highlight new nodes, new edges, cycles, new public interfaces, new background processes, new configuration sources, new external dependencies.
Because a human can object to a picture in ten seconds — why does this feature cross five modules, why did one dependency become six, why is a leaf package now a hub, why are there three configuration paths, why does deleting this feature require touching an unrelated service. That reaction is valuable precisely because it arrives before the detailed defence of every class.
Keep the diagrams disposable and reproducible. A hand-maintained architecture diagram is just another stale artifact. The model can render the structure and challenge it. The accountable reviewer decides whether its cost is justified.
7. Make the design reviewable before the diff exists
A diff is a terrible representation of intent. By the time anyone sees it the design has already accumulated implementation weight. Write a small artifact first — a spec, a PRD, or an architecture decision record — stating the required outcome, the explicit non-goals, the constraints, the expected scale and lifetime, acceptable failure behaviour, alternatives considered, why the chosen option is the smallest adequate one, and what would have to become true to justify more complexity later.
There is a specific reason to keep writing them now: an agent will treat an undocumented constraint as an accident. A weird-looking guard with no stated reason is exactly what a cleanup pass removes. Writing the why down somewhere durable has become a defensive measure rather than documentation hygiene — with the obvious caveat that it only helps if the record actually makes it into the agent's review context.
Then review in two passes: the design against product reality, and the implementation against the accepted design. When the code introduces a plugin interface the design never mentioned, that is visible scope expansion rather than a judgment call. When the spec says "single provider for this experiment", a multi-provider abstraction now carries the burden of proof. This is the mechanic behind spec-driven agentic development and the architect's protocol.
Specs can also rationalise overbuilding. The cure is not a longer spec — it is strong non-goals and explicit deletion criteria.
8. Put complexity on a budget
Numbers cannot identify bad architecture. They can force the conversation before complexity becomes ambient.
The tooling is unglamorous and real: ESLint's complexity rule, Radon or Xenon for Python, Knip for unused JavaScript/TypeScript files, exports and dependencies, dependency-cruiser for JS/TS module rules or ArchUnit for Java architecture tests, Size Limit for frontend bytes. The dead-code lane is worth taking seriously — a JSNation 2026 talk described a production cleanup that removed 28,000 lines, with Knip doing the identifying and people doing the verifying. Start in report-only mode; blocking CI on day one just alienates a team with a legacy repo.
Treat thresholds as alarms, not scores. Engineers game metrics that become goals — one complex function becomes five pointless ones, a large PR gets split without reducing scope, a dependency hides behind an internal wrapper. Budgets catch symptoms. The debt this article is about is clean by construction, so it passes every one of them.
9. Make deletion first-class work
A review process whose only verbs are add, handle, document and test can only ever grow a system. That is worth sitting with, because it describes almost every review process in existence.
So create deletion PRs with explicit targets: remove an unused extension point, collapse an interface that has one implementation, delete speculative configuration, eliminate a duplicate retry layer, drop a dependency. Include the evidence that the retained behaviour still satisfies the contract.
And do not measure deletion in lines. Removing one line that deletes a public interface or a dependency is worth more than deleting a thousand generated ones. Count removed concepts, states, edges, operational responsibilities and supported permutations. Deletion is product work — it reduces the number of futures the team has to stay compatible with.
The protocol, at PR level
Nothing here needs an autonomous architecture oracle. It uses current agents for planning, questioning, retrieval, rendering, specialised criticism and editing, and keeps the strategic decision with humans.
What does not work yet
Asking an agent "is this too complex?" gets you very little. It is a leading question with no decision procedure behind it, and the model has no stake in the answer. Ask "is this design appropriate?" and you will often get an equally fluent defence. Underspecified review questions produce framing-sensitive answers.
It does not carry the pager. It does not explain the roadmap slip. It will not migrate the database in two years or delete the abstraction when the imagined second implementation never arrives. And product strategy mostly lives in conversations, customer commitments, failed experiments and staffing constraints — a large context window is not organisational memory.
There is also a taste problem, and taste is not knowledge of design patterns. It is calibrated discomfort with concepts that cost more than they return, and it comes from watching systems age. That is the thing on my list of things AI is still bad at that has moved least in a year.
For a model to do subtraction on its own, several things would have to change: durable memory of product strategy, non-goals and prior decisions; feedback tied to total system cost over months rather than patch acceptance; evaluation that rewards removed concepts and avoided maintenance; access to real usage data; explicit authority to reject scope; and reliable uncertainty handling that says "measure this" instead of inventing a defensive framework.
Until then the strongest final check is still low-tech: an independent reviewer with enough product context to ask why each concept exists. Agents can surface deletion candidates and render the structure. Somebody accountable still has to ask the question the diff cannot answer — why does this need to exist?
KISS Your AI Workflow — the same principle applied to the workflow instead of the codebase.
The Review Is Automated — the Decision Isn't — where the line between agent and human actually falls.
The Third Pass — the review structure that keeps independent lenses from collapsing into one.
Things AI Is Surprisingly Bad At — the taste problem.
Claude Now Watermarks Your Text — what the invisible mark actually proves, and why code is the hardest case for it.