How often should you refactor?

Refactoring

Refactoring Problem Overview


I had a discussion a few weeks back with some co-workers on refactoring, and I seem to be in a minority that believes "Refactor early, refactor often" is a good approach that keeps code from getting messy and unmaintainable. A number of other people thought that it just belongs in the maintenance phases of a project.

If you have an opinion, please defend it.

Refactoring Solutions


Solution 1 - Refactoring

Just like you said: refactor early, refactor often.

Refactoring early means the necessary changes are still fresh on my mind. Refactoring often means the changes tend to be smaller.

Delaying refactoring only ends up making a big mess which further makes it harder to refactor. Cleaning up as soon as I notice the mess prevents it from building up and becoming a problem later.

Solution 2 - Refactoring

I refactor code as soon as it's functional (all the tests pass). This way I clean it up while it's still fresh in my mind, and before anyone else sees how ugly the first version was.

After the initial check-in I typically refactor every time I touch a piece of code. Refactoring isn't something you should set aside separate time for. It should be something you just do as you go.

Solution 3 - Refactoring

You write code with two hats on. The just-get-the-thing-working hat and the I-need-to-understand-this-tomorrow hat. Obviously the second hat is the refactoring one. So you refactor every time you have made something work but have (inevitably) introduced smells like duplicated code, long methods, fragile error handling, bad variable names etc...

Refactoring whilst trying to get something working (i.e. wearing both hats) isn't practical for non-trivial tasks. But postponing refactoring till the next day/week/iteration is very bad because the context of the problem will be gone from your head. So switch between hats as often as possible but never combine them.

Solution 4 - Refactoring

I refactor every chance I get because it lets me hone my code into the best it can be. I do this even when actively developing to prevent creating unmaintainable code in the first place. It also oftentimes lets me straighten out a poor design decision before it becomes unfixable.

Solution 5 - Refactoring

Three good reasons to refactor:

  • Your original design (perhaps in a very small area, but design nonetheless) was wrong. This includes where you discover a common operation and want to share code.
  • You are designing iteratively.
  • The code is so bad that it needs major refurbishment.

Three good reasons not to refactor:

  • "This looks a little bit messy".
  • "I don't entirely agree with the way the last guy did this".
  • "It might be more efficient". (The problem there is 'might').

"Messy" is controversial - there is a valid argument variously called "fixing broken windows", or "code hygiene", which suggests that if you let small things slide, then you will start to let large things slide too. That's fine, and is a good thing to bear in mind, but remember that it's an analogy. It doesn't excuse shunting stuff around interminably, in search of the cleanest possible solution.

How often you refactor should depend on how often the good reasons occur, and how confident you are that your test process protects you from introducing bugs.

Refactoring is never a goal in itself. But if something doesn't work, it has to be fixed, and that's as true in initial development as it is in maintenance. For non-trivial changes it's almost always better to refactor, and incorporate the new concepts cleanly, than to patch a single place with great lumps of junk in order to avoid any change elsewhere.

For what it's worth, I think nothing of changing an interface provided that I have a handle on what uses it, and that the scope of the resulting change is manageable.

Solution 6 - Refactoring

As the book says, You refactor when

  • you add some code... a new feature
  • when you fix a bug / defect
  • when you do a code-review with multiple people
  • when you find yourself duplicating something for the third time.. 3 strikes rule

Solution 7 - Refactoring

I try to go by this motto: leave all the code you touch better than it was.

When I make a fix or add a feature I usually use that opportunity to do limited refactoring on the impacted code. Often this makes it easier to make my intended change, so it actually doesn't cost anything.

Otherwise, you should budget dedicated time for refactoring, if you can't because you are always fighting fires (I wonder why) then you should force yourself to refactor when you find making changes becomes much harder than it should and when "code smells" are just unbearable.

Solution 8 - Refactoring

A lot of times when I'm flushing out ideas my code starts out very tightly coupled and messy. As I start polishing the idea more the logical separations start becomming more and more clear and I begin refactoring. It's a constant process and as everyone suggests should be done 'Early and Often'.

Solution 9 - Refactoring

I refactor when:

I'm modifying code and I'm confused by it. If it takes me a while to sift it out, it needs refactoring.

I'm creating new code and after I've got it "working". Often times I'll get things working and as I'm coding I realize "Hey, I need to redo what I did 20 lines up, only with a few changes". At that point I refactor and continue.

