Does Code Quality Still Matter? It Depends on This — Max Kanat-Alexander, Capital One

Read the talk

Does Code Quality Still Matter? It Depends on This

Recording frame at 16:03: Does Code Quality Still Matter? It Depends on ThisOpen full source frame
Does Code Quality Still Matter? It Depends on This — recording at 16:03

Failure consequences, replacement cost, dependencies and maintenance help determine how much engineering rigor software deserves. Making that rigor cheaper is a separate opportunity—and makes it easier to recover when a supposedly disposable program becomes a lasting system.

From a talk by Max Kanat-Alexander

At a glance

Ideas worth remembering

  • Code quality supports understanding actual system behavior and changing it safely. A modification can cause trouble now or make later changes harder, allowing risk to compound across successive changes.

  • Judge disposability by failure consequences, replacement cost, people and systems depending on the software, and maintenance cost. Cheap replacement alone does not settle the decision; uncertain estimates should lean toward durability.

  • Make software easier to discard by isolating its data access, blocking production dependents, retaining a durable fallback and limiting its scope. The fallback example shows how durable and disposable software can coexist.

  • Lower the cost of rigor through standard stacks and protocols, automatic reliable checks, and shared infrastructure for fast, deterministic tests. Coding agents can help create in-memory service fakes, but those fakes still need to be made available to test authors.

  • Apply strict linting early while keeping false positives low and their consequences tolerable. Avoiding a large later cleanup is one way to make rigor cheaper—and cheaper rigor makes it easier to recover when supposedly disposable software becomes durable.

What code quality buys

“It depends” is the senior engineer’s ready answer to whether code quality still matters. Max Kanat-Alexander of Capital One starts by asking what that answer depends on. Before deciding how much engineering effort to spend, we need a reason code quality mattered in the first place. Feeling good about the code is too weak a justification.

Recording frame at 2:29: What code quality buysOpen full source frame
What code quality buys — recording at 2:29

His framework starts with two requirements for accomplishing anything with software: understanding, and executing on that understanding. Debuggers, observability, evaluations and tests help us learn what a system does or act on what we have learned. The same model covers work as different as aligning a model, scaling a system and driving adoption. Code quality earns its place by supporting those two requirements.

For a software engineer, two kinds of understanding matter most:

  • Actual behavior: What the system really does, including behavior its documentation may not capture.
  • Safe modification: How to change that behavior correctly and safely.
0:120:42
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

0:12 · section reference included

Structure gives a large system understandable parts

For a program that prints Hello, World, understanding and execution fit in a tiny example. Its behavior is the printed text. Change the requirement to Hi, World, and the intended modification is equally easy to describe. There is little else to understand before making it.

The codebase map of Chromium, the open source project behind Chrome, introduces a different problem. Its components can interact in too many ways for a useful description to enumerate the whole system’s behavior. A component provides a smaller unit of understanding: Chromium’s URL parser identifies the different parts of a URL. That behavior can be described even when the behavior of the browser as a whole is too complex to hold at once.

The next Hello, World comparison asks what structure contributes when output stays the same. Both versions would print Hello World on Linux. The left-hand representation makes its identity as a Hello, World program apparent; the right-hand representation presents a series of instructions whose overall purpose is harder to recognize.

Recording frame at 4:41: Structure gives a large system understandable partsOpen full source frame
Structure gives a large system understandable parts — recording at 4:41

At this small scale, a reader can still work through the instructions. Across millions or billions of lines, the missing structure becomes much more consequential. Readability and testability are ways of talking about the underlying need for an understandable system. Identifiable components let us reason about behavior without repeatedly reconstructing their purpose from individual operations.

2:122:42
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

2:12 · section reference included

Two risks compound across changes

Changing a system creates two kinds of risk:

  • A problem with the current change: The code might behave incorrectly for users, but the project can also run late, exceed its budget or fail. A bug is only one kind of bad outcome.
  • More difficulty on future changes: The modification can make the system harder to understand and alter, increasing the likelihood of problems later.
Recording frame at 5:47: Two risks compound across changesOpen full source frame
Two risks compound across changes — recording at 5:47

