Skip to main content

What is Dead Code?

Dead code is code that exists in your codebase but never executes. It might be an unused function, an import you forgot to remove, or a variable that's assigned but never read.

Why Does Dead Code Exist?

Dead code accumulates naturally over time:

Common sources:

  • Feature evolution: Old implementations left behind
  • Abandoned experiments: Prototype code never cleaned up
  • Defensive over-importing: "I might need this later"
  • Incomplete refactoring: Moved code, forgot to delete original
  • AI-generated code: Copilot/ChatGPT suggests things you don't use

The True Cost of Dead Code

Dead code isn't harmless. It has real costs:

1. Cognitive Load

Every line of code is a line someone has to read and understand:

# Developer sees this and wonders:
# "Is this used? Should I update it too? What does it do?"

def legacy_process(data): # dead
# 50 lines of complex logic...
pass

def process(data): # used
# Different logic...
pass

More code = slower onboarding, harder debugging, confused developers.

2. Maintenance Burden

Dead code still needs to be:

  • Updated when dependencies change
  • Reviewed in code reviews
  • Included in test coverage metrics
  • Migrated during major upgrades

3. Hidden Security Vulnerabilities

"Unused" code can still be exploited:

# "Dead" admin function, but still accessible via URL!
def admin_delete_all(): # Looks unused
db.execute("DELETE FROM users")

# Attacker finds: yoursite.com/admin/delete_all

If it's in the codebase, it's in the attack surface.

4. Misleading Metrics

Dead code skews your metrics:

MetricWith Dead CodeWithout
Lines of Code100,00070,000
Test Coverage60%85%
Complexity ScoreHighMedium
Onboarding Time3 weeks2 weeks

5. Slower Builds & Larger Bundles

Dead imports still get processed:

# Each import adds to startup time
import pandas # Unused - but still loads 100MB library
import numpy # Unused
import tensorflow # Unused

Types of Dead Code

Unreachable Code

Code that can never execute due to control flow:

def:

# example():
return "done"
print("This never runs") # Unreachable

def another():
if True:
return "always"
return "never" # Unreachable

Unused Definitions

Functions, classes, or variables defined but never referenced:

def:

    pass

def helper_v2(): # called
pass

result = helper_v2()

Unused Imports

Modules imported but never used:

import:

import os    # Never used
from typing import List, Dict, Optional # Dict, Optional unused

def get_items() -> List[str]:
return ["a", "b"]

Dead Parameters

Function parameters that are never read:

def:

    return transform(data)

Dead Variables

Variables that are assigned but never read:

def:

# calculate():
temp = compute_something() # temp is never used
result = compute_other()
return result

Why Removal is Hard

If dead code is so bad, why don't we just delete it?

Fear of Breaking Things

# Is this really unused? What if:
# - It's called dynamically via getattr()
# - It's imported by another service
# - It's used in production but not in the codebase I'm looking at

No Tooling Confidence

Simple grep/search isn't enough:

# Searching for "helper" finds:
# - The function definition
# - Comments mentioning it
# - String literals with the word
# - Actually usage? Hard to tell.

Time Pressure

"I could clean this up... or ship the feature."

Dead code removal gets deprioritized because:

  • It's not a feature
  • It's not a bug fix
  • It's hard to quantify the benefit

How Skylos Helps

Skylos makes dead code removal safe and confident:

1. Cross-File Analysis

Skylos checks the entire codebase, not just one file:

2. Framework Awareness

Skylos understands that frameworks call code implicitly:

@app.route("/users")  # Skylos sees: Flask route decorator
def get_users(): # Not flagged as unused
return users

3. Confidence Scoring

Instead of binary "used/unused", Skylos scores confidence:

FindingConfidenceRecommendation
def _private_helper()20%Probably internal, skip
def unused_public_fn()90%Safe to remove
import json # in test file15%Might be for fixtures

4. Safe Removal Workflow

# 1. See what would be removed
skylos . --dry-run

# 2. Interactive selection
skylos . -i

# 3. Comment out instead of delete (safer)
skylos . -i --comment-out

Best Practices

Delete code, don't comment it

Git remembers everything. Don't leave commented code "just in case."

# Bad - clutters the file
# def old_function():
# pass

# Good - deleted, recoverable from git history
Run Skylos in CI

Prevent new dead code from being introduced:

- name: Check for dead code
run: skylos . --confidence 80 --gate
Schedule regular cleanups

Dedicate time (e.g., monthly) to dead code removal. It's hygiene, like vacuuming.

Start with high confidence

Begin with --confidence 90 to get easy wins. Lower the threshold as you build trust.


Next Steps

Dead Code Detection

How Skylos finds dead code

Vibe Coding & AI Debt

Why AI assistants create dead code