Quoting Ron Jeffries:
One of the ExtremeProgramming practices is to RefactorMercilessly. When you find two methods that look the same, you refactor the code to combine them. When you find two objects with common functionality, you refactor to make there be just one (see ParameterizeMethod). Extreme projects do not use BigDesignUpFront. Therefore they upgrade their designs continuously. RelentlessTesting and ContinuousIntegration (UnitTests synchronized with changes disseminated to other engineers) permit changes that would introduce the risk of bugs in slower projects.[…]
Since we DoTheSimplestThingThatCouldPossiblyWork, sometimes what we do needs improvement an iteration or so down the line. We welcome these opportunities to make the system more like what it should be, and we welcome the fact that we do it in solid knowledge of what is really needed, not what we imagined in the past was needed.
The result of this is that the system is always as simple as we can make it, which means we can understand it better, which means we can change it more rapidly while keeping it reliable.
When I asked Sandi Metz how long a refactoring should take, she said:
Oh, like… a minute? …to tear a class apart into two classes takes a little bit of time, 10 minutes or so.
This is consistent with my own experience, and, I believe, with the intent of the original Red Green Refactor cycle. I think it’s also consistent with the view DHH expressed when the RubyRogues interviewed him: wait until the last minute, until you feel the pain, and then refactor. Immediately.
I’ve watched the meaning of the word “refactoring” drift over the past several years. I don’t know if this is specific to the Ruby community or a larger problem in the software industry. But on nearly every project I’ve been on, I’ve heard statements like this in iteration planning meetings:
Oh, this feature is going to touch the Frotz class. We’ll need to add some time to the estimation. The Frotz class is a huge mess, we really need to schedule time to refactor it.
Nearly every project has had areas which everyone recognized as painful. In fact, everyone had been recognizing those areas as painful for weeks or months.
If there’s an area of the code that everyone has recognized as painful for weeks, the time for refactoring has been and gone. That battle is lost. It’s not called “Red Green Red Green Red Green Spend A Whole Day Refactoring”. We’re not talking about refactoring anymore; we’re in Code Refurbishment territory now:
developers are actually talking about a much more extensive structural redevelopment technique that does not have a common term. These structural changes are often not a complete ground-up rewrite because much of the existing code will be reused.
The refurbishment process may consist of many small refactorings. But it’s likely to be more than that: refactoring always takes place in the context of test coverage, and often refurbishment involves, first, making the code more amenable to testing and then adding new tests.
Does terminology matter? I think it does, because I’ve also observed that true refactoring, and the easy, pleasurable coding experience that accompanies it, is becoming something of a lost art. When we talk about “scheduling some refactoring time for the next iteration”, we tell novice programmers (as well as ourselves) that refactoring is something that can be put off. And over time, we lose (or never discover) the Red-Green-Refactor rhythm.
When we chose agile methods, we made a deal with ourselves and our stakeholders: we’ll trade the supposed assurances of careful up-front design for constant, iterative just-in-time design. Refactoring is where much of that minute-by-minute design happens. When we have “skeleton closet” classes which have become everyone’s pain point for weeks on end, it means we reneged on the deal. Now we are doing the same periodic Big Rewrites that were the hallmark of BDUF. And our stakeholders become understandably leary of this “refactoring” business. Quoting Martin Thompson again:
The reason the business folk have come to recoil is that they fear we are about to head off into uncharted waters with no idea of how long things will take and if any value will come out of the exercise.
I think that for our own happiness and for the health of our projects, if we’re going to keep practicing this “agile” or “lean” stuff we need to make a conscious effort to restore refactoring to its original place, right in the heart of the rhythm and flow of coding. In order to do that, several factors are required:
- We must be hypersensitive to pain. If we’re noticing a lot of churn in one class over a period of months, that’s too late. And it’s not enough to be able to say “hm, these two methods look similar, maybe I should DRY them up”. We need to be able to make deeper observations such as: “I just changed three methods in order to support one new field. That’s Shotgun Surgery. What can I do to avoid that?”
- We must have comprehensive, reliable, fast automated tests. If we feel a moment’s hesitation before refactoring, either because the we’re not confident that the tests will keep us from accidentally changing behavior; we’re concerned our changes will require tests to be fixed as well; or we just don’t want to wait for the tests to run to verify our changes, that’s the death knell for our refactoring practice.
- We must have a license to refactor. The project’s team culture must establish a “safe space” for refactoring. It cannot be a dirty word, something we feel a little bit guilty about every time we take a minute to extract a method.
- We must have good tools. The people who came up with the idea of refactoring also came up with the Smalltalk Refactoring Browser, a point-and-click environment for automating common refactorings. If we are to make refactoring habitual, at the very least we need editors which make it easy to automate frequent tasks, and the willingness to learn to use them effectively.
I’d love to end this with a list of resources for mastering the art of refactoring. One that I always recommend to Ruby programmers is Refactoring in Ruby, a workbook companion to the Refactoring, Ruby Edition (those are Amazon affiliate links). Unfortunately, I’m out of time for writing. So I’ll open the floor: what book/article/screencast/presentation helped you understand refactoring better? Leave a link in the comments!