34

I've read through most of Fowler's Refactoring book and have refactored many applications in my past big and small.

One of the harder things I find to teach is "when" to refactor. I tend to do this based on a gut feel which has served me remarkably well in the past. However, when getting into discussions with people about whether a piece of code should be left alone or refactored right now it is hard to stand by the "gut check".

I feel like there should be more rigorous approaches to this, but am not sure what they are.

I understand "code-smells", red-green-refactor and other thoughts, but often I feel that the best time to refactor is not the first time you write the code, but the second or third time you are using the code and realize that it is actually a problem and is in actual use.

1

9 Answers 9

24

Refactor when the cost of refactoring is less than the cost of not refactoring.

Measure "cost" however you can. For example, is the code so poorly implemented that trivial bugs cost hours or days to fix? Will refactoring allow you to gain more customers, or increase capacity, or improve performance and thus make your existing customers happier?

8
  • shortform and perfect
    – ZJR
    Feb 20, 2012 at 4:16
  • 9
    In other words: "it's worth to refactor when it's worth to refactor". Duh. Well, it's not really an answer, is it :) Measure "cost" however you can. - OK, how? Isn't that the gist of the question? What time perspective should be applied when measuring that cost? Feb 20, 2012 at 15:52
  • 2
    @Morawski: no, That is an incorrect paraphrase. I said it's worth it to refactor if the value received from the refactoring is greater than the cost of the refactoring. That's not the same as saying "it's worth it to refactor when it's worth it to refactor". Calculate the cost of refactoring. Calculate the cost of not refactoring. Which is bigger? Feb 20, 2012 at 16:47
  • 1
    @BryanOakley : problem is, you can't "calculate" these costs. You can at best estimate them, which is really hard to do when it comes to the cost of not refactoring. What maintenance cost multiplicator do you apply to the unrefactored version vs refactored version ? How do you know if the code in question will have to be maintained or changed at all ? How do you estimate the number of bugs it will generate ? In the end I guess we all unconsciously make these kind of estimations as part of our decision process when we think about refactoring, but there's no accuracy to be expected from it. Feb 24, 2012 at 16:50
  • 2
    @ian31: true, you can't calculate values, and the best you can do is estimate. Still, this is the only really valid way to decide whether to refactor or not, assuming you have limited time and resources. You need to decide whether the refactor is worth it. How you define "worth" is a very inexact science. The point is, you shouldn't refactor on a gut feeling -- there should be a good reason for doing the refactoring other than "I want the code to be prettier". Feb 24, 2012 at 18:19
12

  1. Is the cyclomatic complexity of the function below 5?
  2. Did you completely understand what cyclomatic complexity was without following that link?
  3. Do you have an automated test or documented test case for every path through the function?
  4. Do all of the existing test cases pass?
  5. Can you explain the function and all it's edge cases to me in less than 1 minute?
  6. If not, how about 5 minutes?
  7. 10 minutes?
  8. Are there fewer than 100 lines of code in the function (including comments)?
  9. Can you find two other developers who agree this code is error free just by visual inspection?
  10. Is this function used in only one place?
  11. Does the function meet it's performance goals (Time/Memory/CPU)?

Scoring

Add up the "no" answers above:

  • 0-1 - Why would you even think about refactoring this? You probably just want to rename variables because you don't like the previous developer's naming convention
  • 2-5 - This might need a little tweaking, but I wouldn't hold up a production release for something in this range
  • 6-8 - OK, we probably need to fix this... It's likely we're going to keep revisiting this and/or we don't actually know what it's doing. Still on the fence, but it's highly suspect
  • 9+ - This is a prime candidate for refactoring. (Note, writing test cases is a form of refactoring)

http://mikemainguy.blogspot.com/2013/05/when-to-refactor-code.html

1
  • 4
    #2 sounds very snobbish and is actually useless for evaluating code. #3 & #4 not every company uses unit tests. #8 Avoid comments wherever possible, and 100 lines is waaay too high. I have 1 big widescreen monitor in portrait mode and I would barely be able to see the whole function at once. If it's more than 15 lines of actual code, there should already be a solid reason why you keep it that way. It's a nice, practical approach to have a checklist, but too many points here are just made up or use random values without any reasoning behind it.
    – R. Schmitz
    Mar 29, 2017 at 10:21
9

When your gut is telling you that you should probably do some refactoring, It's likely it's your instincts telling you a little late that you've been putting something important off for too long.

I understand "code-smells", red-green-refactor and other thoughts, but often I feel that the best time to refactor is not the first time you write the code, but the second or third time you are using the code and realize that it is actually a problem and is in actual use.

