Code Quality

Concept

Keeping code in a state where someone else can read and change it six months from now, so later fixes stay cheap.

Why it exists

For a long time, working code and good code meant the same thing. If the screen loaded and the button did what it said, the code had done its job, and nobody except its author ever looked at the shape of it. That held up fine as long as the service was short-lived or the person who wrote it stayed in the same seat. When someone with the whole map in their head sits two desks away, the shape of the code barely matters, because every question has a shortcut.

The assumption broke as people left and years passed. At Pagedeck it broke on the day Theo was asked to reword one line of payment-failure copy. He said an hour. It took three days. The same sentence lived in four places, the engineer who wrote the first one had already left, and nothing in the code said which of the four actually reached a customer's screen. He fixed three, shipped, and the next morning enterprise accounts were still seeing the old wording.

None of the three days went into writing the new sentence, which took a minute. They went into finding every copy, reading enough of the surrounding code to guess which one mattered, and then guessing wrong. That split — a small change wrapped in a large search — is the shape of the problem, and it shows up long before anyone calls it a problem.

After that happens a few times, the meeting always lands in the same spot. One side asks how a single line of copy takes three days. The other side says that's just how that part of the codebase is. Neither statement is wrong, so nothing gets decided. The only visible fact is a slipped date, and the real reason sits inside the code with no name attached to it.

Code quality is the name for that place. Whether a feature works is answered by testing, which is the practice of setting things up so a machine, rather than a person, confirms the code does what it was meant to do. Code quality takes the next question: how cheaply can a stranger change this working code half a year from now. The first catches what is broken today. The second lowers both the odds of breaking something later and the price of the repair. That's why quality isn't a review step tacked on at the end — it's treated as the daily habit of writing the code itself.

How this field breaks down

The terms under code quality fall into four branches. Concepts name the bad state, activity reverses it, tools find it before a person does, and principles keep it from forming in the first place.

Concepts give a name to something that is otherwise invisible. There are two.

  1. Code smell — a signal that the structure has degraded, even though nothing is broken yet. One function grown to 400 lines, the same calculation copied into four files, a name that describes something other than what the code does. It's called a smell rather than a fault because it doesn't mean stop, it means open this up and look.
  2. Technical debt — the cost of cleanup postponed to move faster, collected later with interest. The debt metaphor holds because the balance grows while it goes unpaid. The principal is the cleanup itself; the interest is the extra time every future feature spends working around it. A branch of logic wedged in to save a day this week takes half a day back every time anyone touches that area two quarters later.

Activity is the branch that pays the balance down. Refactoring changes structure while leaving behavior alone, and it comes with one condition: nothing a user can see may differ before and after. Collapsing those four copies of the payment message into one is exactly this. The customer's screen is identical, and the next person to change the wording edits a single place. Since no human can eyeball whether behavior really stayed identical, refactoring is only safe where tests already exist to say so. It also works in small steps by design. Renaming one thing, splitting one function, moving one file — each step shippable on its own — rather than a month-long rewrite that can't be reviewed or reversed.

Tools are the branch where a machine reads the code before any person does. There are three, each looking wider than the last.

  1. Formatter — fixes surface appearance automatically: line breaks, indentation, quote style. Run it on every save and arguments about appearance disappear as a category. The time a team spent trading review comments about two spaces versus four drops to zero.
  2. Linter — catches risky habits rather than looks. A variable declared and never used, an assignment written where a comparison belongs, an error case left unhandled. Findings that would cost a reviewer a day show up as a red underline the moment the file is saved.
  3. Static analysis — scans the whole codebase without running it, to find problems with a longer reach. Instead of staying inside one file it follows calls between functions and files, flagging paths where a value can be empty or where outside input travels in without ever being checked.

