Thoughtful Reactions Refactor Mercilessly

From ThoughtfulReactionsToXp:

"Must be controlled otherwise you're constantly refactoring and never adding. No code or design is ever perfect - you have to draw the line somewhere if you have a product to deliver!"


The image that this puts in my mind is of someone one day declaring 'Look lads and lasses. The code's got a bit out of shape. Let's spend a week refactoring'.

Refactoring done correctly occurs as a continuous part of the process and is automatically controlled by the scope of your current EngineeringTask/UserStory and is performed as a part of implementing that EngineeringTask/UserStory.

Your product is delivered incrementally with timescales defined at the beginning of the cycle so you should not be in the 'let's hack it to get it working and deal with the rubbish later' mentality that you tend to get into when you (or someone else) decided your timescales nine months ago with a completely different set of requirements.

-- LanceWalton


RE: "Must be controlled otherwise you're constantly refactoring and never adding. No code or design is ever perfect - you have to draw the line somewhere if you have a product to deliver!"

This turns out not to be the case. A few minutes refactoring something ugly will make it clean. Then it doesn't want to be refactored any more. Spent a little time refactoring with a fellow yesterday. The original code was a method with two loops, one directing whether to map a record, another detecting a record mapper to do the work. We wrote ...

 process: aRecord
(self shouldMap: aRecord) ifTrue: [self map: aRecord]

Done. No need to revisit. It always turns out that way. There is no looping in improving the code.

You don't work with the non-XP code that I do. I could refactor for a solid month and not be done. -- JeffGrigg


RE: "Must be controlled otherwise you're constantly refactoring and never adding. No code or design is ever perfect - you have to draw the line somewhere if you have a product to deliver!"

If you don't see how easy it becomes to add functionality to code you are refactoring I don't think you are refactoring enough. I sit back and watch all the cool new functionality I can add as I refactor, of course I have to constantly remember that YouArentGonnaNeedIt, but it is nice to see how easy it would be to add in. If you don't see this then I would start sniffing my code for emerging patterns.

Where do you draw the line when it is time to deliver? I have always heard that you do it when the number of bugs flattens out ( or disappears ). With tests it seems to me that I am always in a good position to release my code. Because I can prove that ItWorks.

ErikMeade


I'm new to XP (reading about it for a week) and I feel I am completely missing the point about refactoring. So, I'd like to ask some blunt questions.

  1. If the code is working, why in the world would I want to rewrite it?
  2. How would I even know to look at a file to decide to rewrite it?
  3. If I am tracking down a problem, wouldn't rewriting the code potentially mask the problem, especially if it needs to be fixed in a higher or lower layer?

Like I said, I feel like I am completely missing the point here, so any comments to set me on the right path are appreciated. -- WayneMack


Direct Answers to Wane's questions:

1) If the code is working, why in the world would I want to rewrite it?

There are a lot of reasons you might want to rewrite a "working" piece of code.

  1. To make it clearer to understand,
  2. to make it reusable elsewhere in your application,
  3. to optimize its performance.
If you're looking at a file and having no urge to improve what you see, then you probably shouldn't. Rewriting a suspect module while you are tracking down a problem is indeed a bad idea, as you lose your "control". However, once the problem is found it may provide a strong clue as to whether and how you should restructure the code.

2) How would I even know to look at a file to decide to rewrite it?

A: The CodeSmells

Or, put another way, you see that the code could have been written a different way, and if it had been, it would be better. So you change it to be that way. Now it's better.

3) If I am tracking down a problem, wouldn't rewriting the code potentially mask the problem, especially if it needs to be fixed in a higher or lower layer?

If you're tracking down a problem, looking for the cause of a bug DON'T CHANGE ANYTHING!!! ...until you find the cause of the problem.

Refactoring won't fix a bug, because refactoring (along) does NOT change the functionality of the program. But refactoring the code make leave it in a state that makes it a lot easier to fix the bug.

So (1) find the bug first. Then (2) write a test that exposes the bug. Then you can (3) fix the bug and finally (4) refactor.


Wayne asked, "If the code is working, why in the world would I want to rewrite it?"

There are two ways you can read this statement:

If my kitchen counter looks clean, why would I clean it again?

The answer to the this is that you of course shouldn't; if you can cook comfortably and safely, then your kitchen is clean enough.
I don't want to cook dinner right now, so even if all the dishes are dirty, why would I wash them now?

Here the answer is that you do the cleaning now so that it's easy to cook later. Although it's theoretically possible to wash each pan and dish just before you need it, the practical truth is that if your kitchen is a disaster, you'll walk in, sigh, and order a pizza.

Code that has been properly refactored is a breeze to modify. And when you modify it, you then refactor it, so it's still a breeze to modify.


Refactoring can be risky if you don't have a full set of UnitTests in place, along with "the whole nine yards" of XP process. Therefore, until you have the rest of the process in place and running smoothly...

Only refactor code that you are going to change anyway.
On any project that's still "alive," you'll have constant stream change requests - bug fixes and additional features - changes that you'll have to make to the program.

Now the most common maintenance approach is to make the absolute minimum change required in the program to accomplish each change request. However, this is foolish: Such "quick fixes" have a high probability of introducing further bugs, and will quickly add up to make the program very difficult to maintain.

A better approach is to keep your eyes open while doing routine maintenance, and improve any code you happen to be working on. If a refactoring of surrounding code will make this customer-required change easier, do it. Add comments. Change a few variable names to make their intent clearer. Extract repeated code into a subroutine/function.

This approach does not significantly increase risk, even if you don't have a full set of regression tests in place: Even if you were to do the customer-requested changes with a "minimal code change hack," you'd still have to test it thoroughly; same goes for any minor refactoring you do at the time.

You may be surprised: A few months of "underground refactoring" can dramatically improve the reliability and maintainability of a system - even to the extent of being visible to management. [ExtremeProgrammingInEnemyTerritory]

I think we can develop some useful guidelines by examining the EconomicsOfRefactoring

Contributors: JeffGrigg


I would say 'If I am tracking down a problem, rewriting the code would clarify the problem.' The point is to improve the structure of the code such that it is easy to add new functionality and (hopefully) easy to reuse the methods elsewhere. For me, increasing the clarity of my code drastically improves my understanding of it. If you understand PythonLanguage, I could show you several refactorings that I've done, or you could check out this recently documented PythonLanguage refactoring: http://www.sabren.com/rants/2000/05/20000526a.php3 -- ShaeErisson


EditText of this page (last edited September 26, 2002) or FindPage with title or text search