There are effectively two levels to refactoring. The first is the obvious issues that appear when you first code. These are the little optimizations that cost you very little to do up front. Things like keeping your methods and classes small, and adhering to DRY and SRP. Then you have the additional stage of dealing with major flaws in your design, which may not be immediately apparent until your code has a couple of miles under it. It's this second level that you are talking about, and yet in order to ensure that later refactoring isn't too costly, you need to have already written your code in such a way that the effort you later envisage is made easier and less costly, which means doing an early refactoring.

As Jeff mentioned in his answer, "time is money", particularly in companies where the workload is high and the risks even higher. Time spent up front making sure the code is in its best possible state is time saved later, when teasing out what should have been an easy refactoring turns out to be a major operation.

When writing software, every moment spent improving your code up front is time saved later, when you're really going to need it. The earlier you refactor, the clearer your later changes will be. It's like making a down payment in today's dollars against future technical debt which will be in tomorrows inflated dollars.

In any case, refactoring shouldn't be a task that you put off until some mysterious future when the software is already complete and stable, as it increases your risks later when the stakes are much higher and the product much more difficult to change. Refactoring should be a part of your daily activities, and this is the essence of the Red-Green-Refactor philosophy that you mentioned.

2

I think your question can be answered differently by each developer and even the management in charge of the programming.

My personal preference is, whenever I learn something new, or improve my best practices, I refactor the code that I can - I like to keep my code up to standard as soon as I learn what the best standard to use for that situation was. I am allowed to do this though because it is a smaller company that uses the same software for long periods of time.

In a bigger software development company where time is money, it may be to just start designing with the better practices you learned from this point forward, do not worry about refactoring until verison 2 of that specific software?

I feel teaching when to refactor really depends on the company you are currently in.

2

"When to refactor ?"

Short answer : every time you come across code that smells bad or could be improved (Boy Scout Rule)

Practically, this happens :

  • If you practice TDD, systematically during the Refactor step of the TDD cycle, that is, once your test is green and before you start writing a new test.
  • As a result of a code review
  • When taking over legacy code
  • When consuming code that seems awkwardly designed
  • etc.
2
  • I feel like this just says "You should refactor" without answering the harder part: "I feel like there should be more rigorous approaches to this, but am not sure what they are."
    – Hortitude
    Feb 23, 2012 at 18:58
  • I don't know what to say except feel what's painful to maintain, sniff for code smells and use your experience. I doubt there will ever be a definitive, established method that tells you when and what to refactor if that's what you're looking for. Feb 24, 2012 at 16:25
1

When I was first learning about refactoring, my mentor told me: "Do it twice, hold your nose. Do it three times. refactor." (Thanks, Josh!) To be specific, what he was saying was that when you are about to write the same block of code for the third time (or even a similar code pattern), that is the time to refactor. I have followed that for the past 10 years, and found it to be a sound enough rule of thumb.

Using Eclipse, or similar IDE which has strong refactoring support, reduces the effort to do the refactoring. The IDE support makes it more likely you will refactor as soon as you hit the "third time" (or see the need), instead of seeing it as additional effort.

Also - TDD is a big help here too, since you can keep running your tests as your refactor, and know that you haven't broken anything.

1

Refactoring by its definition is a process. This implies that you should not strive to find spare time to do the rafactoring task, instead you should keep refactoring all the time when you come across code code that could be written better.

Personally I like writing evolutionary prototypes, saying it more simply: code that just works, and then refactoring those until they will meet expected coding standards. Another good example is adding additional functionality and refactoring existing code to enable its reuse.

1

In my 20 years of programming, here is the only rule of thumb that I've actually seen work, which people can stick to, and managers allow time for. (Refactoring is like dieting: sure, "calories in / calories out" is the formula to losing weight, but that doesn't translate into a diet that people will comply with.) And so:

Refactor continuously, as you work. Use Test Driven Development so that you have several red-green-refactor cycles through the day. Refactor just the parts of the code that you've touched.

Once you're more sure of yourself, you can vary from this regimen.

1

I think, that depends on the demands of the project owner and the guy that answers for the quality of the code. You simply can't decide it alone, when the money of somebody else are under question.

As for technical reasons, there are several.

  • If you have a bug in the code, that means that this place is misunderstood and it is VERY probable that more errors could be hidden here and surely there will be great problems with any attempt to develop the connected parts of code. So, this place should be checked for possible refactoring.
  • Another reason is when you add or change a feature and the old code is very inconvenient for changing/adding and the later changes/addings are highly possible. Of course, you should balance the cost.
  • Maybe the most serious reason is when you are changing the code and it is untestable.
1
  • As a scrum master, we had a developer who constantly argued that every story the team sized was larger than what the team thought, and found realized he wanted to refactor every piece of code he came across. Thus, a 3 point story was always an 8 for him. Clearly this was screwing up the delivery of value. So somehow there needs to be some understanding of when to refactor, and how the decision should be made. Just my thought, from that (and a few other) experience. Mar 28, 2017 at 18:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.