Skip to main content

Module 2: Refactoring Techniques

Primary text: Refactoring: Improving the Design of Existing Code (Fowler, 2nd edition) Selective support: Working Effectively with Legacy Code ideas (seams, enabling points), Clean Code for readability pressure, Good Code, Bad Code for engineering judgment around rollout

This guide is the primary teacher. You do not need to read Fowler's catalog front-to-back to complete this module. You do need to become operational at naming a refactor move, executing it in small behavior-preserving steps, proving behavior is preserved by tests, and knowing when to stop.


Scope of This Module

This module is not a pattern-name trivia quiz. It is where "clean up the code" stops being vague and becomes a named, disciplined sequence of moves under a test harness.

What it covers in depth:

  • the precise definition of refactoring as behavior preservation
  • the two-hats rule that keeps refactoring commits separate from feature commits
  • the three triggers: rule of three, preparatory, comprehension, and opportunistic
  • characterization tests that pin current behavior before any structural change
  • seams and enabling points from Working Effectively with Legacy Code
  • the core Fowler moves: Extract/Inline Function, Extract Variable, Rename, Change Function Declaration, Move Function/Field, Split Phase, Encapsulate Record, Replace Primitive with Object
  • conditional restructuring: Replace Conditional with Polymorphism, Decompose Conditional, Consolidate Conditional Expression
  • API reshaping: Introduce Parameter Object, Preserve Whole Object
  • large-scale strategies: Branch by Abstraction, Parallel Change, Strangler Fig

What it deliberately does not try to finish here:

  • the full Fowler catalog of seventy-plus refactorings
  • comprehensive legacy-code recovery techniques (Module 5 and future)
  • design patterns as destinations (that is Modules 3 and 4)
  • team-process choreography like feature branching and trunk-based development (Track B)

This is the operational core. If you can quote the names but cannot execute the moves without breaking tests, you are not done.


Before You Start

Answer these closed-book before starting the main path:

  1. What is the difference between "cleaning up code" and "refactoring" as Fowler defines it?
  2. Why is it a rule to never add a feature and refactor in the same commit?
  3. What does a characterization test assert, and why is that different from a regular unit test?
  4. If you cannot test a function because it calls the network, what structural change gives you a place to intervene?
  5. When is Replace Conditional with Polymorphism the wrong move?

Diagnostic Interpretation

4-5 solid answers

  • You are ready for the full path.

2-3 solid answers

  • Continue, but expect extra time in Cluster 2 (safety net) and Cluster 4 (conditional restructuring).

0-1 solid answers

  • Revisit S3M1 smells first. Refactoring is the answer to smells; if you cannot name the smell, the move is arbitrary.

What This Module Is For

Refactoring is the mathematical language of safe change. Every real codebase asks questions like:

  • how do I clean up this 300-line function without breaking the existing callers?
  • how do I add a new feature when the shape of the existing code fights me?
  • how do I get this untested legacy class under test before I change it?
  • how do I replace a library dependency without a six-month branch?
  • which of the ten code smells I just spotted should I fix first?

This module builds the change-safety skills needed for:

  • Module 3 and 4, where patterns are often introduced by refactoring, not written from scratch
  • Module 5, where code review depends on being able to read diffs move by move
  • real production work, where the "big rewrite" almost always ends badly and the incremental replacement almost always wins

You are learning to reshape running code without stopping it.


Concept Map


How To Use This Module

Work in order. Later clusters assume the discipline and test habits from earlier ones.

Cluster 1: The Refactoring Discipline

OrderConceptTypeFocus
1Refactoring Is Behavior PreservationPRIMARYFowler's precise definition and why "any cleanup" is not refactoring
2The Two Hats: Refactor or Feature, Never BothPRIMARYKent Beck's metaphor as a commit-level discipline
3When to Refactor: Rule of Three, Preparatory, Opportunistic, ComprehensionPRIMARYThe four triggers and why scheduled "refactoring sprints" usually fail

Cluster mastery check: Can you explain why a commit labeled "refactor and fix bug" is a defect in the commit itself?

Cluster 2: Tests as a Safety Net

OrderConceptTypeFocus
4Characterization Tests: Pin Behavior Before ChangePRIMARYCapturing current behavior, including bugs, as the baseline
5Legacy Seams and Enabling PointsPRIMARYFeathers' vocabulary for breaking dependencies without editing everywhere
6Test Granularity: Unit vs Integration During a RefactorSUPPORTINGWhich level of test actually protects which kind of move

Cluster mastery check: Can you name a seam in code you wrote this week and the enabling point that would activate a stub?

Cluster 3: Fundamental Refactor Moves

OrderConceptTypeFocus
7Extract Function and Inline FunctionPRIMARYThe intention/implementation split and its inverse
8Extract Variable, Rename, Change Function DeclarationPRIMARYNaming as a refactor discipline, not a cosmetic
9Move Function, Move Field, Split PhasePRIMARYRelocation moves that fix coupling and sequential-phase tangles
10Encapsulate Record and Replace Primitive with ObjectPRIMARYGiving anonymous data a home and behavior

