Here's a key philosophical question regarding refactoring: There are two roles with direct relevance here: the Developer, who writes the code, and the Development Manager whose job it is to deliver a solid product on time. The Developer is often motivated to refactor his/her code to improve the "elegance factor." This stems naturally (and appropriately) from their pride in their work. However, the Manager is (and should be) more focused on the "bottom line" and will sometimes view refactoring as "hubcap polishing" (or a similar, less seemly, metaphor) -- that is, refinements whose marginal practical value are less than their cost. Having been in both roles, I understand both perspectives. The question (finally!) is, "What criteria makes sense to differentiate between worthwhile refactoring and 'hubcap polishing'? " [This message has been edited by Bill Compton (edited October 11, 2000).]
If you recall the subtitle of Fowler's book, "Refactoring: Improving the Design of Existing Code" then it ought to be clear that sometimes it is the case that assignments when complete present a less than elegant, or possibly even a less than acceptable solution when viewed from a a long term perspective. Particularly in such a situation, if maintenance is to be done on the code, or if the functionality provided by that section of code is to extended, an opportunity to "improve the design of the existing code" presents itself. A programmer who wishes to refactor the involved code ought to be able to make a case for the design improvement, and explain what she wants to do so that an assessment can be made of the value of the proposed modifications. A person assigned to make "final" decisions about the proposed modifications, whether to approve them or not, must either trust the person(s) making the request or he/she, possibly with input from the rest of the staff, must be able to evaluate the value of the modifications. Given that two different people will often assign differing value to the same proposition, it depends I suppose, on the strength of the case presented on behalf of the change as well as whether the improvements will allow the code to be more flexible and extensible. In other words, do the proposed changes improve the design and if so, is the design change worth implementing? I think that there are no particular rules of thimb for this question, at least none that seem obvious to me. Decisions about what to and what not to develop must be made with regard to time to market, value to customers, value to the software infrastructure and a host of other factors. I wish that I believed that there were good and obvious rules of thumb for these decisions, then there probably wouldn't be so many fights about what to do at work.
[This message has been edited by andy glick (edited October 11, 2000).]
I think the problem with looking at refactoring like this, is that it assumes that refactoring is done after the product is "complete", to somehow "make the code more elegant". It also seems to imply that refactoring is a big, and thus expensive, effort. This is not really what refactoring is all about, though. Refactoring should really be done continuously, during development, so that its benefits and savings are applicable immediately, for all the rest of the work. The main aim of refactoring is to put the code base into a position where the next change is easier/quicker/cheaper/more robust/more understandable etc, rather than just tidying up an already fully-working project. If development proceeds as a series of small steps (decomposed customer requirements, fault fixes, whatever), refactoring between these small steps is an extremely valuable tool to help constrain the increase of costs and complexity, and decrease the size, and potential for introducing more bugs as development continues. Imagine a system where we are looking at just one aspect of refactoring - the so called "OAOO" (Once And Only Once) principle. If (say) the code to convert between US dollars and British pounds is implemented in three different places, then any change to the system will involve changes to three bits of code. But what if in the past these three bits of code have got out of step - the developer may actually have to find three different solutions to essentially the same problem - three times the cost! What if the code in the three places is already so different that the stressed developer only finds two of them, and leaves some unusual cases using the old system. This is getting serious, in real, bottom-line terms. So, The developer tasked with doing this first refactors all three cases into one, called from the three different locations, then makes the change to use the new system. This is unlikely to take much (if any) more time than fixing the three places individually, but has made any future changes in that area much easier to do as well as solving the current problem. So refactoring is always a good thing to do. The essence of refactoring is that it is a series of very small changes, each of which doesn't affect the behaviour of the system. Very small changes implies they don't cost much, and can often (as in the example above) cost nothing, or even save costs - even on a very short time scale. Doesn't affect the behaviour of the system implies that they can be done at any time, without impacting the system function.
Thanks, Andy & Frank for your thoughtful responses. I distilled these two key points from Andy's response: 1) Refactoring is indicated if you'll maintain or extend the code. This makes good sense. The corollary is that code that will (at least, likely) never be touched again would likely not justify refactoring. This might apply, for example, to a stopgap piece of code written to solve a one-time-only problem, such as a migration from an old data format to a new one. Of course, this situation is clearly the minority case. 2) The relevant factors in making decisions are: time to market, value to customers, value to the software infrastructure. Again, this makes sense. These are examples of reasons why you'd be making future changes (either bugfixes or enhancements) to the code. Are there are other factors? I distilled these three key points from Frank's response: 1) Refactoring should be many, small, changes, not a big project at the end. I agree that refactoring "along the way" is better than "big bang" at the end. That said, this approach necessitates greater care in separating refactoring from new functionality or big fixes, a necessity that Fowler emphasizes. Also, there may be cases in which "big bang" refactoring is helpful, even if incremental refactoring has been done along the way. Given the larger cost, greater care in deciding to do this would be indicated. 2) The focus is to facilitate next set of changes. This coincides with Andy's point #1 above. 3) "So refactoring is always a good thing to do." This statement goes too far, I think, in its generality. Taken at face value, it implies that there are (absolutely) no scenarios (no matter how small or short-lived) wherein refactoring doesn't yield a net gain. While I understand (and agree with) the context and the overall point, I think there are some exceptions. There is another facet of this question we haven't addressed: "How do you know you're done?" Having decided to refactor (either incremental or big bang), what criteria make sense to determine that the refactoring process on the given piece of code should stop?
Joined: Jan 07, 1999
"So refactoring is always a good thing to do." This statement goes too far, I think, in its generality Yes, I was a little overzealous, there. I might rephrase that as "refactoring is always worth considering". Any better? As for how you know you've finished. This is an immense area. In practice I guess its when you can no longer justify what you are doing (to yourself, your peers, your management, or whoever else you look to for guidance), the budget runs out, or work pressures demand that something else be done instead. The has been some, rather abstract, discussion of a notion of "software entropy", and the claim that an effective refactoring is one which somehow decreases this value. If we had such a measure, it would be relatively easy to set target entropy levels, or minimum change levels, and stop refactoring when these targets are reached. Unfortunately such a measure seems to refuse to be quantified. There has also been some discussion of a sort of "normal form", in which it is provable (or at least demonstrable) that the software is in its "lowest-entropy" value, but likewise this idea also remains intangible. Personally, I use refactoring as a tool for my own work, and do as much or as little as I personally feel is necessary at the time. It's less science and more craft, but it does get the job done