← Back to Epic planning
See how it helps
Safe legacy refactoring
Restructures legacy code in focused steps while recording current behavior and keeping intentional changes distinct from accidental regressions.
legacy-refactoring
Workflow agents using this skill
When is it useful?
Use it when you must modify hard-to-test code without quietly replacing its existing contract.
What does it help you do?
- Captures existing behavior in passing characterization tests.
- Introduces only the seam needed to isolate the change.
- Separates deliberate bug fixes from behavior-preserving restructuring.
Try asking this
Extract pricing logic while preserving the current documented rounding behavior. Use boundary-value invoices as characterization cases. The extracted calculation must return identical totals, while any suspected rounding bug is documented separately.
Detailed documentation
Read the skill’s original instructions, examples and checks in their authored language.
Show less
Legacy Refactoring
Code without trustworthy tests is legacy code. Get control before improving the design: understand the current behavior, protect what must stay, open the smallest seam, break the dependency that blocks feedback, make the requested change, and leave the area easier to test.
Before editing
- State the behavior change you were asked for and the current behavior that must stay. Do not quietly fix suspicious behavior; characterize it and report it.
- No rewrite and no module-wide cleanup unless the task asks for it or it is clearly safer.
- Find the change point, then trace its effects outward (return values, fields, outputs, calls to collaborators) to choose where a test can observe it.
Characterization tests
- Pin what the code does now, not what it should do: call it with real inputs, capture the actual output (even a wrong one) and assert exactly that.
- Cover the paths your change touches, including odd branches and error paths. Mark wrong behavior in the test name or a comment, and leave fixing it to a separate, deliberate change.
- They must pass before you change anything; a failure afterwards is a behavior change you did not intend.
- Prefer fast, focused tests close to the change; use a broader integration test only where that is the safest place to observe.
Seams and dependencies
- Use the smallest seam that lets you substitute, observe or intercept, and say whether it is for sensing (seeing a result) or separation (running without a dependency).
- Break only the dependency that blocks the test or the safe change: constructor work, hidden allocation, globals and statics, framework objects, time, randomness, environment, files, network, database writes, process exits. Wrap or inject that boundary.
- Match the technique to the barrier: a narrower parameter, an extracted interface, a parameterized constructor or method, an encapsulated global, an overridable factory call. Build or link tricks only when ordinary seams are impractical.
- Hard-to-test methods: separate construction from use, move side effects behind collaborators, extract pure computation first, separate business rules from persistence, UI and framework code.
Adding the change
- When editing in place is risky, add behavior beside it: a sprout method or class for new logic, a wrap method or class to run something before or after the old code.
- Keep behavior changes, structural refactoring and cleanup in separate steps, each verified by the tests. Do not keep exploratory restructuring done only to understand the code.
- In a large method or class, sketch its effects and responsibilities first and extract one piece at a time; never edit many branches at once.
- Remove duplication step by step under tests, not with a broad redesign.
Avoid
- Growing hidden dependencies, or mocking around untestable structure without improving it.
- Renaming or reformatting while the real dependency knots remain.
- Bringing in a large architecture before basic seams exist.
- Leaving test-only seams, public-for-test members or subclass tricks without a cleanup note.
Before you finish
- The behavior to change and the behavior to keep are stated.
- Characterization tests pinned the current behavior before the change.
- The smallest seam was used; its purpose (sensing or separation) is clear.
- Behavior change, refactoring and cleanup are separate steps.
- Temporary seams have a cleanup path; the area is easier to test than before.
Included files 2
LICENSE.txtSKILL.md
