The Best Code Is No Code: Why Deleting Beats Adding
The Best Code Is No Code: Why Deleting Beats Adding
Engineers get rewarded for adding — features shipped, lines written, pull requests merged. So they add. But here's the counterintuitive truth experienced engineers eventually learn: every line of code is a liability, not an asset. Code has to be maintained, debugged, secured, and understood — forever. The most valuable code is frequently the code you didn't write.
This reframes the whole job. Here's why deleting beats adding, and why the best engineers write less code, not more.
Quick Answer
Code is a liability, not an asset. Every line must be maintained, debugged, and secured — so the best code is often no code.
The reframe:
- Less code = less to maintain, break, and secure. Every line is ongoing cost.
- The best solution is often no new code — reuse, simplify, or don't build it.
- Deleting code is valuable work, not a failure to produce.
- Measure outcomes, not output — lines written is a terrible metric.
The best engineers solve problems with the least code, not the most.
Photo by Markus Spiske on Unsplash
Why every line is a liability
The intuitive view is that code is an asset — you build it, you own it, it has value. But code's value lies in the problems it solves, not in its existence, and meanwhile every line carries ongoing cost. Code must be maintained as requirements change, debugged when it breaks, secured against new threats, and understood by everyone who touches it later. That cost never ends; it's a perpetual liability on the books.
This is why "more code" is rarely the win it feels like. Each line you add is something that can break, a surface that can be attacked, a thing the next engineer has to comprehend. The codebase that does the same job with half the code is better — easier to maintain, harder to break, simpler to secure. Recognizing code as a liability rather than an asset flips the instinct to add: the goal becomes solving the problem with as little code as possible, because every line you avoid writing is a liability you never take on.
The best solution is often no new code
Once you see code as a liability, a powerful question emerges before any build: do we need to write this at all? Often the best solution involves no new code:
| Instead of building… | Consider… |
|---|---|
| A new feature from scratch | Reusing what already exists |
| A complex custom solution | A simpler approach with less code |
| Yet another abstraction | Removing one |
| The feature at all | Whether it's even needed |
Reuse, simplification, and not building are frequently superior to writing something new, precisely because they avoid taking on new liability. The best engineers reach for "can we solve this without new code?" before reaching for the keyboard. This connects directly to the build-vs-buy decision: often the wisest engineering choice is to not build at all, sidestepping the entire maintenance burden. The code you don't write is the code you never have to maintain, debug, or secure.
Deleting code is real work
If code is a liability, then removing it is genuinely valuable work — yet it's chronically undervalued because it doesn't look like production. A pull request that deletes a thousand lines while preserving behavior is a real improvement: less to maintain, fewer places for bugs to hide, a smaller attack surface, a more understandable system. Deleting code reduces liability, which is exactly the goal.
The cultural problem is that engineers are rewarded for adding and rarely for removing, so deletion gets neglected even though it's often the highest-value thing you can do. Treating code as a liability corrects this: a day spent removing unneeded code, collapsing duplication, or simplifying an over-engineered abstraction is a day well spent, not a day without output. The best engineers are as comfortable deleting as adding — sometimes more so — because they understand that a smaller, simpler codebase is a stronger one. Deleting isn't a failure to produce; it's producing the most valuable thing of all: less liability.
Measure outcomes, not output
The deepest implication is about measurement. Lines of code is a terrible metric because it measures output (liability produced) rather than outcomes (problems solved). An engineer who solves a problem in 50 lines did better work than one who took 500, yet a lines-written metric rewards the worse engineer. Optimizing for output actively encourages the wrong behavior — more code, more liability, worse systems.
What matters is outcomes: problems solved, value delivered, systems kept simple and reliable. The best engineers measure themselves by what they accomplish, not how much they wrote — and frequently accomplish more with less code. This is the same vanity-metrics trap applied to engineering: impressive-looking output (lines, PRs, features) is not the same as real value (problems solved, simplicity maintained). Judge by outcomes, and the incentive to write more code for its own sake disappears — replaced by the goal of solving problems with the least code possible.
The bottom line
The best code is often no code. Every line is a liability — something to maintain, debug, secure, and understand forever — not an asset whose value comes from existing. Once you see code that way, the instinct to add flips: the goal becomes solving problems with the least code possible.
That means asking whether you need to build at all (reuse and simplification beat new code), treating deletion as the valuable work it genuinely is, and measuring outcomes rather than output, since lines of code rewards exactly the wrong behavior. The best engineers solve problems with the least code, not the most — because the code you don't write is the liability you never carry.
The Hidden Costs of Code: Beyond Maintenance and Security
Code’s liability extends far beyond the obvious burdens of maintenance and security. Every line introduces cognitive overhead—complexity that slows down onboarding, increases the risk of misinterpretation, and makes future changes more error-prone. A system with 10,000 lines isn’t just twice as hard to manage as one with 5,000; it’s exponentially more difficult due to the interactions between components, edge cases, and implicit assumptions. This is why large codebases often suffer from "knowledge silos," where only a handful of engineers understand critical paths, creating bottlenecks and single points of failure.
Another underappreciated cost is the "opportunity cost" of code. Time spent writing, reviewing, and maintaining code is time not spent on higher-leverage activities—like improving observability, reducing technical debt, or exploring alternative solutions. For example, a team might spend weeks building a custom caching layer, only to later realize that an off-the-shelf solution would have been cheaper, more reliable, and easier to maintain. The best engineers recognize this trade-off and default to "boring" solutions—proven tools and patterns—over novel implementations that introduce risk without proportional value.
When Reuse Becomes a Trap: The Over-Abstraction Problem
Reusing code is often framed as a universal good, but over-reliance on abstractions can backfire. The wrong abstraction—one that’s too generic, too rigid, or too complex—can become a liability in itself. For example, a shared utility library that handles everything from logging to authentication might seem efficient, but it forces every team to adopt its conventions, dependencies, and quirks. When the library needs to change, every dependent system must update, creating a cascade of work that could have been avoided with simpler, decoupled solutions.
The key is to favor composition over inheritance and specificity over generality. Instead of building a monolithic "core" library, break it into smaller, focused modules that teams can adopt independently. Similarly, resist the urge to abstract prematurely—wait until a pattern has emerged organically in multiple places before creating a shared solution. This approach reduces the risk of over-engineering while still capturing the benefits of reuse.
Common pitfalls of over-abstraction include:
- Premature generalization: Building for hypothetical future use cases that never materialize, adding complexity without value.
- Tight coupling: Creating dependencies that make systems harder to change or test in isolation.
- Leaky abstractions: When the abstraction fails to hide underlying complexity, forcing engineers to understand its internals anyway.
The Role of Process in Reducing Code Liability
Code isn’t the only way to solve problems—process changes can often achieve the same outcome with less risk. For example, instead of building a custom approval workflow for deployments, a team might enforce a manual review step with clear documentation. This avoids the liability of maintaining a new system while still achieving the goal of controlled releases. Similarly, a feature flag framework might seem like a heavyweight solution for gradual rollouts, but a simple spreadsheet tracking rollout status can work just as well for smaller teams.
The best engineers think beyond code to consider:
- Operational workarounds: Can the problem be solved with existing tools or manual processes, at least temporarily?
- User education: Could better documentation or training reduce the need for a technical solution?
- Business trade-offs: Is the feature worth the long-term cost, or can the requirement be adjusted to simplify implementation?
This mindset shift—from "how do we build this?" to "do we need to build this at all?"—is critical for reducing code liability. It requires close collaboration with stakeholders to understand the real problem, not just the requested solution. Often, the most effective engineering work happens before a single line of code is written, by challenging assumptions and exploring alternatives that don’t involve new code.
Key Takeaways
- Treat every new line of code as a long-term liability—it requires perpetual maintenance, debugging, security updates, and comprehension by future engineers, increasing total cost of ownership.
- Before writing new code, exhaust non-code solutions: reuse existing components, simplify requirements, or eliminate the feature entirely to avoid unnecessary liability.
- Deleting code is high-value work—removing unused or redundant code reduces maintenance burden, attack surface, and cognitive load, yet is often undervalued in engineering cultures.
- Replace vanity metrics like lines of code with outcome-based measurement: prioritize problems solved and system simplicity over output volume to incentivize better engineering.
- The best engineers default to 'no code'—they solve problems with minimal new code, leveraging existing tools, abstractions, or process changes to avoid adding liability.
- Over-engineering and premature abstraction create hidden costs; favor straightforward, maintainable solutions over complex ones that solve hypothetical future problems.
Frequently Asked Questions
How can code be a liability when it's what we build?
Because code's value is in the problems it solves, not its existence — and every line carries perpetual cost: maintenance as requirements change, debugging when it breaks, securing against threats, and comprehension by everyone who touches it. That cost never ends. A codebase doing the same job with less code is better — easier to maintain, harder to break, simpler to secure. Seeing code as a liability flips the instinct to add and pushes you to solve problems with as little code as possible.
Is deleting code really valuable if it doesn't add features?
Yes — if code is a liability, removing it reduces liability, which is real improvement: less to maintain, fewer places for bugs, a smaller attack surface, a more understandable system. A PR that deletes a thousand lines while preserving behavior is genuinely valuable. Deletion is undervalued only because engineers are rewarded for adding, not removing. The best engineers are as comfortable deleting as adding, because they know a smaller, simpler codebase is a stronger one.
Why is lines of code a bad metric?
Because it measures output — liability produced — rather than outcomes — problems solved. An engineer who solves a problem in 50 lines did better work than one who took 500, yet a lines-written metric rewards the worse one and encourages more code, more liability, and worse systems. The right measure is outcomes: value delivered and systems kept simple and reliable. Judge by what's accomplished, not how much was written, and the incentive to write code for its own sake disappears.




Comments
Sign in to join the conversation
No comments yet. Be the first to share your thoughts!