The only thing that in my opinion should stop you from doing this is time constraints. Like it or not, sometimes you just don't have the time to do it.

Solution 10 - Refactoring

It's like the National Parks -- Always leave it a little better than you found it.

To me, that means any time I open code, and have to scratch my head to figure out what's going on, I should refactor something. My primary goal is for readability and understanding. Usually it's just renaming a variable for clarity. Sometimes it's extracting a method -

For example (trivial), If I came across

temp = array[i];
array[i] = array[j];
array[j] = temp;

I would probably replace that with a swap(i,j) method.

The compiler will likely inline it anyways, and a swap() tells everyone semantically what's going on.

That being said, with my own code (starting from scratch), I tend to refactor for design. I often find it easier to work in a concrete class. When its done and debugged, then I'll pull the old Extract Interface trick.

I'll leave it to a co-worker to refactor for readability, as I'm too close to the code to notice the holes. After all, I know what I meant.

Solution 11 - Refactoring

Refactor opportunistically! Do it whenever it's easy.

If refactoring is difficult, then you're doing it at the wrong time (when the code doesn't need it) or on the wrong part of the code (where there are better efficiencies to be gained elswhere). (Or you're not that good at refactoring yet.)

Saving refactoring for "maintenance" is a tautology. Refactoring is maintenance.

Solution 12 - Refactoring

I refactor every time I read anything and can make it more readable. Not a major restructuring. But if I think to myself "what does this List contain? Oh, Integers!" then I'll change it to List<Integer>. Also, I often extract methods in the IDE to put a good name of a few lines of code.

Solution 13 - Refactoring

The answer is always, but more specifically:

  • Assuming you branch for each task, then on each new branch, before it goes to QA.
  • If you develop all in the trunk, then before each commit.
  • When maintaining old code, use the above for new tasks, and for old code do refactoring on major releases that will obtain extra QA.

Solution 14 - Refactoring

Everytime you encounter a need. At least when you're going to change a piece of code that needs refactoring.

Solution 15 - Refactoring

I localize refactoring to code related to my current task. I try to do my refactoring up front. I commit these changes separately since from a functional standpoint, it is unrelated to the actual task. This way the code is cleaner to work with and the revision history is also cleaner.

Solution 16 - Refactoring

"Refactor early, refactor often" is a productive guideline. Though that kind of assumes that you really know the code. The older a system gets, the more dangerous refactoring becomes, and the more deliberation is required. In some cases refactoring needs to be managed tasks, with effort level and time estimates, etc.

Solution 17 - Refactoring

Continuously, within reason. You should always be looking for ways to improve your software, but you have to be careful to avoid situations where you’re refactoring for the sake of refactoring (Refactorbation).

If you can make a case that a refactoring will make a piece of code faster, easier to read, easier to maintain or easier or provide some other value to the business I say go for it!

Solution 18 - Refactoring

If you have a refactoring tool that will make the changes safely, then you should refactor whenever the code will compile, if it will make the code clearer.

If you do not have such a tool, you should refactor whenever the tests are green, if it will make the code clearer.

Make small changes -- rename a method to make what it does clearer. Extract a class to make a group of related variables be clearly related. Refactoring is not about making large changes, but about making things cleaner minute by minute. Refactoring is clearing your dishes after each meal, instead of waiting until every surface is covered in dirty plates.

Solution 19 - Refactoring

Absolutely as soon as it seems expedient. If you don't the pain builds up.

Since switching to Squeak (which I now seem to mention every post) I've realised that lots of design questions during prototyping fall away because refactoring is really easy in that environment. To be honest, if you don't have an environment where refactoring is basically painless, I recommend that you try squeak just to know what it can be like.

Solution 20 - Refactoring

Refactoring often can often save the day, or at least some time. There was a project I was working on and we refactored all of our code after we hit some milestone. It was a great way because if we needed to rip code out that was no longer useful it made it easier to patch in whatever new thing we needed.

Solution 21 - Refactoring

We're having a discussion at work on this right now. We more or less agree that "write it so it works, then fix it". But we differ on the time perspective. I am more "fix it right away", my coworker is more "fix it in the next iteration".

Some quotes that back him up:

Douglas Crockford, Senior Javascript Architect Yahoo:

> refactor every 7th sprint.

Ken Thompson (unix man):

> Code by itself almost rots and it's > gonna be rewritten. Even when nothing > has changed, for some reason it rots.

I would like that once done with a task the code submitted is something you can come back to in 2 months and think "yes, I did well here". I do not believe that it is easy to find time to come back later and fix it. believing this is somewhat naive from my point of view.

Edit: spelling error

Solution 22 - Refactoring

I think you should refactor something when you're currently working on a part of it. Means if you have to enhance function A, then you should refactor it before (and afterwards?). If you don't do anything with this function, then leave it as it is, as long as you have something else to do.

Do not refactor a working part of the system, unless you already have to change it.

Solution 23 - Refactoring

There are many views on this topic, some linked to a particular methodology or approach to development. When using TDD, refactor early and often is, as you say, a favoured approach.

In other situations you may refactor as and when needed. For example, when you spot repetitious code.

When following more traditional methods with detailed up-front design, the refactoring may be less often. However, I would recommend not leaving refactoring until the end of a project. Not only will you be likely to introduce problems, potentially post-UAT, it is often also the case that refactoring gets progressively more difficult. For this reason, time constraints on the classic project cause refactoring and extra testing to be dropped and when maintenance kicks in you may have already created a spaghetti-code monster.

Solution 24 - Refactoring

If it ain't broke, don't refactor it.

I'd say the time to refactor belongs in the initial coding stage, and ou can do it as often and as many times as you like. Once its in the hands of a customer, then it becomes a different matter. You do not want to make work for yourself 'tidying' up code only to find that it gets shipped and breaks something.

The time after initial delivery to refactor is when you say you'll do it. When the code gets a bit too smelly, then have a dedicated release that contains refactorings and probably a few more important fixes. That way, if you do happen to break something, you know where it went wrong, you can much more easily fix it. If you refactor all the time, you will break things, you will not know that its broken until it gets QAd, and then you'll have a hard time trying to figure out whether the bugfix/feature code changes caused the problem, or some refactoring you performed ages ago.

Checking for cbreaking changes is a lot easier when the code looks roughly like it used to. Refactor a lot of code structure and you can make it next to impossible, so only refactor when you seriously mean to. Treat it like you would any other product code change and you should be ok.

Solution 25 - Refactoring

I think this Top 100 Wordpress blog post may have some good advice. http://blog.accurev.com/2008/09/17/dr-strangecode-or-how-i-learned-to-stop-worrying-and-love-old-code/

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBob KingView Question on Stackoverflow
Solution 1 - RefactoringjopView Answer on Stackoverflow
Solution 2 - RefactoringBill the LizardView Answer on Stackoverflow
Solution 3 - RefactoringGarth GilmourView Answer on Stackoverflow
Solution 4 - RefactoringBob KingView Answer on Stackoverflow
Solution 5 - RefactoringSteve JessopView Answer on Stackoverflow
Solution 6 - RefactoringGishuView Answer on Stackoverflow
Solution 7 - RefactoringWedgeView Answer on Stackoverflow
Solution 8 - RefactoringMicahView Answer on Stackoverflow
Solution 9 - RefactoringLeananView Answer on Stackoverflow
Solution 10 - RefactoringChris CudmoreView Answer on Stackoverflow
Solution 11 - RefactoringcatfoodView Answer on Stackoverflow
Solution 12 - RefactoringCraig P. MotlinView Answer on Stackoverflow
Solution 13 - RefactoringBrian R. BondyView Answer on Stackoverflow
Solution 14 - RefactoringVVSView Answer on Stackoverflow
Solution 15 - Refactorings_t_e_v_eView Answer on Stackoverflow
Solution 16 - RefactoringChris NoeView Answer on Stackoverflow
Solution 17 - RefactoringJames BenderView Answer on Stackoverflow
Solution 18 - RefactoringSean McMillanView Answer on Stackoverflow
Solution 19 - RefactoringMarcinView Answer on Stackoverflow
Solution 20 - RefactoringZee JollyRogerView Answer on Stackoverflow
Solution 21 - RefactoringsonstaboView Answer on Stackoverflow
Solution 22 - RefactoringComSubVieView Answer on Stackoverflow
Solution 23 - RefactoringBlackWaspView Answer on Stackoverflow
Solution 24 - RefactoringgbjbaanbView Answer on Stackoverflow
Solution 25 - RefactoringAlexForbesView Answer on Stackoverflow