Unit 16 · lesson

Refactoring Changes Structure, Not Required Behavior

Refactoring improves internal design without intentionally changing externally required behavior.

Examples:

  • extract a method;
  • rename a misleading symbol;
  • replace repeated variables with a collection;
  • move behavior into the object that owns the knowledge;
  • introduce an interface at a real dependency boundary;
  • split a giant class by responsibility.

A refactor can still introduce bugs. That is why tests matter.

Capture behavior first

Before changing structure:

  1. identify required behavior;
  2. make sure tests cover it;
  3. record a baseline;
  4. make one coherent structural change;
  5. run the same tests.

If the requirement is intentionally changing too, separate that feature change from the refactor when possible. Otherwise you cannot tell whether a failing test comes from new behavior or broken old behavior.

Example: duplicated classification

Before:

if (score >= 90) {
    IO.println("HIGH");
} else if (score >= 70) {
    IO.println("PASS");
} else {
    IO.println("RETRY");
}

and later the same logic appears again.

Extract:

String classify(int score) {
    if (score >= 90) return "HIGH";
    if (score >= 70) return "PASS";
    return "RETRY";
}

Now the rule has one named location and a clean test boundary.

But note: the extracted version shown above still lacks the invalid-range rule from Unit 4. Refactoring duplicated code can preserve a duplicated defect. Tests must reflect the real requirement, not simply prove both versions behave the same.

Smell is a clue, not a command

Common clues:

  • method is difficult to summarize;
  • repeated conditional rules;
  • many parameters that belong to one concept;
  • class changes for unrelated reasons;
  • caller knows concrete implementation details it does not need;
  • same data travels through many loosely related parameters.

Do not perform a mechanical refactor merely because a code-smell list says so. State the design problem you are trying to reduce.

Measure improvement qualitatively

You do not need a fake numeric "clean code score."

Use evidence like:

one rule now has one implementation
caller now depends on interface instead of concrete class
method contract is now testable in isolation
class no longer owns formatting and persistence
parameter list replaced by a coherent domain object

Refactor challenge

Take a working program from an earlier checkpoint. Choose one structural problem.

Before editing, run its regression set.

Refactor one boundary.

Run the same set.

Then add one new test made easier by the improved structure.

Evidence

Show a before/after responsibility or call diagram, not only code diffs.

Explain what knowledge moved, what behavior stayed fixed, and which tests support the claim that the refactor preserved requirements.