# Legacy Code Expert

> Safely modify legacy code lacking tests. Identifies seams, breaks dependencies, plans characterization tests. Invoke before verification-protocol when touching untested code with tangled dependencies.

- Skill: `maroffo/legacy-code-expert` (Agent Skill)
- Install (CLI): `npx skillmds@latest add maroffo/legacy-code-expert`
- Raw SKILL.md: https://api.skillmd.com/api/skills/maroffo/legacy-code-expert/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: maroffo (https://skillmd.com/u/maroffo)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/maroffo/legacy-code-expert

---


# ABOUTME: Feathers' dependency-breaking techniques for safely modifying untested legacy code
# ABOUTME: Seam identification, change point analysis, characterization test planning

# Legacy Code Expert

**When to invoke:** before `verification-protocol` (TDD), when the target code lacks tests and has dependencies that block testing. This skill produces the analysis; verification-protocol drives the test-first cycle that follows.

## Workflow

1. **Identify change point** (where the modification goes)
2. **Map dependencies** blocking testability
3. **Find seams** (places to alter behavior without editing production code)
4. **Select techniques** (simplest that works, minimal ripple)
5. **Plan characterization tests** (capture current behavior)
6. **Define transformation steps** (small, reversible)
7. **Hand off to verification-protocol** for TDD execution

## Seam Types

| Seam | Mechanism | Best For | Example |
|------|-----------|----------|---------|
| Object | Polymorphism, interfaces | OOP languages (Java, C#, Go, Ruby) | Extract interface, subclass and override |
| Preprocessing | Macros, conditional compilation | C/C++ | `#ifdef TESTING` to swap implementations |
| Link | Linker substitution, module replacement | C/C++, dynamic languages | Replace `.o` file, monkey-patch module |

**Seam identification questions:**
- Can I substitute this dependency via a constructor or method parameter?
- Is there a virtual/overridable method I can intercept?
- Can I extract an interface the caller depends on?
- Does the language support module-level replacement (mocks, monkey-patching)?

## Dependency-Breaking Techniques

Organized by primary seam type. Prefer techniques higher in each list (simpler, less invasive).

### Object Seams

| Technique | When to Use |
|-----------|-------------|
| **Extract Interface** | Class has concrete dependency; create interface for substitution |
| **Parameterize Constructor** | Dependency created internally; pass it in instead |
| **Parameterize Method** | Single method needs a dependency; pass as argument |
| **Extract and Override Call** | Isolate one problematic call into a virtual method |
| **Extract and Override Factory Method** | Object creation blocks testing; make it overridable |
| **Extract and Override Getter** | Field access blocks testing; route through virtual getter |
| **Subclass and Override Method** | Create test subclass that overrides problematic methods |
| **Extract Implementer** | Move implementation to new class, keep interface in original |
| **Break Out Method Object** | Large method with many dependencies; extract to own class |
| **Adapt Parameter** | Wrap parameter type to break dependency on problematic type |
| **Pull Up Feature** | Move method to superclass to enable override in subclass |
| **Push Down Dependency** | Move dependency to subclass, keep parent testable |
| **Introduce Instance Delegator** | Instance method delegates to static (enables override) |

### Preprocessing/Text Seams

| Technique | When to Use |
|-----------|-------------|
| **Template Redefinition** | Use generics/templates to inject test dependencies |
| **Text Redefinition** | Use macros to redefine dependencies at compile time |
| **Definition Completion** | Provide test implementation for incomplete type |

### Link/Global Seams

| Technique | When to Use |
|-----------|-------------|
| **Encapsulate Global References** | Wrap globals in a class for controlled access |
| **Replace Global Reference with Getter** | Access global through virtual getter |
| **Introduce Static Setter** | Add setter for singleton/global (test-only) |
| **Replace Function with Function Pointer** | Use function pointers for runtime substitution |
| **Link Substitution** | Replace at link time (C/C++ only) |
| **Supersede Instance Variable** | Add setter to replace dependency post-construction |
| **Primitivize Parameter** | Replace object params with primitives to cut dependency |

## Output Format

Produce this analysis, then hand off to verification-protocol:

```
## Legacy Code Analysis: [File/Class]

### Change Point
[Where the modification goes and what behavior changes]

### Dependencies Blocking Testing
- [dependency]: [why it blocks tests]

### Identified Seams
| Seam Type | Location | Exploitation Strategy |
|-----------|----------|-----------------------|
| [type] | [where] | [how to use it] |

### Recommended Techniques
1. **[Technique]**: [one-line rationale]
   - Steps: [ordered list of mechanical changes]
   - Risk: [what could go wrong]

### Characterization Tests
[Tests to lock current behavior BEFORE any changes]
- [test]: calls X with Y, expects Z (current behavior, not ideal)

### Transformation Steps
1. [small, reversible step]
2. [next step]
...
N. Hand off to verification-protocol: write failing test for new behavior
```

## Guidelines

- Safety over elegance: smaller, safer changes win
- Characterization tests capture ACTUAL behavior (bugs included), not ideal behavior
- Goal: get tests in place, not perfect design
- Some debt is acceptable if it enables testing
- When full rewrite is cheaper than incremental change, say so (R4 deviation)
- Document reasoning for future maintainers