These risks connect to understanding in different ways. Existing difficulty makes it harder to perform today’s change safely. New difficulty introduced by the change makes tomorrow’s work riskier. A confusing production configuration or behavior that emerges from complicated interactions can make the current system difficult to understand; a modification that obscures the system adds to that difficulty.

The feedback path below explains how one modification can raise the risk of later problems. A change can cause immediate trouble, and it can also leave a less understandable system as the starting point for the next change. Kanat-Alexander describes this as a nonlinear compounding effect. At the extreme, almost every modification creates a problem. His giant mainframe example illustrates the result: a system becomes difficult to change at all, with costs appearing in timelines and organizational problems as well as software failures.

How a change can increase the risk of later changes

Current systemExisting behavior, configuration or interactions may already be difficult to understand.
Attempt a changeReason about the system and modify its behavior.
Problems in this changeUnexpected behavior, delays, budget overruns or project failure.
Less understandable systemThe modification can make future changes harder and riskier.
The two outgoing branches represent separate risks of the same modification. The return path carries added difficulty into the starting conditions for later work.
Read the diagram as text
  • Current system. Existing behavior, configuration or interactions may already be difficult to understand.
  • Attempt a change. Reason about the system and modify its behavior.
  • Problems in this change. Unexpected behavior, delays, budget overruns or project failure.
  • Less understandable system. The modification can make future changes harder and riskier.
  • Current system → Attempt a change: Existing difficulty raises the risk of changing it.
  • Attempt a change → Problems in this change: May introduce.
  • Attempt a change → Less understandable system: May leave behind.
  • Less understandable system → Current system: Becomes starting difficulty for the next change.
4:425:12
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

4:42 · section reference included

When software can be thrown away

Future models might become better at handling complex systems. Kanat-Alexander sets that possibility aside to examine another change: the expansion of disposable software. This category has existed for a long time. He expects it to become dramatically more common as models make software easier to create and replace.

Recording frame at 8:40: When software can be thrown awayOpen full source frame
When software can be thrown away — recording at 8:40

Imagine a program with minimal or nonexistent consequences of failure, few users and almost no other systems depending on it. There is little need to coordinate changes with others. The whole thing can be replaced in hours or days, and maintenance costs nearly nothing. Under those conditions, preserving code quality has little value in this framework: the compounding risks it was meant to prevent no longer justify the effort of preserving the implementation.

Durable software carries a different set of obligations. It lives for years, serves thousands or millions of people, can fail in ways that threaten the business, and demands continuing maintenance. Kanat-Alexander expects these systems to remain among the most important software even if disposable programs become the most numerous. Their continuing need for changes keeps the value of understanding and safe modification high.

Two small examples make the difference tangible:

  • A personal calculator: If the calculator supplied with the operating system is unsuitable, make another one. In the imagined world of cheap replacement, the few people using such a tool can have agents make their own versions instead of preserving one implementation indefinitely.
  • A planner for one party: Build software to organize a party for the kids, use it for that event, then throw it away. The task ends with the party; the software does not need a continuing life as a maintained product.
6:226:52
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

6:22 · section reference included

Four factors set the level of rigor

To decide how much engineering rigor a system needs, compare four factors together. The endpoints of the spectrum are:

FactorDisposable endDurable end
Consequences of failureMinimal or nonexistentPotentially catastrophic for the business
Cost of replacementNear zero; replaceable in hours or daysHigh
People and systems depending on itFew people; almost no other systemsMany dependents
Cost of maintenanceNearly zeroSubstantial continuing work
Recording frame at 9:33: Four factors set the level of rigorOpen full source frame
Four factors set the level of rigor — recording at 9:33

When all four are low, the system is disposable; when all four are high, it is durable. Cheap replacement addresses only one row of the table. These factors provide qualitative guidance, so mixed cases still require judgment about how much rigor to apply. The practical bias is conservative: err toward treating the software as durable, and assume each factor may be higher than it first appears.

7:218:00
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

9:00 · section reference included

Design software to be more disposable

Disposability is something engineering can increase. Four independent choices reduce the consequences or obligations that make software expensive to abandon:

