The software industry spent a generation fighting bad habits: cryptic variable names, functions that ran to hundreds of lines, logic nested so deep it required a map. The solution the industry landed on was readability. Write code that reads like prose. Name things clearly. Keep functions short. Make it obvious.

This was the right correction. But somewhere along the way, readability became a proxy for quality. If code looks clean, it gets approved. If it doesn’t, it gets pushed back. The problem is that readability and correctness, performance, and architectural soundness are separate dimensions. Code can score high on one and fail badly on the others. Conflating them produces a particular kind of codebase: one that looks professional, passes review, and slowly falls apart under real conditions.

Why Readability Became the Dominant Metric

Readability is easy to evaluate at a glance. In a pull request review, a reviewer has minutes to assess thousands of lines of change. They can immediately tell whether a variable is named x or userAuthenticationToken. They cannot immediately tell whether a function will behave correctly under concurrent access, or whether an abstraction will survive a feature requirement that doesn’t exist yet.

This asymmetry shapes incentives. Code reviewers optimize for what they can evaluate quickly. Engineers learn what gets approved. Over time, the codebase becomes very readable and very fragile.

The clean code movement, influenced heavily by Robert Martin’s writing, gave this tendency intellectual cover. Martin’s rules (small functions, single responsibility, expressive naming) are genuinely useful. But they were adopted by many teams as a complete definition of quality rather than one component of it. The result is a generation of engineers who can write immaculate-looking code that misses the point.

The Problems Readable Code Can Hide

Consider correctness. A function named getActiveUsers that returns users from cache without checking whether the cache has been invalidated is readable. It is also wrong. The name communicates clearly. The behavior does not match the name. This particular failure mode is so common it has a name: semantic mismatch. The code reads fine and does the wrong thing.

Performance is a starker case. Expressive, readable code often layers abstractions in ways that destroy performance at scale. A chain of map, filter, and reduce calls over a large dataset looks elegant in Python or JavaScript. It may also create multiple intermediate collections, iterate the data several times unnecessarily, and run ten times slower than an equivalent loop that a readability-focused reviewer might flag as “too clever” or “not idiomatic.”

This is not hypothetical. Engineers at companies operating at significant scale regularly have to rewrite readable, idiomatic code because it cannot survive the load. The readable version was easier to write and easier to review. It was not good code for the context in which it was being deployed.

Architectural correctness is the hardest to evaluate and the most expensive to get wrong. Clean interfaces can paper over fundamentally broken designs. A beautifully named set of microservices that are tightly coupled in ways their clean APIs obscure will cause serious problems when you try to change one of them. The readability of individual components says nothing about whether the system is structured to survive its own growth.

Radar chart comparing a readability-heavy codebase against a balanced one across five quality dimensions
Readability is one dimension of code quality. A codebase that scores high on it while neglecting the others isn't well-engineered — it's well-formatted.

What Good Code Actually Requires

Good code satisfies the requirements of its context. A throwaway script has different requirements than a payment processing service. A prototype has different requirements than infrastructure running in production for ten years. Readability matters in all of these contexts, but its weight relative to other properties changes significantly.

The properties that actually matter, in rough order of importance for most production software:

Correctness comes first. Code that does the wrong thing is not good code regardless of how well-named its variables are. This sounds obvious and gets violated constantly. Correctness under edge cases, under failure conditions, and under concurrent access is harder to demonstrate in a review than clean naming, so it gets less attention.

Reliability and error handling are closely related. How does the code behave when the database is unavailable? When the input is malformed? When the external API returns an unexpected response? Good code has considered these paths. Readable code may have ignored them entirely because the happy path is where the expressive naming lives.

Performance at the expected scale matters, though it’s frequently over-optimized prematurely. The correct approach is not to ignore performance in favor of readability; it’s to understand your performance requirements and write code that meets them without unnecessary complexity.

Maintainability includes readability but extends beyond it. Code that is easy to change without breaking other things, code with well-considered boundaries, code where the dependencies are explicit and manageable: these properties make software actually maintainable. Readable code contributes to this but does not guarantee it.

The Code Review Problem

Code review culture has amplified the readability bias in ways that are worth being explicit about. When engineers learn that naming, formatting, and function length are what reviewers comment on, they optimize for those dimensions. Style guides enforced by linters have made this even more pronounced: machines now check formatting automatically, which pushes human reviewers to focus on what machines can’t catch, but in practice many reviewers still spend significant attention on style.

The most valuable code reviews focus on correctness under failure, edge cases, coupling and dependency, and whether the abstraction chosen will generalize to the problem’s actual shape. These require deep reading and contextual understanding. They take longer. They produce comments that are harder to write and sometimes harder for authors to receive than “please rename this variable.”

Teams that want to improve code quality need to evaluate what their review culture actually rewards. If the highest-comment PRs are style discussions, there’s a structural problem.

Readability Is Necessary, Not Sufficient

None of this is an argument against readable code. Unreadable code is a serious problem. Code that no one can understand cannot be maintained, cannot be reviewed, cannot be debugged quickly when it fails. Readability is a real and important property.

The problem is treating it as sufficient. A codebase full of beautifully named, cleanly structured functions that handle errors poorly, couple components unnecessarily, and fail under load is not a high-quality codebase. It is a readable low-quality codebase, which in some ways is more dangerous than an obviously bad one because it will pass review and accumulate until the problems become expensive.

Good code is readable, correct, appropriately performant, and structured to survive change. Readable code is just the first condition. Promoting it to the whole definition is a category error that the industry has been making for long enough that it has shaped how engineers are trained and how software is evaluated. That is worth correcting.