working-with-legacy-code

Guides safe modification of untested codebases using seams, characterization tests, and dependency-breaking techniques.

Updated Jun 27, 2026
One-click install
npx skills add https://github.com/rachmadideni/ai-staff-assistant --skill working-with-legacy-code-rachmadideni
Or copy as Structured Prompt for Agent▼
Please help me install this Agent Skill.
Skill: working-with-legacy-code
Source: https://github.com/rachmadideni/ai-staff-assistant/tree/main/.agents/skills/working-with-legacy-code
Command: npx skills add https://github.com/rachmadideni/ai-staff-assistant --skill working-with-legacy-code-rachmadideni

SYSTEM DOCUMENTATION & REQUIREMENTS

💡 This Skill includes references (resource) components.

What problem does it solve? Changing code without tests is risky because there is no way to verify that existing behavior is preserved. This Skill provides a disciplined, step-by-step method—based on Michael Feathers' Working Effectively with Legacy Code—for getting untested code under a test harness before making changes, so edits stop being gambles. ## Core Features & Use Cases - Legacy Code Change Algorithm: A five-step procedure (identify change points, find test points, break dependencies, write tests, then change) with safety checklists and triage guidance for tight deadlines. - Characterization Tests & Golden Masters: Pin down actual current behavior—including bugs—before refactoring, with guidance on snapshot testing and handling volatile output. - Dependency-Breaking Catalog: Named techniques like Parameterize Constructor, Extract Interface, Subclass and Override Method, and Break Out Method Object, with before/after code in TypeScript, Python, and Java. - Use Case: You inherit an 800-line service class with zero tests and must add a feature. The Skill walks you through parameterizing the constructor, pinning nine characterization tests, and sprouting the new logic as a fully tested class—shipping with zero regressions. ## Quick Start Ask the AI to help you safely add a feature or fix a bug in a specific untested class or module, and it will apply the change algorithm, seams, and characterization tests step by step.

Frequently Asked Questions about working-with-legacy-code

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I safely change code that has no tests?▼

Follow the five-step legacy code change algorithm: identify change points, find test points, break dependencies with minimal signature-preserving edits, write characterization tests that pin current behavior, then make your change. Never mix refactoring and behavior changes in one commit.

What is a characterization test and how do I write one?▼

A characterization test documents what code actually does, not what it should do. Write an assertion you know is wrong, run it, read the failure message to learn the real behavior, then change the assertion to pin that observed value.

How do I test a class whose constructor opens a database connection?▼

Use Parameterize Constructor: add constructor parameters for the dependencies with production defaults, so existing callers compile unchanged while tests inject fakes. Extract Interface on heavy collaborators first if their concrete types are hard to fake.

What is a seam in legacy code?▼

A seam is a place where you can alter program behavior without editing that code, such as an overridable method, a module import, or a build flag. Every seam needs an enabling point reachable from your test where you choose which behavior runs.

Should I fix bugs I find while writing characterization tests?▼

No—pin the buggy behavior with a comment and file a ticket instead. Downstream code may depend on the wrong behavior, so fix it later as a deliberate, separate behavior-change commit that flips the assertion and the code together.

When should I use Sprout Method or Wrap Method instead of refactoring?▼

Use them when you cannot get the host code under test today. Sprout puts new logic in a fresh, fully tested method or class called from one line in the legacy code; Wrap renames the old method and adds behavior around it, decorator-style.