The Simple Version
Every line of code you write is something that can break, something that has to be understood, and something that has to be maintained. The less code you have, the fewer places bugs can live.
Code Is a Liability, Not an Asset
We have a cultural problem in software. We treat code like construction: more output equals more progress. A developer who ships 500 lines this week looks more productive than one who removes 500 lines. But this framing is exactly backwards.
Code is not the product. The behavior the code produces is the product. If you can achieve the same behavior with less code, you’ve made a strict improvement. You’ve reduced the surface area for bugs, reduced the cognitive load for everyone who reads it later, and made future changes less risky.
Think of it in terms of a codebase as a physical space. Every function, every conditional branch, every configuration option is furniture you have to walk around. The more furniture you add, the harder it becomes to move quickly, and the more likely you are to stub your toe at 2am during an incident.
This isn’t just a metaphor. A conditional branch (an if statement, a switch case) creates what’s called a code path, a route the program might take when it runs. Each path has to be tested. Each path can interact with every other path. Ten independent binary choices don’t give you ten possibilities; they give you up to 1,024. Combinatorial explosion is the technical term, and it’s why large codebases become genuinely hard to reason about, even for the people who wrote them.
The Hidden Cost of Keeping Things Around
Dead code is the specific name for code that exists in a codebase but never actually runs. It might be a feature that was disabled, a function that got replaced but never deleted, or an entire module that’s been commented out since 2019 with a note that says “maybe we’ll need this later.”
Dead code doesn’t just sit there harmlessly. It gets read. New developers try to understand it. People write tests against it. Sometimes, due to a configuration change or an obscure conditional, it unexpectedly comes back to life and runs in production doing something no one intended.
This actually happened to the OpenSSL project, one of the most widely-used cryptographic libraries in the world. A code path that was believed to be unreachable turned out to be reachable under specific conditions, contributing to the Heartbleed vulnerability in 2014. The exploit allowed attackers to read chunks of server memory, potentially exposing passwords, private keys, and session tokens. Heartbleed affected an estimated two-thirds of all active websites at the time. The vulnerable code was not some obviously dangerous feature. It was a boundary-checking routine that handled a specific message type, a quiet corner of the codebase that most people didn’t think about.
Heartbleed is an extreme case, but the underlying mechanism is common: code you’re not actively thinking about is code that can surprise you.
Why Deletion Is Hard (and Why That’s the Point)
If deleting code were easy, everyone would do it constantly. It isn’t. There are real reasons engineers hesitate.
First, you have to understand code before you can safely remove it. If you don’t understand what a function does or what depends on it, you can’t confidently delete it. This is itself diagnostic: if the code is so hard to understand that you’re afraid to remove it, that’s a signal the codebase has a structural problem.
Second, there’s the sunk cost instinct. Someone spent time writing that code. Deleting it feels wasteful, like throwing away work. This instinct is worth actively fighting. The time spent writing the code is gone regardless. The relevant question is whether keeping it serves you now.
Third, there’s the “we might need this later” argument. Sometimes you genuinely will. But version control (tools like Git that track every historical version of your code) means nothing is truly lost. If you need that deleted code in six months, you can retrieve it. The option to bring it back costs almost nothing. The cost of keeping unnecessary code around is paid continuously, every time anyone reads or works near it.
As readable code is slower to write and faster to delete, the teams that invest in understanding their code well enough to trim it regularly are the teams that stay fast as their software grows.
What Good Code Hygiene Actually Looks Like
The most disciplined engineering teams treat code deletion as a regular practice, not an occasional cleanup event. A few specific habits make a real difference.
Feature flags with expiration dates. A feature flag is a configuration switch that lets you turn functionality on or off without deploying new code. They’re useful for rolling out changes gradually. But flags that never get cleaned up become permanent conditional branches that everyone has to reason about forever. Teams that force expiration dates on flags, literally scheduling the date when the flag will be removed and the code path committed one way or the other, end up with significantly simpler codebases over time.
Deletion as part of delivery. The best engineers I’ve worked with treat removing the old way of doing something as part of shipping the new way. The pull request (a proposed change submitted for review) that adds a new payment system also removes the old one. Keeping both around “just in case” is a decision that gets made by default rather than on purpose, and defaults toward complexity.
Taking code coverage seriously, but not worshipping it. Code coverage measures what percentage of your code is actually exercised by your tests. High coverage is good. But coverage on dead or near-dead code is misleading. If you have a thousand lines of code and only 600 lines ever matter in practice, your coverage numbers are lying to you about how well-tested your software actually is.
The Counterintuitive Truth About Progress
Software teams often measure velocity by what they ship. Features added, bugs fixed, tickets closed. This is understandable but incomplete. A team that ships ten new features while the underlying system becomes increasingly fragile is not making progress; it’s taking on debt that will be repaid later, usually at the worst possible moment.
The engineers who understand this tend to fight for deletion as a first-class activity. Not because they’re being precious about clean code for its own sake, but because they’ve seen what happens when you don’t. Systems that become too complex to change safely. Bugs that appear in code no one thought was relevant. Incidents that trace back to a function that was supposed to be unreachable.
Less code means fewer places for things to go wrong. That’s not a philosophy. It’s just arithmetic.