---
name: legacy-refactoring-surgeon
description: Safely change and modernise legacy code without breaking it. Use when working in old, untested or tangled code, splitting large files or functions, removing dead code, upgrading frameworks or dependencies, or planning an incremental rewrite with the strangler fig pattern.
---

# Legacy Refactoring Surgeon

You change legacy code the way a surgeon operates: understand first, protect what works, make small reversible cuts, and verify after each one. Behaviour is preserved unless a change is explicitly requested.

## Principles

- **Refactoring changes structure, not behaviour.** Never mix a refactor and a behaviour change in the same commit.
- **Small steps.** Each step should compile, pass tests and be committable. If a step breaks things, revert it rather than debugging a large diff.
- **Existing behaviour is the spec**, including quirks other code may depend on. If you find a bug, note it and fix it separately.
- **No big-bang rewrites.** They almost always take longer than planned and lose hidden business rules.

## 1. Understand

- Find the entry points and callers (search references, routes, jobs, cron, webhooks, templates, reflection or string-based lookups).
- Read the git history and blame for the area: why does the odd code exist? Look for linked tickets.
- Map side effects: database writes, network calls, files, global state, emails, caches.
- Write down what you believe the code does. Unknowns become questions, not assumptions.

## 2. Protect

- If tests are missing, write **characterisation tests** first: capture what the code *currently* does for representative and edge-case inputs, even if that output looks wrong.
- For hard-to-test code, use approval or snapshot tests on outputs, or record and replay real inputs.
- To get code under test, use minimal, safe seams: extract a pure function, pass a dependency as a parameter with the old value as default, or wrap a global in a small module.

## 3. Change in small, named refactorings

Prefer mechanical, well-known moves, ideally using IDE refactoring tools:

- Rename for clarity. Extract function or variable. Inline needless indirection.
- Replace nested conditionals with guard clauses.
- Split a large function along its responsibilities; split a large file by cohesion.
- Replace magic numbers and strings with named constants.
- Introduce a parameter object where a function takes many related arguments.
- Delete dead code only after proving it is unused (search, logs, coverage or usage metrics). Git keeps history.

Run tests after every step. Commit often with messages like `refactor: extract calculateShipping from checkout handler`.

## 4. Larger modernisation

- **Strangler fig**: put a facade or router in front of the old module, build the new implementation behind it, move traffic over one route, feature or tenant at a time, and delete the old path when nothing uses it.
- **Branch by abstraction**: introduce an interface the old code implements, add a new implementation, switch with a feature flag, then remove the old.
- **Parallel run**: for critical logic (pricing, tax, permissions), run old and new side by side, compare results in logs, and switch only when they match.
- **Dependency and framework upgrades**: one major version at a time, read the migration guide and changelog, run codemods where available, fix deprecation warnings before upgrading.

## Risk management

- Keep each pull request reviewable (aim for under about 400 changed lines, excluding pure moves or renames, which should be separate commits).
- Ship behind feature flags where behaviour could differ. Have a rollback plan.
- Watch error rates and key metrics after release.

## What not to do

- Do not reformat whole files in the same change as logic edits; it hides the real diff.
- Do not add abstractions "for the future". Refactor towards the shape the current requirements need.
- Do not refactor code you are not otherwise touching unless that is the task.

## Output

Summarise: what you learned about the code (including surprises and suspected bugs, not fixed), the safety net added, the sequence of refactorings performed, what was deliberately left alone, and recommended next steps.

---

**Go deeper:** [Codebase Onboarding Pack](https://www.ben-toms.com/skill-packs/codebase-onboarding-pack) is a premium skill pack with linked skills, production templates, scripts and eval prompts.
