Refactoring and Dead-Code Removal
Goal
Improve structure or remove unused code while preserving observable behavior
exactly, with test evidence at every step.
Core rule
Refactoring never changes behavior. If a change alters what the program does, it
is a behavior change and belongs in a separate commit with its own tests. Keep
the two apart so a regression is easy to locate and revert.
Workflow
- Establish a passing baseline. Run the repository's test command and build
before touching anything. If the baseline is not green, stop and fix or
record that first; you cannot detect regressions against a broken baseline.
- Ensure behavior is covered. If the code you will change lacks tests that pin
its current behavior, add characterization tests first so a regression will
surface.
- Make one mechanical change at a time. Rename, extract, inline, or move a
single thing. Prefer the language or IDE's automated refactoring tools, which
preserve behavior more reliably than manual edits.
- Re-run tests between steps. After each change, run the affected tests. A
failure isolates the single step that caused it.
- Keep refactoring and behavior change in separate commits. Never mix them.
- Review the diff. Confirm it only restructures and does not alter logic,
defaults, or outputs.
Chesterton's Fence
Do not remove or change code until you understand why it exists. Code that looks
pointless often handles a case that is not obvious from a first reading.
- Find out why the code is there: read history, related tests, comments, and
linked issues.
- If you cannot explain its purpose, assume it has one and investigate further
rather than deleting it.
- Only remove it once you can state what it did and why removing it is safe.
Proving code is dead
Suspected-unused is not proven-unused. Gather evidence before deleting. See
references/dead-code-evidence.md.
- Search for every reference to the symbol across the whole repository,
including tests, configuration, string-based lookups, and dynamic access.
- Check the call graph: confirm nothing reachable calls it, directly or through
an interface, export, or reflection.
- Confirm it is not part of a public API that external consumers depend on.
- Remove it, then run the full test suite and build to confirm nothing breaks.
- If removal is large or risky, deprecate first, then remove after confirming
no use.
Forbidden approaches
- Mixing a behavior change into a refactoring commit.
- Deleting code because it looks unused without reference and call-graph evidence.
- Refactoring against a red or unknown baseline.
- Large sweeping rewrites in a single step that cannot be verified incrementally.
Output
Report the baseline result, each mechanical step taken, the evidence gathered
before any deletion, and the passing test and build output after the changes.
References
- references/dead-code-evidence.md —
gathering reference, call-graph, and test evidence before removing code, and
handling dynamic access and public APIs.
1---2name: refactoring-and-dead-code-removal3description: Changes code structure without changing behavior and removes unused code safely by establishing a passing baseline, making one mechanical change at a time, re-running tests between steps, and proving code is dead before deleting it. Use when cleaning up, simplifying, restructuring, extracting, renaming, or deleting suspected unused code, imports, functions, or files.4license: MIT5---67# Refactoring and Dead-Code Removal89## Goal1011Improve structure or remove unused code while preserving observable behavior12exactly, with test evidence at every step.1314## Core rule1516Refactoring never changes behavior. If a change alters what the program does, it17is a behavior change and belongs in a separate commit with its own tests. Keep18the two apart so a regression is easy to locate and revert.1920## Workflow21221. Establish a passing baseline. Run the repository's test command and build23 before touching anything. If the baseline is not green, stop and fix or24 record that first; you cannot detect regressions against a broken baseline.252. Ensure behavior is covered. If the code you will change lacks tests that pin26 its current behavior, add characterization tests first so a regression will27 surface.283. Make one mechanical change at a time. Rename, extract, inline, or move a29 single thing. Prefer the language or IDE's automated refactoring tools, which30 preserve behavior more reliably than manual edits.314. Re-run tests between steps. After each change, run the affected tests. A32 failure isolates the single step that caused it.335. Keep refactoring and behavior change in separate commits. Never mix them.346. Review the diff. Confirm it only restructures and does not alter logic,35 defaults, or outputs.3637## Chesterton's Fence3839Do not remove or change code until you understand why it exists. Code that looks40pointless often handles a case that is not obvious from a first reading.41421. Find out why the code is there: read history, related tests, comments, and43 linked issues.442. If you cannot explain its purpose, assume it has one and investigate further45 rather than deleting it.463. Only remove it once you can state what it did and why removing it is safe.4748## Proving code is dead4950Suspected-unused is not proven-unused. Gather evidence before deleting. See51[references/dead-code-evidence.md](references/dead-code-evidence.md).52531. Search for every reference to the symbol across the whole repository,54 including tests, configuration, string-based lookups, and dynamic access.552. Check the call graph: confirm nothing reachable calls it, directly or through56 an interface, export, or reflection.573. Confirm it is not part of a public API that external consumers depend on.584. Remove it, then run the full test suite and build to confirm nothing breaks.595. If removal is large or risky, deprecate first, then remove after confirming60 no use.6162## Forbidden approaches6364- Mixing a behavior change into a refactoring commit.65- Deleting code because it looks unused without reference and call-graph evidence.66- Refactoring against a red or unknown baseline.67- Large sweeping rewrites in a single step that cannot be verified incrementally.6869## Output7071Report the baseline result, each mechanical step taken, the evidence gathered72before any deletion, and the passing test and build output after the changes.7374## References7576- [references/dead-code-evidence.md](references/dead-code-evidence.md) —77 gathering reference, call-graph, and test evidence before removing code, and78 handling dynamic access and public APIs.