People refer to all kinds of changes to existing code as refactoring, which is a common case of semantic diffusion.
Like many terms in software development, “refactoring” is often used very loosely by practitioners.
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.
General Definition of Refactoring
In my refactoring book, I gave a couple of definitions of refactoring.
Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior.
Refactoring (verb): to restructure software by applying a series of refactorings without changing its observable behavior.
Martin Fowler
“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:
A refactoring is a “behavior-preserving transformation” […]
Joshua Kerievsky
Refactoring to Patterns (p. 66).
Pearson Education. Kindle Edition.
Similarly, Michael Feathers defines and explains refactoring in Working Effectively with Legacy Code:
The act of improving design without changing its behavior is called refactoring. […] we are making a series of small structural modifications, supported by tests to make the code easier to change.
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:
In my definitions, I use the phrase “observable behavior.” This is a deliberately loose term, indicating that the code should, overall, do just the same things it did before I started. It doesn’t mean it will work exactly the same—for example, Extract Function (106) will alter the call stack, so performance characteristics might change—but nothing should change that the user should care about.
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.
Rewriting, reworking, and re-architecting code is collectively known as restructuring. But there’s a subset of that activity that has become practiced as refactoring.
[…]
Refactoring is not intended to be a special, high-ceremony, once-in-a-while activity, like plowing under the whole garden in order to replant. Instead, refactoring is a day-to-day activity, taking low-risk small steps, more like weeding and raking. Instead of a free-for-all, wholesale rewrite of the codebase, it’s a targeted, precision approach to help keep the code easy to change.
In order to guarantee that the external behavior hasn’t changed, you need good, automated unit testing that validates the behavior of the code.David Thomas, Andrew Hunt
The Pragmatic Programmer (p. 372)
Pearson Education. Kindle Edition.
Refactoring, as with most things, is easier to do while the issues are small, as an ongoing activity while coding. You shouldn’t need “a week to refactor” a piece of code—that’s a full-on rewrite.
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.
I use “restructuring” as a general term to mean any kind of reorganizing or cleaning up of a code base, and see refactoring as a particular kind of restructuring.
Martin Fowler
Refactoring: Improving the Design of Existing Code (p. 46).
Pearson Education. Kindle Edition.
Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior.
Its heart is a series of small behavior preserving transformations. Each transformation (called a “refactoring”) does little, but a sequence of these transformations can produce a significant restructuring. Since each refactoring is small, it’s less likely to go wrong. The system is kept fully working after each refactoring, reducing the chances that a system can get seriously broken during the restructuring.
Martin Fowler
refactoring.com
It’s long been one of my pet peeves that people use refactoring as a synonym for restructuring something. Refactoring is a very particular process that uses a series of small semantics-preserving transformations to change a code base. It’s quite a particular and disciplined process. There are other ways to restructure code, beneficial or not these are not refactoring.
Martin Fowler
[…] the term “refactoring” is often used when it’s not appropriate. If somebody talks about a system being broken for a couple of days while they are refactoring, you can be pretty sure they are not refactoring. If someone talks about refactoring a document, then that’s not refactoring. Both of these are restructuring. […]
Refactoring is a very specific technique, founded on using small behavior-preserving transformations (themselves called refactorings). If you are doing refactoring your system should not be broken for more than a few minutes at a time, and I don’t see how you do it on something that doesn’t have a well defined behavior.Martin Fowler
Refactoring isn’t another word for cleaning up code – it specifically defines one technique for improving the health of a code-base. I use “restructuring” as a more general term for reorganizing code that may incorporate other techniques.
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.
Refactoring changes the programs in small steps, so if you make a mistake, it is easy to find where the bug is.
Martin Fowler
Refactoring: Improving the Design of Existing Code (p. 8).
Pearson Education. Kindle Edition.
So I might spend a couple of hours refactoring, during which I would apply a few dozen individual refactorings.
Martin Fowler
Refactoring: Improving the Design of Existing Code (p. 45).
Pearson Education. Kindle Edition.
If someone says their code was broken for a couple of days while they are refactoring, you can be pretty sure they were not refactoring.
Martin Fowler
Refactoring: Improving the Design of Existing Code (p. 46).
Pearson Education. Kindle Edition.
Refactoring changes the programs in small steps, so if you make a mistake, it is easy to find where the bug is.
Martin Fowler
Refactoring: Improving the Design of Existing Code (p. 8).
Pearson Education. Kindle Edition.
I emphasize the safe way of doing the refactoring—which is to take very small steps and test after every one. At work, I usually take larger steps than some of the baby steps described, but if I run into a bug, I back out the last step and take the smaller steps.
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?
There is another way to deal with the testing problem. If I use an environment that has good automated refactorings, I can trust those refactorings even without running tests. I can then refactor, providing I only use those refactorings that are safely automated. This removes a lot of nice refactorings from my menu, but still leaves me enough to deliver some useful benefits. I’d still rather have self-testing code, but it’s an option that is useful to have in the toolkit.
[…]
teams using [certain language-specific automated refactorings] have found they can do useful refactoring on large code bases with poor test coverage. I don’t focus on that in this book, as it’s a newer, less described and understood technique that involves detailed, language-specific activity.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.
Because refactoring is the act of performing behavior-preserving transformations, you might think that you would not need to run test code after you perform an automated refactoring. Well, you do, much of the time. You may have complete confidence in your automated refactoring tool for some refactorings, while you may not completely trust it for other refactorings.
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.
When you have a tool that does refactorings for you, it’s tempting to believe that you don’t have to write tests for the code you are about to refactor. In some cases, this is true. If your tool performs safe refactorings and you go from one automated refactoring to another without doing any other editing, you can assume that your edits haven’t changed behavior. However, this isn’t always the case.
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.
Refactorings were invented by William Opdyke in his 1992 PhD thesis, “Refactoring Object-Oriented Frameworks”, and became popular after Fowler’s book. They have evolved since Fowler’s definition. Most modern IDEs support automatic refactorings. These are safe and make structural changes without changing the behavior of the system.
Maximiliano Contieri
Clean Code Cookbook (p. 15).
O’Reilly Media. Kindle Edition.
Refactoring.com, published by Martin Fowler, says this about refactoring tools:
Automated tools are helpful, but not essential
When I wrote the first edition of Refactoring, back in the late 90’s, there were few automated tools that supported Refactoring. Now many languages have IDEs which automate many common refactorings. These are a really valuable part of my toolkit allowing me to carry out refactoring faster. But such tools aren’t essential – I often work in programming languages without tool support, in which case I rely on taking small steps, and using frequent testing to detect mistakes.
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.

