Why and When should I refactor?

I recently bought the second edition of Refactoring by Martin Fowler, I like it a lot.
Last year I did a talk about refactoring with some thoughts I had: use ubiquitous language from Domain Driven Design to write code; apply visual design principles to identify code smells to start; and lastly refactor often.
I thought it is a good time to review the book and summarize what I learned in the past few months about refactoring.
The purpose of building systems is to continue playing the game. True long term thinking is goalless thinking. It is not about one single accomplishment, it is about a cycle of endless refinement and continuous improvement. It is your commitment to the process that will determine your progress.
- James Clear, “Atomic Habits”
What is Refactoring?
I find that refactoring becomes a loose concept term, similar as changing code for a better structure, where we miss some very important characteristics of it: it does not alter the external behaviors, and thus it needs to be done in a systematical disciplined way.
Refactoring is the process of changing a software system in a way that does not alter the external behavior of the code yet improves its internal structure.
- Martin Fowler, “Refactoring: Improving the Design of Existing Code”
Martin did a talk recently at Etsy Code as Craft Speaker Series, where he said: “Refactoring is a series of small changes that each change is so small that they are not worth doing it, but doing a whole bunch of them you are going to make a big change. ” This is also what DHH retweeted: small changes and programming habits.
So I think refactoring is a systematic and disciplined approach to change the internal structure of the code without changing the external behavior, such that “it makes the change easier.” Doing it often helps us to create good programming habits to write cleaner code and can continuously improve.
Why Refactoring?
In Martin’s book, there is a section on “Why should we refactor?” in Chapter 2. It talks about perspectives that refactoring improves the design of software; refactoring makes software easier to understand; refactoring helps me find bugs; and refactoring helps me program faster.
What resonates me most is that refactoring makes software easier to understand. As the software engineer who spent the past 8 years on legacy code bases, I spent more time reading and modifying the existing code than developing new code. I advocate that we should be more compassionate in coding to make our future self and others’ life easier. Making code easier to understand will save countless hours of future maintainers. My colleague and friend at work shared this article coding with empathy the other day. It reminds me of Sarah Mei’s talk Livable Code: The important part of software is not the code and the important part of software is not the people. It is code and people. Software engineering is working with other humans through code.
Making software easier to understand has multiple benefits: it makes the path to evolve a better design more visible; it accumulates domain knowledge as the code itself is the documentation; it removes accidental complications thus will improve our estimation of adding a new feature.
When to Refactor?
To avoid digging your own grave, refactoring must be done systematically.
In the book there is also a section about “When should we Refactor?”
From my experience working on product teams, the best strategy to use to do a “big” refactoring is “to refactor just before I need to add a new feature to the code base” and “make the change easier and then make the easy change.”
Take every opportunity, such as when investigating a production issue, fixing a bug, writing a design documentation etc., to do small “unworthy” refactoring changes to make the code easier to understand, such as renaming, extract methods, formatting, and align code so that it is easier to scan.
Before we change any code structures, make sure we have tests in place. If not, we need to start with characterization tests to capture the existing system behavior. Learn the systematic steps of refactoring outlined in the book so that we are able to make small changes every time instead of burying down in the rabbit hole.
Refactoring is good learning experience to understand the system better and end up making the system easier to understand. When we don’t understand our code, it is an invitation to do some refactoring.