Safe Legacy Editing Discipline
by @quochungto
Apply 4 editing disciplines when modifying legacy code: Hyperaware Editing, Single-Goal Editing, Preserve Signatures, Lean on the Compiler. Use whenever a de...
(a) Java developer about to add a parameter to a legacy method with no tests
Situation: A Java developer needs to add a locale parameter to a 200-line method InvoiceFormatter.format(Invoice invoice) that has no tests.
Step 1 (context): Untested-bootstrap. There are no tests. This is initial dependency-breaking work.
Step 2 (anti-pattern): Edit-and-Pray risk β the developer plans to add the parameter and then "test it manually by running the UI." Name the pattern and flag it.
Step 3 (Hyperaware): Adding a new parameter is behavior-changing. Every call site that currently compiles with one argument will break. Every place that constructs the string output may now differ. High-risk edits β note them explicitly.
Step 4 (Single-Goal): Write: "Goal: add Locale locale parameter to format() and thread it to the one callsite that needs it." While reading the method, the developer notices three other parameters that "should really be an object." Write them on the deferred list. Do not act on them now.
Step 5 (Preserve Signatures): Copy Invoice invoice from the current signature. Type public String format( then paste, add , Locale locale). Do not retype. Do not reorder. Do not rename invoice to inv.
Step 6 (Lean on the Compiler): The compiler error list after adding the parameter reveals 7 call sites, not the 2 the developer thought existed. Update all 7 before checking inheritance (no superclass has a format() method β confirmed via Grep).
Result: The parameter is threaded through all 7 call sites. No signature mutations were introduced. 5 deferred cleanup items are on paper. The code compiles. The developer can now write a characterization test.
(b) Team stuck in Minimization Freeze rationalization
Situation: A tech lead says: "Our core billing class has 800 lines. We can't add tests without refactoring, but we don't want to refactor because something might break. The policy is: if it's not broke, don't fix it."
Step 2 (anti-pattern): This is Minimization Freeze combined with Legacy Code Dilemma. Name both.
The inversion to surface: "It involves less editing, and it's safer" is backwards. Every future change to the 800-line class is made without any safety net. The cumulative risk grows with every undisciplined edit. True safety requires more edits (to create seams), not fewer.
The path out of Legacy Code Dilemma: Conservative dependency-breaking techniques (from Chapter 25) are designed specifically to be safe enough to apply without tests. They are not general refactoring β they are a bootstrap protocol. Apply one conservative technique (e.g., Parameterize Constructor), confirm it compiles, write the first test against the newly isolated code. The circularity is broken at the first test.
Single-Goal application: The first goal is not "clean up the billing class." It is: "break one dependency so we can write one test." Write that as the goal. Everything else is deferred.
(c) C++ developer encapsulating globals via Lean on the Compiler
Situation: A C++ developer wants to encapsulate two global variables (domestic_exchange_rate, foreign_exchange_rate) into a class so they can be substituted in tests.
Step 1 (context): Untested-bootstrap. Encapsulating globals IS a dependency-breaking technique. No tests yet.
Step 5 (Preserve Signatures): The globals are variables, not methods. The principle still applies: the new class fields should have identical names (domestic_exchange_rate, foreign_exchange_rate), not renamed versions.
Step 6 (Lean on the Compiler):
1. Comment out both global variable declarations
2. Compile β 34 errors across 9 files
3. Navigate to each error; prefix the reference with exchange.
4. Re-compile β 0 errors
Inheritance check: These are global variables, not class methods. Inheritance masking does not apply. The compiler's 34 errors are the complete set of usages.
Result: All 34 usages updated mechanically. No manual search required. The change is ready for a characterization test of the exchange rate behavior.
clawhub install bookforge-safe-legacy-editing-discipline