esteban@devtrillo:~/blog/writing$
← cd -
$ cat refactoring-is-a-discipline.md

Refactoring Is a Discipline, Not a Cleanup

Jul 21, 2026·8 min read
$ tail -f refactoring-is-a-discipline/readers
connecting…

Ask ten engineers what “refactor” means.

You will get ten versions of the same answer: clean it up. Rename some things. Delete the dead code. Do it on a Friday when the sprint is quiet.

That is not what the word means.

When Martin Fowler wrote the book, he gave “refactoring” a definition sharp enough to argue with.1

Refactoring is a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior.

Read that last part again.

Refactoring is a discipline, not a cleanup.

Cleanup is a vibe. You do it when the code annoys you. You stop when it looks nicer. There are no rules.

Refactoring has rules. It has a definition, a safety net, and a rhythm. That is what makes it a discipline — and that is what makes it work.

The word has a definition

Fowler splits the word in two, and the split matters.

There is refactoring the noun: a small, named change to the structure of code. Extract Function. Inline Variable. Move Field. Each one is tiny and each one preserves behavior.

There is refactoring the verb: applying those small changes in a series, one after another, to reshape the whole.

Notice what is missing. Rewriting is not on the list. Rewriting a module over a weekend, breaking it, and gluing it back together is not refactoring. It is a rewrite wearing a nicer word.

CleanupRefactoring
Do it when there’s spare timeDo it to make the next change easy
Stop when it “looks nicer”Stop when behavior is preserved and the step is done
Big edits, then hopeSmall named steps, tests green between each
A phase you scheduleA rhythm woven into every feature

The left column is the thing everyone calls refactoring. The right column is the thing Fowler actually wrote about.

The discipline is small steps

Here is the part that feels wrong the first time you try it.

You do not reshape the code in one confident move. You make one small change. You run the tests. You make the next small change. You run the tests again.

It looks slow. It is not. Small steps mean you are never more than one undo away from working code. You never sit in a broken state wondering which of your forty edits caused the failure, because you only made one.

Kent Beck calls this the “two hats.”2 When you add a feature, you wear the feature hat and you do not touch structure. When you refactor, you wear the refactoring hat and you do not add behavior. You switch hats often. You never wear both.

Scrub through a real one. Same function, reshaped in steps — the badge stays green the whole way, because behavior never changes.

function highRentClients(clients) {
  return clients
    .filter((client) => client.active && client.monthlyRent > 2000)
    .map((client) => client.name);
}

Where it starts: a loop, nested guards, a mutable accumulator.

Nothing there is clever. That is the point. Each step has a name from the catalog, each one is reversible, and at no point did the function stop returning the same answers. If a test had gone red, you would know exactly which two-line move to blame.

NOTE

The steps are not the goal. The steps are how you stay safe while you change the shape. Take them small enough that a mistake is obvious and a revert is free.

Tests are what make it a discipline

There is a reason “without changing observable behavior” is in the definition.

You cannot know behavior stayed the same by staring at the diff. Plausible code looks correct. So do its bugs. The only thing that actually proves behavior held is a suite of tests that passed before your change and passes after it.3

That green bar is not decoration. It is permission. It is the thing that lets you rip a function apart and put it back together without holding your breath. Without tests you are not refactoring — you are editing and hoping, and hoping is not a discipline.

So the honest order of operations is:

If you cannot check every box, you are doing something. It might even be useful. But it is not refactoring, and you should not pretend it carries the same guarantees.

Smells tell you when

If refactoring is a discipline, then “whenever the code annoys me” is not a trigger. You need a real one.

Fowler’s answer is code smells: named, recognizable signals that something in the structure is working against you.4 Long Function. Long Parameter List. Duplicated Code. Feature Envy. Divergent Change. The value of naming them is that a vague “this feels bad” becomes a specific “this is Feature Envy, and the fix is Move Function.”

Each smell points at a refactoring. Here is one of the smallest: a comment explaining a condition is often a smell. The fix is Extract Function — let the name carry the meaning.

The behavior is identical. The reminder still goes out on exactly the same invoices. What changed is that the reason now has a name, and the next person does not have to reconstruct it from an expression.

DEEP DIVEWait — isn't deleting the comment losing information?

No, it moves the information somewhere it can’t rot. A comment sits next to the code and drifts out of sync the moment someone edits the condition and forgets the note. A function name is the code. If isOverdue stops meaning what it says, the name is wrong in a place you can’t ignore. Fowler’s rule of thumb: when you feel the urge to write a comment explaining what a block does, try extracting it into a well-named function instead. Save comments for why.

You refactor to make a change easy

So when do you actually do it? Not on a schedule. Not in a dedicated “refactoring sprint” that never gets approved anyway.

You do it right before you change the code, as part of changing it. Beck’s line is the whole philosophy in one sentence: make the change easy, then make the easy change.5

A feature is hard to add because the code is in the wrong shape? Refactor until the feature is easy — that is a legitimate, tested, behavior-preserving reshaping. Then add the feature. The refactoring is not a detour from the work. It is part of the work.

This is why the discipline pays for itself instead of being a tax. The two moves are separate on purpose — reshape under a green suite, then change behavior. Never both in the same step.

checkout()tax + shipping + discount, all inlinenested ifs three deepthe new rule would go… somewhere in here
checkout()calcTax(order)calcShipping(order)applyDiscount(order, code)

Refactor first. Extract the tangle into named pieces. Structure moves, behavior holds, the suite stays green — no feature added yet.

Now the change is easy. The new rule is one small, obvious line that drops into a shape built to receive it.

Do that every time and the feature is never the scary part. The reshaping absorbs the difficulty up front, in small tested steps, so the change itself stays a one-liner. Skip it and every feature fights the shape of the code — which is how a codebase slowly becomes the thing nobody wants to touch.

TIP

If a refactor can’t point at a change it’s making easier — a feature, a bug, a smell that’s actively blocking you — it can probably wait. Refactoring is preparation, not redecoration.

So, what is refactoring?

It is not the cleanup you do when the sprint is quiet.

It is a small, named change to structure. It is a series of those changes, applied one at a time. It is a green test suite that proves behavior held. It is a smell telling you where, and a feature telling you when.

Rename it in your head. “Refactor” is not “tidy up.” It is “reshape safely, in small steps, without changing what the code does, so the next change is cheap.”

That is a discipline. Treat it like one and it quietly keeps your codebase changeable for years.

Treat it like a cleanup and you will keep waiting for a Friday that never comes.

Footnotes

  1. Martin Fowler, Refactoring, and the definition on his site: Refactoring.

  2. The “two hats” — separating adding function from refactoring — comes from Kent Beck and opens Fowler’s chapter on principles. See Refactoring, 2nd ed., ch. 2.

  3. Fowler devotes a full chapter to this: you build a self-checking test suite before you refactor. See Self-Testing Code.

  4. The phrase “code smell” is credited to Kent Beck. Fowler catalogs them in ch. 3. See CodeSmell.

  5. Kent Beck, “for each desired change, make the change easy (warning: this may be hard), then make the easy change.”