Recording frame at 10:50: Design software to be more disposableOpen full source frame
Design software to be more disposable — recording at 10:50
  • Isolate data access. Limit deployment to an environment with constrained access to the builder’s data, excluding customer data and personally identifiable information. The environment limits what the software can affect when something goes wrong.
  • Prevent production dependents. Disallow inbound API calls from other production systems. Keeping those systems from relying on this one makes its deletion or replacement easier to tolerate.
  • Keep a durable fallback. An old, clunky system can remain available while people generate more efficient front ends. When one of those front ends fails, its users can return to the old system. The new interface is easier to discard because the important work still has another route.
  • Limit scope. Keep the calculator for one person or the planner for one party. Fewer users and a shorter useful life leave fewer commitments for future changes.

The fallback example makes the relationship especially clear: a durable backup and disposable front ends can coexist. The backup is what makes a front end’s failure tolerable. Kanat-Alexander proposes designing for this kind of disposability as an additional discipline of software engineering. He also expects AI coding tools to increase the absolute amount of durable software, because they make that software easier to create too.

Disposable and durable therefore describe a spectrum. What changes across it is the amount of effort worth putting into engineering rigor. A team can change a system’s position by reducing its consequences and dependencies, while still preserving durable systems where their responsibilities require them.

10:0010:29
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

10:00 · section reference included

Make rigor cheap enough to use by default

A second design choice changes the cost of rigor itself, both immediately and over time. A program initially treated as disposable may later need to be durable. The cheaper it is to strengthen that software, the less painful the mistaken estimate becomes. This creates a separate engineering task: reducing the effort required to apply good practices.

Recording frame at 13:37: Make rigor cheap enough to use by defaultOpen full source frame
Make rigor cheap enough to use by default — recording at 13:37

Several practices attack that cost in different ways:

  • Standardize the choices that multiply support work. A system with no PHP has no PHP-specific linters, practices or security issues to manage. Fewer frontend and backend frameworks mean fewer sets of supporting tools to build. Shared remote procedure call (RPC) protocols serve the same purpose. An agent may be able to generate tools for every stack, but each additional stack creates that work again. Standardization reduces the number of possibilities rigor must cover.
  • Put reliable tools in the workflow. Checks should happen automatically, without programmers deciding to run them or understanding their implementation. They also need to be fast and produce few false positives. Automatic but noisy tooling still costs attention; automatic, reliable tooling can feel almost free. At that point it can be reasonable to use it for disposable software too.
  • Make fast, deterministic testing easy to obtain. The goal is for test authors to get these properties without becoming testing experts. That requires substantial work on shared test infrastructure. The concrete proposal is to provide in-memory fake versions of services, so tests can use those substitutes for their dependencies. Coding agents can help create the fakes, but someone must choose to provide them and make them available to everyone. Shared infrastructure lowers the effort each programmer must spend figuring out how to test.
11:5912:29
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

11:59 · section reference included

Turn strictness on before the cleanup grows

The final recommendation is “maximum strictness”: turn lint rules up from the start and apply them consistently. Like standardization, this removes recurring choices and arguments. The tradeoff is accepting some incorrect warnings when the false-positive rate stays relatively low and their consequences are tolerable.

The cost becomes obvious when a large codebase adopts linting late. In Kanat-Alexander’s illustrative example, turning on a linter in a codebase with a million lines creates a cleanup touching a hundred thousand lines. Keeping the checks enabled for everyone from the beginning avoids accumulating that particular backlog. Fixing violations as code is written makes enforcement part of ordinary changes, rather than a large later migration.

Code quality matters for durable software and can cease to matter at the truly disposable end of the spectrum. Its cost is a separate engineering problem. Making rigor inexpensive to apply gives teams more room to change their minds about how durable a system needs to be—and gives a concrete answer beyond “it depends.”

14:5915:29
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

14:59 · section reference included

Resources

  • Stop Prompting — Greg Pstrucha, Sentry

    Turns recurring agent mistakes into repository policies and deterministic checks, including custom linters and strict types—a concrete extension of making rigor part of the workflow.

  • In the Land of AI Agents, the Verifiers Are King

    Explores the durable enterprise case through architectural guidance, layered verification, quality gates and maintenance work, complementing the decision framework for when rigor is worth applying.

Transcript & slides

Loading transcript and slides…

Transcript download