In my experience, most programmers hardly spend any time refactoring their code. Even the simplest of refactorings to do, rename field/variable/method and extract method, are not done more often than they should be. Sure, it's nice to see that more and more programmers are writing unit tests but the way they write them still misses the point. And to write unit tests without paying attention to refactoring to me is just asking for more trouble.
So here are some things from the book that I'd like to highlight about refactoring:
The Pragmatic Programmer wrote:
When Should You Refactor?
When you come across a stumbling block because the code doesn't quite fit anymore, or you notice two things that should really be merged, or anything else at all strikes you as being "wrong," don't hesitate to change it. There's no time like the present. Any number of things may cause code to qualify for refactoring:
Duplication You've discovered a violation of the DRY principle (Don't Repeat Yourself)
Nonorthogonal design. You've discovered some code or design that could be made more orthogonal
Outdated knowledge. Things change, requirements drift, and your knowledge of the problem increases. Code needs to keep up.[/b]
Performance. You need to move functionality from one area of the system to another to improve performance.
If I had to add one thing, I would add this:
Lack of Clarity. If you or anyone else has to spend five minutes trying to understand what a method does, then you need to change something so that the code's intent is immediately obvious.
These days there are people, in particular I imagine Michael Feathers among others, who would argue that the last point about performance is not really a motivation for refactoring. Refactoring and optimization may appear to do the same kind of things but their goals are different. Refactoring is about changing structure to improve maintainability. Optimization is about changing structure to improve resource usage. One thing I found from interviewing people is that many think that refactoring is mainly about optimization. Since PP was published in 2000 and Michael Feathers' book "Working Effectively with Legacy Code" where he differentiates refactoring from optimization was published in 2005, I'll give the PP guys a pass on this one.
Continuing my monologue... (does no one else have something to say about refactoring?!)
Recent replies in this thread got me to thinking about my strategy for refactoring. In the thread I stated that Rename, Extract Method, and Composed Method are the most basic and most common refactorings I perform maybe 85% of the time. It got me thinking about how the simple act of renaming variables/methods/classes can quickly get you and keep you on the right track and how much pain and confusion poorly chosen names can really cause. This just validates my assertion that if you put in some effort to make your code read like a story and then try to read your code out loud, something almost magical happens when you have chosen the right words. More importantly, when you hear yourself reading something that doesn't make a whole lot of sense out loud, you have a better chance of catching conceptual incongruencies in your code.
Another case in point in this thread. The OP actually did good by abstracting out the details and writing code that revealed its intent. Yet, the first two responses recommended reverting to a less intention-revealing but ostensibly more performant version of the code. Why?! Why would you refactor away clarity? Premature optimization, which is the root of all evil, strikes again.
Second thing to point out in that thread is that a few simple Rename refactorings can help improve (IMO) the code even more. I think spending time trying to find good names really pays big dividends and it's one of if not the first things you should try do when you're refactoring. It's low-hanging fruit and you often get a lot of bang for the buck. In fact, often it's all the bang you really need.
I've seen several threads lately in which the OP defends against "attacks" against their code (aka "constructive criticism") by saying something like "It's my code, so it doesn't matter whether other people can't read it". What those people don't realize is that a year from now, that code will have been written by a different person -- you aren't the same person you were a year ago. I'm sure you've had the experience of looking at something you wrote a few years ago and asking yourself what you were thinking back then. I know I've had that experience.
Paul Clapham wrote:I'm sure you've had the experience of looking at something you wrote a few years ago and asking yourself what you were thinking back then. I know I've had that experience.
Yes, I certainly had that experience early on in my career. Nowadays, my constant insistence on investing in Ruthlessly Refactoring my code has all but made that a thing in the long-distant past. Just last week I had to go back and review parts of an application that I had maintained a while ago. It was nice to be able to go into one of the things that I touched and still be able to easily find my way around it.
A few years ago, my wife started insisting that we clean up the house before we left for a long vacation. The first time we had to do this, the kids and I complained but when we came back to a nice, clean house we knew that, as always, my wife was right. That's kind of like how I feel when I come back to code that I took time to leave well-factored.