← Back to Phaser · project planning pack

Skill · Version 1.0.0

Safe legacy refactoring

Makes older gameplay code easier to change while preserving its current behavior. Captures existing rules in tests and separates structural cleanup from deliberate changes to game mechanics.

legacy-refactoring

Agents using this skill

See how it helps

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

Refactor a large inventory controller that handles stacking, equipment and quest items. First capture the existing behavior for full bags and item removal. Extract only the boundary needed for the next feature, rerun those cases and list any intended rule change separately from the behavior-preserving refactor.

Detailed documentation

Read the skill’s original instructions, examples and checks in their authored language.

Details…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.txt
  • SKILL.md