Raimund Krämer

Software Craftsman, Consultant, Coach

People refer to all kinds of changes to existing code as refactoring, which is a common case of semantic diffusion.

Martin Fowler

Refactoring: Improving the Design of Existing Code (p. 45).
Pearson Education. Kindle Edition.

If you hear a term misused often enough, or before you are familiar enough with it to recognize the incorrect use, the misunderstanding or partial understanding is only reinforced.

Is a certain use of the term correct or not? Who is the definitive authority on refactoring? There may not be a single one, and how a term is used can vary between different groups of people or even change over time. However, if there weren’t a correct definition, we wouldn’t need to care about a precise meaning of the term either way. Martin Fowler, author of the 1999 book Refactoring: Improving the Design of Existing Code, may be as close as it gets to a definitive source. This article tries to clear up some of the confusion and myths around the term by quoting Fowler and other authors.

  1. General Definition of Refactoring
  2. Refactoring vs. Restructuring
  3. Small Steps
  4. Test Coverage
  5. Conclusion

General Definition of Refactoring

Martin Fowler

https://martinfowler.com/bliki/DefinitionOfRefactoring.html

“A change made to the internal structure of the software […] without changing its observable behavior.” This is probably the most common definition of refactoring. Note the explicit mention of “internal structure” and “observable behavior”.

Joshua Kerievsky, author of Refactoring to Patterns, provides a very similar definition:

Joshua Kerievsky

Refactoring to Patterns (p. 66).
Pearson Education. Kindle Edition.

Similarly, Michael Feathers defines and explains refactoring in Working Effectively with Legacy Code:

Michael Feathers

Working Effectively with Legacy Code (p. 5).
Pearson Education. Kindle Edition.

Fowler clarifies his use of observable behavior as something the user cares about, but not necessarily anything someone might observe through technical means:

Martin Fowler

Refactoring: Improving the Design of Existing Code (p. 46).
Pearson Education. Kindle Edition.

This makes sense, because if we were pedantic enough, we could say that at least some people (with the technical means and know-how) could “externally” observe changes by measuring the tiniest performance differences or even analyzing memory access patterns. However, the statement by Fowler clarifies that redesigning or restructuring a UI is an externally observable change in behavior. If I move a button into a different menu, the user will definitely notice a different behavior when opening the GUI menu where they expected the button to be. The user also doesn’t care whether the GUI change happened “just in the presentation layer” or “only in markup”, as long as the behavior is different than what they expected.

When used as a verb: “To restructure software by applying a series of refactorings […]” Note the distinction between restructuring and refactoring being mentioned even in the very definition of refactoring. It already implies that refactoring is one way of restructuring software and usually involves a series of individual refactorings.

Refactoring vs. Restructuring

A common confusion is the use of refactoring to refer to any kind of structural changes.

David Thomas, Andrew Hunt

The Pragmatic Programmer (p. 372)
Pearson Education. Kindle Edition.

David Thomas, Andrew Hunt

The Pragmatic Programmer (p. 374)
Pearson Education. Kindle Edition.

Refactoring is a subset of restructuring, but a very specific and disciplined one.

Martin Fowler

Refactoring: Improving the Design of Existing Code (p. 46).
Pearson Education. Kindle Edition.

Martin Fowler

refactoring.com

Martin Fowler

https://martinfowler.com/bliki/RefactoringCringely.html

Martin Fowler

https://martinfowler.com/bliki/RefactoringMalapropism.html

Martin Fowler

refactoring.com

Small Steps

While large changes could theoretically be behavior-preserving, refactoring is in practice usually done in small steps, each one being a behavior-preserving transformation. Even when refactoring over longer periods of time, it involves many smaller individual refactorings, each of them by definition keeping the existing behavior in place.

Martin Fowler

Refactoring: Improving the Design of Existing Code (p. 8).
Pearson Education. Kindle Edition.

Martin Fowler

Refactoring: Improving the Design of Existing Code (p. 45).
Pearson Education. Kindle Edition.

Martin Fowler

Refactoring: Improving the Design of Existing Code (p. 46).
Pearson Education. Kindle Edition.

Martin Fowler

Refactoring: Improving the Design of Existing Code (p. 8).
Pearson Education. Kindle Edition.

Martin Fowler

Refactoring: Improving the Design of Existing Code (p. 102).
Pearson Education. Kindle Edition.

So while there are techniques for achieving even large structural changes and even over longer periods of time via many individual refactorings, simply rewriting parts of a system with a new architecture or even different technologies can’t really be considered refactoring.

Test Coverage

You might hear someone redefining refactoring, claiming that without test coverage it can’t be considered refactoring by definition. However that is a misconception. While such a statement may even have occurred in the first edition of the Refactoring book (I’ve only read the second edition), that was at a time where the tooling landscape was different. More likely, it is an incorrect assumption by some, inferred from the definition that the observable behavior must remain unchanged when refactoring, since tests are one way of increasing confidence in the behavior staying the same. What if there were other ways to ensure unchanged behavior?

Martin Fowler

Refactoring: Improving the Design of Existing Code (pp. 59-60).
Pearson Education. Kindle Edition.

As long as we adhere to the rule that the observable behavior remains unchanged, we can use certain IDE-provided automated refactorings or even the compiler and type system to safely refactor even without tests, but the available tooling varies greatly depending on language and frameworks. This also does not diminish the value of tests in those cases, but in some situations we might need to deal with low test coverage already in place.

Kerievsky makes a similar statement about some automated refactorings. He also implies that according to his definition of refactoring (which matches Fowler’s), what matters are the behavior-preserving transformations, with tests being one tool for increasing confidence.

Joshua Kerievsky

Refactoring to Patterns (p. 66).
Pearson Education. Kindle Edition.

Consequently, while tests are helpful and recommended, saying that changing code without tests in general is not refactoring by definition is a misconception, and instead it depends on the exact circumstances. For example, one might inherit a legacy code base without tests and need to safely refactor to a more testable design to add some test coverage in the first place using certain automated refactorings or techniques described by, e.g., Michael Feathers in Working Effectively with Legacy Code.

Feathers also mentions safe automated refactorings. His statement is similar to Fowler’s and Kerievsky’s.

Michael Feathers

Working Effectively with Legacy Code (p. 46).
Pearson Education. Kindle Edition.

Maximiliano Contieri also has something to say about the evolution of refactoring support in IDEs in his book Clean Code Cookbook.

Maximiliano Contieri

Clean Code Cookbook (p. 15).
O’Reilly Media. Kindle Edition.

Refactoring.com, published by Martin Fowler, says this about refactoring tools:

Martin Fowler

refactoring.com

Conclusion

I hope this helped clarify some confusion. Words matter, and if we use well-established technical terms sloppily, we lose precision in meaning and cause misunderstandings. These misunderstandings then lead to less than ideal behaviors and practices.

If someone sent this article to you, consider paying it forward by sharing it with someone who also benefits from a more precise understanding. If your team has different understandings of what it means to refactor code, perhaps the information and quotes above help create a common understanding in your team.