Cluster mastery check: Can you execute Extract Function on a 40-line function in 10 minutes with every test still green?

Cluster 4: Reorganizing Data and Logic

OrderConceptTypeFocus
11Replace Conditional with PolymorphismPRIMARYTurning recurring switch statements into type-dispatched behavior
12Introduce Parameter Object and Preserve Whole ObjectSUPPORTINGShrinking parameter lists by letting data clumps become types
13Decompose and Consolidate ConditionalSUPPORTINGExtracting the "why" from tangled branches; combining parallel branches

Cluster mastery check: Can you decide between polymorphism, parameter object, and a decomposed conditional for a given smelly function, and justify the choice?

Cluster 5: Refactoring Large Changes and Rollout

OrderConceptTypeFocus
14Branch by Abstraction and Parallel ChangePRIMARYKeeping the system shippable through a multi-week change
15Incremental Strangler Refactors in ProductionSUPPORTINGReplacing a legacy component while users are still using it

Cluster mastery check: Can you sketch how to replace a hand-rolled ORM with a library in a system shipped three times a week, without a two-month branch?

Then work these practice pages:

OrderPractice pathFocus
1Behavior Preservation LabCharacterization tests and seam identification
2Small Refactor Moves WorkshopExtract, inline, rename, move drills with tests green
3Conditional and Data Restructuring ClinicPolymorphism, parameter objects, decomposed conditionals
4Code KatasSix to eight refactor katas with real before/after code

Use Module Quiz after the concept and practice path. Use Reference and Selective Reading and Learning Resources only for targeted reinforcement.


Learning Objectives

By the end of this module you should be able to:

  1. State Fowler's definition of refactoring and explain what "observable behavior" rules in and out.
  2. Keep refactor and feature commits separate and explain the cost of mixing them.
  3. Choose between rule-of-three, preparatory, opportunistic, and comprehension refactoring as triggers.
  4. Write characterization tests for a function whose current behavior is not documented.
  5. Identify seams in legacy code and name the enabling point for each seam.
  6. Execute Extract Function, Inline Function, Extract Variable, Rename, and Change Function Declaration without breaking tests.
  7. Execute Move Function, Move Field, and Split Phase on code where the module boundary was wrong.
  8. Execute Encapsulate Record and Replace Primitive with Object to give data a home.
  9. Replace a recurring type-switch with polymorphism, and know when not to.
  10. Introduce Parameter Object, Preserve Whole Object, Decompose Conditional, and Consolidate Conditional Expression deliberately.
  11. Plan a large-scale change using Branch by Abstraction, Parallel Change, or a Strangler Fig, keeping the system shippable throughout.

Outputs

  • a refactoring journal with at least 15 named moves applied to real code, each with a before/after diff and a test log
  • one characterization-test set for at least one function you did not write
  • one seam-identification memo naming at least 5 seams and their enabling points in code you work with
  • one mixed-commit-audit: find a PR that mixes refactor and feature, and rewrite its commit history into clean refactor-only and feature-only commits
  • one "kata log" where each of the six to eight katas has been completed at least twice
  • one large-change plan for a real system you use, choosing between Branch by Abstraction, Parallel Change, and Strangler Fig with written justification
  • one mistake log naming at least 10 real refactor mistakes (e.g., changed behavior in a rename, introduced a bug during Extract Function because of aliasing, applied polymorphism with only one subclass)

Completion Standard

You have completed Module 2 when all of these are true:

  • you can name the move before you do it
  • you run tests between every refactor step, not just at the end
  • your refactor commits do not contain feature code, and vice versa
  • you can characterize a legacy function with tests before you touch it
  • you can point to a seam in real code and say "here is the enabling point"
  • you can talk someone out of Replace Conditional with Polymorphism when the conditional is not recurring
  • you can propose a large-scale change without a multi-week dark branch

If you can do the moves but cannot explain why one move is better than another for a given smell, the module is not complete.


Reading Policy

  • Concept pages are the main path.
  • The Refactoring book chunks are selective reinforcement, not a second syllabus.
  • Read only if stuck means try the concept page, self-check, and drill first.
  • Optional deep dive means additional nuance or alternate examples, not required progression.
  • External Fowler articles are cited only where they add something the book chunks do not already carry.

Suggested Weekly Flow

DayWork
1Concepts 1-3; write the two-hats contract and pin it to the repo
2Concepts 4-6; characterize a function you did not write
3Concepts 7-8; Extract Function / Rename katas
4Concepts 9-10; Move Function / Split Phase drills
5Concepts 11-13; conditional restructuring clinic
6Concepts 14-15; large-change plan
7Practice pages, quiz, mistake-log cleanup

Reference

If you need exact links into the local chunked books, use Reference and Selective Reading.


Rich Learning Pages

Worked Examples | Guided Labs | Case Studies | Mistake Clinic | Reading Guide | Capstone Thread


Model Artifact Calibration

For reviewable refactoring evidence, compare your writeup to the refactor PR model artifact.