Principles are the judgment calls made while the code is being written. They work less like rules and more like sentences you pull out at a fork in the road.

  1. Don't Repeat Yourself (DRY) — the same piece of knowledge should not live in two places. Those four copies of one sentence were this principle being ignored. Copying is cheap only in the moment it happens; the bill goes to whoever edits next.
  2. You Aren't Gonna Need It (YAGNI) — don't build it before it's needed. If a currency structure built in case the product went international has spent two years handling only one currency, it isn't preparation. It's weight that every reader has to walk around.
  3. Boy Scout Rule — leave the code you touched a little better than you found it. It improves the state of a codebase without anyone approving dedicated cleanup time, which is why teams that can't get that time reach for it first.

The four branches aren't a flat list. They feed each other in a loop: ignoring a principle produces a smell, leaving smells alone accumulates debt, paying that debt down is refactoring, and tools catch the first three before a human would, shrinking the balance that ever needs paying.

Knowing the four branches still leaves the question of whether the code is good right now, and that has to be measured separately. There is no single reading for code quality the way a scale gives a weight, so teams usually pick two or three stand-ins. How many days similar-sized changes took on average. How many files had to be touched to change one thing. Whether the warnings the tools produce went up or down since last month. No one of those represents quality on its own. An area where all three drift the wrong way at once is an area due for work. Reading them one area at a time matters too, since a codebase is rarely uniformly bad. Usually one or two directories carry most of the cost while the rest is fine, and finding those is the point of measuring at all.

How it sounds at work

"Give me two days of code quality work this sprint. Payments can't take another feature in its current state."

A request to trade new work for cleanup, argued as the price of keeping the next date rather than as a preference.

"In reviews, let's only raise code quality points the machines can't catch."

Leave formatting and rule violations to tooling so people spend review on design and naming, where judgment is actually required.

"At this code quality, a new hire won't ship anything for three weeks."

Restating how hard the code is to read as a number: onboarding time.

At Pagedeck this comes up most often in quarterly planning. Grace asks what ships next quarter, and Theo answers that payments can carry two features at the current pace. Asked why, he brings the last three payment changes and how many days each took, split into time spent building the new thing and time spent understanding the existing code. Five days for one feature, three of them spent reading.

Grace's question is always the same: if we spend two days now, how many days does that buy back next quarter. When the answer isn't a number, cleanup slides. So Theo started logging the days each change took along with a one-line reason. Once the evidence lives in a record, the same request clears the room far faster.

Mia puts those numbers into the schedule. A feature landing in a rough area gets more time than its size suggests, and cleanup work goes between features rather than after them. In areas that never get dedicated time, Theo's team relies on leaving each spot slightly better than they found it. Half a year later the frequently edited files are noticeably easier to read while the untouched ones stay as they were, which is the intended outcome: the places people work in improve first. Theo doesn't argue for the untouched files. A file nobody has opened in a year is costing the team nothing, and cleaning it up buys back nothing either.

What people get wrong

The most common mistake is treating code quality as something to do when there's spare time. Cleanup changes nothing on screen and no customer notices, so it looks like work that can wait until the urgent list is empty. In practice it's the variable that decides how many days the next feature takes — the reason a same-sized feature costs two days in one area and a week in another. Left alone, the time spent on comparable work creeps up quarter by quarter until someone proposes rewriting from scratch because that would be faster. If the proposal wins, months pass with nothing new shipping, and the rewrite repeats the conversation in two years if the same habits carry over. The bill doesn't vanish while it's postponed; it grows. Deferring is less a choice to do urgent work first than a choice to move the work to a more expensive moment.

Assuming more quality is always better runs a close second. The word itself sounds like something you'd want more of. But code has a lifespan, and lifespans differ. Applying one standard to a throwaway screen built to test an idea for a week and to payment code that will move money for three years gets both wrong: the first gets answered too late, the second stays fragile. A team holding this belief either polishes unvalidated ideas until it loses its learning speed, or carries prototype standards into code that has to last. The decision worth making isn't how high to set quality, it's how long this code is expected to live. Once that's settled, how far to polish follows from it. A prototype meant to be deleted in a week needs to be readable enough for one person for one week. Payment code needs to be readable by someone who hasn't been hired yet.

Where to go next

  • Engineering

    see which branch of a technical organization this work sits in first

  • Refactoring

    the activity that actually reverses a degraded codebase, so read it next

Sub-terms

Last updated 2026-09-16