Refactoring Basics

Expected level: Working

Refactoring is restructuring existing code to make it easier to understand and change, without altering what it does for its users. It is done in small steps, each leaving the program working.

What counts as refactoring

Refactoring changes the structure of code and leaves its behaviour alone. Renaming a variable, extracting a block into a well-named function and removing duplication are refactorings. Fixing a bug, adding a feature or changing output are not; they change behaviour, and mixing them in makes both harder to review.

How to keep behaviour the same

You need a way to tell whether behaviour changed:

  • Automated tests that cover the code you are about to touch. If there are none, write a few that capture current behaviour first (see Unit Testing).
  • Small steps: change one thing, run the tests, repeat.
  • Version control: commit after each working step so you can undo (see Undoing Mistakes).
  • Your editor’s refactoring tools: rename, extract and move operations are safer than manual edits.

Common refactorings

  • Rename for clarity (see Clean Code and Naming).
  • Extract a function from a long block, or inline one that adds nothing.
  • Remove duplication by sharing code, but only when the copies really mean the same thing.
  • Simplify conditions, for example with early returns.
  • Move code to where it belongs, improving modularity.
  • Delete dead code; version control remembers it.

When and how much

Refactor when it helps the work in front of you: before adding a feature to messy code, or while reviewing and fixing. Keep refactoring commits separate from feature commits (see Commit Hygiene) and keep pull requests small enough to review. Large rewrites with no safety net are risky and rarely finish. Refactoring is also one way to pay down technical debt.

Try it

Find a function of 30 or more lines in a codebase with tests, or write a few tests for it first. Rename two unclear variables and extract one block into a named function. Run the tests after each step and commit each separately.

Common mistakes

  • Mixing bug fixes or new features into a refactoring.
  • Refactoring code that has no tests and no safety net.
  • Merging code that only looks the same but means different things.
  • Starting a large rewrite instead of small steps.

Check yourself

  • Why is fixing a bug not a refactoring?
  • What do you need before refactoring code safely?
  • Why keep refactoring commits separate?

Related topics

Terms

Further reading