Refactoring & Code Quality

Refactoring & Testing Safety

Refactoring is only as safe as the test suite underneath it: tests are what turn "I'm fairly sure this is equivalent" into "I verified this is equivalent." Without them, the same edits are just changes made on faith.
  • A regression suite is the harness that makes small, frequent refactoring steps verifiable rather than hopeful
  • Legacy code with no tests needs characterization tests first — tests that pin down current behavior (bugs included) before anything is restructured
  • Red-Green-Refactor (from TDD, see Testing Philosophy) is refactoring's most disciplined form: never restructure and add behavior in the same step
  • Coverage percentage is a floor, not a guarantee — 100% coverage with weak assertions can still miss a broken refactor
  • Mutation testing (deliberately introducing small bugs and checking the suite catches them) measures whether tests actually assert something, not just execute the code

A characterization test doesn't test "correct" behavior — it tests current behavior, quirks and all, so that a refactor of unfamiliar legacy code has something to check itself against. Write the test, run it against the untouched code, and record whatever it produces as the expected result — even if that result looks wrong. Only after the refactor is safely underway, with the suite green throughout, does fixing the actual bug become a separate, deliberate step.

The TDD cycle, refactoring's strictest discipline
StepRule
RedWrite a failing test for the next tiny bit of behavior — nothing else
GreenWrite the simplest code that makes it pass — no more
RefactorClean up the result with tests green throughout — no new behavior added here
Sources
  • Refactoring: Improving the Design of Existing Code (2nd ed.)Ch. 4 — Building Tests
  • The Pragmatic Programmer (20th Anniversary ed.)Ch. 5 — Bend, or Break (Testing section)