Why Deleting Code Is One of the Most Underrated Engineering Skills

by Eric Hanson, Backend Developer at Clean Systems Consulting

The Code That Shouldn't Be There

A developer is debugging a slow query. They trace it to a join on a table called user_preferences_v2. They look at the surrounding code to understand the schema. They notice there's also a user_preferences table. And a user_preferences_legacy table. All three are being queried in various parts of the codebase. Nobody currently on the team knows which one is canonical or what the other two are for.

This is the archaeological layer problem: codebases accumulate history. Features get deprecated but not removed. Experiments get abandoned but not cleaned up. Migrations complete but the old paths stay. Each layer is maintained, read, and sometimes misunderstood by everyone who touches the codebase afterward.

The three user_preferences tables represent three times as much schema to understand, three times as many queries to audit, and an ongoing risk that new code will interact with the wrong one.

What Deletion Actually Costs

Deleting code has a bad reputation for risk. The fear: what if something depends on this? What if removing it breaks something that wasn't obviously connected?

This fear is legitimate for code that is definitely in use. It is dramatically overstated for code that is clearly unused. Most codebases have a substantial amount of code that falls into easily-identified categories:

Feature flags that are permanently enabled: Code that was once conditionally executed based on a flag that has been true in production for two years. The false branch is dead code.

Deprecated endpoints with zero traffic: API endpoints that were marked deprecated, where metrics show zero calls in the last six months.

Dead code paths detected by coverage: Code that is never executed in production and never exercised in tests. Coverage tools can identify it.

Commented-out code: Code that was disabled by commenting rather than deletion, often "just in case." Git history preserves it permanently; it doesn't need to also exist in the file.

Duplicate implementations: Two functions that do the same thing, created at different points in the codebase's history, both still referenced.

For each of these categories, the deletion risk is low and the maintenance benefit is immediate.

The Discipline of Deletion

The precondition for confident deletion is the tooling to verify that something is unused:

Static analysis: Dead code detectors (IntelliJ's built-in analysis, PMD, SonarQube rules) can identify code that is never called from any reachable code path.

Production metrics: For API endpoints and features, traffic metrics confirm whether they are being used. An endpoint with zero requests in 90 days is a deletion candidate.

Feature flag state: If your feature flags are tracked in a registry, flags that are permanently enabled or disabled are candidates for code cleanup.

Database query analysis: Queries that reference tables or columns can be audited against database access patterns to identify columns that are never actually read.

With these tools, deletion stops being guesswork and becomes a measured activity.

The Process That Makes It Safe

Safe deletion is incremental:

  1. Identify the candidate using static analysis or metrics
  2. Verify by searching for all references (IDE find-all-usages, grep, import tracking)
  3. Shadow delete: For higher-risk cases, add logging at the call site for one to two weeks to confirm zero calls before removing
  4. Delete and ship: Remove the code, run tests, deploy
  5. Monitor: Watch error rates for a day or two after deployment

For low-risk deletion (dead code paths confirmed by analysis, commented-out code), steps 3 and 5 can be skipped. For higher-risk deletion (endpoints that might have undocumented callers, code paths with unusual calling patterns), the shadow delete provides confirmation.

The Cultural Problem

Deletion is undervalued for the same reason code is overvalued: metrics track code added, not code removed. A PR that deletes 500 lines and adds 50 looks like less work than a PR that adds 500 lines. The developer who deleted those 500 lines may have done higher-value work.

Teams that explicitly recognize deletion as engineering work — that treat "removed 2,000 lines of dead code" as a meaningful contribution — develop cleaner codebases. Teams that don't gradually accumulate the maintenance overhead of code that doesn't need to exist.

The Practical Takeaway

Schedule two hours in the next sprint specifically for deletion. Run your language's dead code detector. Look at your feature flags and identify any that have been fully rolled out. Check your API traffic metrics for any endpoints below 10 requests per day. For each candidate you find, verify and delete. Track the line count removed. The codebase will be measurably better and the work will have taken an afternoon.

Scale Your Backend - Need an Experienced Backend Developer?

We provide backend engineers who join your team as contractors to help build, improve, and scale your backend systems.

We focus on clean backend design, clear documentation, and systems that remain reliable as products grow. Our goal is to strengthen your team and deliver backend systems that are easy to operate and maintain.

We work from our own development environments and support teams across US, EU, and APAC timezones. Our workflow emphasizes documentation and asynchronous collaboration to keep development efficient and focused.

  • Production Backend Experience. Experience building and maintaining backend systems, APIs, and databases used in production.
  • Scalable Architecture. Design backend systems that stay reliable as your product and traffic grow.
  • Contractor Friendly. Flexible engagement for short projects, long-term support, or extra help during releases.
  • Focus on Backend Reliability. Improve API performance, database stability, and overall backend reliability.
  • Documentation-Driven Development. Development guided by clear documentation so teams stay aligned and work efficiently.
  • Domain-Driven Design. Design backend systems around real business processes and product needs.

Tell us about your project

Our offices

  • Copenhagen
    1 Carlsberg Gate
    1260, København, Denmark
  • Magelang
    12 Jalan Bligo
    56485, Magelang, Indonesia

More articles

Making Clients Feel Confident in Your Work

Confidence isn’t just about skill—it’s about perception. Here’s how to make clients trust that you’ll deliver, even before the work is done.

Read more

Single Points of Failure Are Hiding in Your System Right Now

Single points of failure are not always obvious. The hidden ones — the ones your architecture diagram does not show — are the ones that take down your system in ways you did not see coming.

Read more

What a Healthy CI/CD Pipeline Actually Looks Like

Most teams know their pipeline has problems but lack a concrete reference for what good looks like. Here are the specific, measurable characteristics that separate a healthy pipeline from one that merely exists.

Read more

Synchronous Communication in Microservices Is a Trap

Building a microservices architecture on synchronous REST calls recreates the availability coupling of a monolith while adding network latency and distributed failure modes. The trap is subtle and the exit is non-trivial.

Read more