software-design-plugin/skills/design-legacy-seams/SKILL.md
Get legacy code under test before changing it — find seams, write characterization tests. Use when changing untested code, breaking dependencies, or taming legacy.
npx skillsauth add laurigates/claude-plugins design-legacy-seamsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
From Working Effectively with Legacy Code (Feathers): legacy code is code without tests. The dilemma is circular — to change it safely you need tests, but to test it you often need to change it. The way out is to find a seam (a place where behaviour can be altered without editing in-line) to break the dependency that makes the code untestable, then pin the current behaviour with characterization tests before you touch logic.
The sequence is non-negotiable: get it under test first, change it second. Characterization tests document what the code does (not what it should do), so a refactor that preserves behaviour stays green and a behaviour change shows up as a deliberate, reviewed diff.
| Use this skill when... | Use something else instead when... |
|---|---|
| About to modify untested code and want a safety net first | The code already has good tests → code-quality-plugin:code-review |
| A dependency (DB, clock, network, global) blocks unit testing | Judging test quality of existing tests → code-quality-plugin:code-test-quality |
| Pinning current behaviour before a risky refactor | A large multi-phase refactor → workflow-orchestration-plugin:workflow-checkpoint-refactor |
| Breaking a hidden dependency to inject a fake | Diagnosing a live bug → code-quality-plugin:debugging-methodology |
| Seam type | Where you alter behaviour | Typical use | |---|---|---| | Object seam | Override a method / inject a collaborator | Replace a real dependency with a fake (most common) | | Link seam | Swap a library/module at build/link time | Stub a third-party at the boundary | | Preprocessing seam | Macro/build substitution before compile | Last resort in C/C++-style builds |
Two enabling moves when no seam exists yet: Extract & Override (pull the hard-to-test work into a method, subclass in the test to override it) and Parameterize Constructor/Method (pass the dependency in instead of constructing it inside). Both are tiny, behaviour-preserving, and create the seam the test needs.
Parse $ARGUMENTS:
git diff HEAD +
staged) and say so.Execute this get-under-test workflow:
Locate where the behaviour change is needed. List the dependencies that make it hard to test now — constructed-inside collaborators, global/singleton state, clocks, randomness, I/O, network, static calls.
For each blocking dependency, identify the cheapest seam:
Make only the smallest behaviour-preserving edit needed to open the seam. Note
that the seam you introduce is often an Adapter (see
software-design-plugin:design-patterns).
Pin the current behaviour, not the intended behaviour:
With the net in place, make the intended change; the characterization tests that should still hold stay green, and the ones that intentionally change become a reviewed diff. Report: the change point, the seam(s) opened (type + the minimal edit), the characterization tests added, and any surprising current behaviour the characterization surfaced.
| Mistake | Correct approach | |---|---| | Refactoring untested code "carefully" by hand | Get it under test first — careful is not a safety net | | Writing tests for what the code should do | Characterize what it does; behaviour change comes after | | A giant rewrite to make one method testable | Smallest seam-opening edit (Extract & Override / Parameterize) | | "Fixing" a surprising behaviour mid-characterization | Flag it; change behaviour as a separate, deliberate step |
| Blocker | Seam move | |---|---| | Collaborator constructed inside | Parameterize Constructor | | Hard call buried in a method | Extract & Override | | Global / singleton / clock | Inject via an object seam | | Untouchable third-party | Link seam / Adapter at the boundary | | Need to pin behaviour | Characterization test asserting current output |
code-quality-plugin:code-test-quality — once under test, judge whether those
tests are good (this skill only gets them present)software-design-plugin:design-patterns — the seam you open is often an
Adapter; Extract & Override leans on subclassingworkflow-orchestration-plugin:workflow-checkpoint-refactor — the multi-phase
refactor this safety net unblockscode-quality-plugin:debugging-methodology — a characterization test is also a
reproduction harness for a legacy bugdevelopment
Debug HTTP APIs: trace requests, inspect headers. Use when a request fails: check status first.
documentation
Render architecture diagrams from text sources. Use when documenting system topology.
tools
Inspect JSON payloads and extract nested fields. Use when parsing API responses.
tools
--- name: no-description allowed-tools: Read --- # No Description This skill has no description and must be dropped with a warning.