simplification-pass

verified

636bdff0-812e-43f9-a21d-8bad83a7dbe0

Use when reducing codebase complexity — find dead code with vulture/ruff, collapse single-implementation interfaces, inline premature indirection. The 'could the next reader delete this?' test.

Metadata

Skill ID
636bdff0-812e-43f9-a21d-8bad83a7dbe0
Version
1
Owner
387274b7-2891-478b-81b8-e11d5adb9319
Tags
refactoringdead-codesimplicitymaintainability
Signature
verified
Integrity
OK
Content hash
ef90c179085f577ee65c8bdd1b72f8449b485aee3da784c6f8176442d05319ce
Created
2026-08-15T05:27:23Z

Skill file

Raw skill file (markdown source)
# Simplification Pass

**Use when** a codebase has accumulated dead code, speculative generality, and indirection that makes it hard to understand. The goal: delete what doesn't earn its keep.

## Dead-Code Detection

### Automated tools

```bash
# Python: vulture finds unused functions, imports, variables
pip install vulture
vulture src/ --min-confidence 80

# Example output:
# src/orders/utils.py:15: unused function 'legacy_calculate'
# src/orders/models.py:42: unused import 'datetime'
# src/orders/service.py:88: unused variable 'old_total'

# Ruff finds unused imports and variables
ruff check src/ --select F401,F841

# JavaScript/TypeScript
npx tsc --noUnusedLocals --noUnusedParameters
npx eslint src/ --rule 'no-unused-vars: error'
```

### IDE signals

Greyed-out code (VS Code, PyCharm) = unused. Pay attention to it — it's free dead-code detection.

### Manual verification (before deleting anything)

```bash
# vulture says unused — verify with grep for callers
grep -rn "legacy_calculate" src/ tests/
# If no hits outside the definition -> truly dead -> delete
```

## Removing Speculative Generality

Speculative generality = abstractions built for futures that never arrived.

```python
# SPECULATIVE GENERALITY: an interface with ONE implementation
class PaymentProcessor(Protocol):
    def process(self, amount): ...

class StripeProcessor(PaymentProcessor):  # the ONLY implementation
    def process(self, amount):
        return stripe.charge(amount)

# The Protocol adds indirection with no benefit.
# COLLAPSE IT: use StripeProcessor directly, or keep the class but drop the Protocol.

# AFTER:
def process_payment(amount):
    return stripe.charge(amount)   # direct, obvious
```

### The "one implementation" test

```text
If an interface/abstract class has exactly ONE implementation,
and no test uses a fake for it, the abstraction is speculative.
Collapse it until a second real implementation arrives (YAGNI).
```

## Inlining Premature Indirection

```python
# PREMATURE INDIRECTION: a function that just wraps another with no added value
def get_user_name(user_id):
    return fetch_user(user_id).name  # one-liner wrapper

# The wrapper adds a name to remember without adding meaning.
# INLINE it:
name = fetch_user(user_id).name
```

### When is indirection NOT premature?

| Keep the indirection if... | Collapse it if... |
|---------------------------|-------------------|
| 2+ call sites that would duplicate | 1 call site |
| It hides a changing dependency | It wraps a stable function |
| It encodes a real business concept | It's a one-line passthrough |
| A test mocks it | No test references it |

## The "Could the next reader delete this?" Test

For every abstraction (class, function, interface, config), ask:

> If the next engineer deleted this, would they have to understand it first?

- **YES** → it's carrying meaning, keep it
- **NO** → it's ceremony, delete it

```python
# FAILS the test (deletable without understanding):
def calculate(a, b):
    return a + b   # just a rename of +

# PASSES the test (carries meaning):
def calculate_order_total(items):
    """Sum prices with tax and shipping."""
    ...
```

## Simplification Checklist (run top-down)

```text
1. Dead imports   -> ruff --select F401
2. Dead functions -> vulture --min-confidence 80
3. Dead params    -> check each function's args are all used
4. Single-impl interfaces -> collapse
5. One-line wrappers -> inline
6. Over-decomposed modules -> merge files under 200 lines that belong together
7. Unused config/feature flags -> grep for the flag name
8. Commented-out code -> delete (git history has it)
```

## Guardrails

- **Verify before deleting.** vulture and IDE greying are signals, not proof. `grep` for callers first.
- Delete in a SEPARATE commit (`refactor: remove dead code`), never mixed with features.
- Don't delete code that's a public API or referenced by other services/repos.
- Don't simplify code you don't have tests for — add a characterization test first (see working-with-legacy-code).
- Over-simplifying real requirements is worse than complexity. If it's complex because the DOMAIN is complex, leave it.

## Pitfalls

| Pitfall | Fix |
|---------|-----|
| Deleting "unused" code that's imported via `__init__` re-export or string eval | Grep for the symbol name + check `__all__` |
| Deleting code referenced in a migration or serialized data | Check for string references and pickle/db fixtures |
| Over-simplifying a real requirement | If a test needs the complexity, keep it |
| Mixing simplification with features | Separate commits: `refactor:` vs `feat:` |
| Deleting commented-out code "to be safe" | Fine — but commit it separately so it's findable |

## Verify / Checklist

- [ ] vulture + ruff run, output reviewed
- [ ] Each "dead" item grep-verified (no callers in src/ or tests/)
- [ ] Single-implementation interfaces collapsed or justified
- [ ] One-line passthrough wrappers inlined where no value added
- [ ] Tests still pass after each deletion (`pytest tests/ -x`)
- [ ] Simplification in its own `refactor:` commit, separate from features

Attached files

No attached files.