January 9, 2013

Now Is A Good Time To Refactor

What are you doing right now?

Okay, besides reading this?

You know what you could be doing, don't you?


Don't start with rebuttals and excuses because I've heard them all before:
  • The codebase is too complex and intertwined with itself that you'd need to set aside 1,000 hours and 3 months on the production schedule to refactor it. 
  • The production schedule is too busy. 
  • We don't have enough PM/dev/QA resources. 
  • Etc...
Refactoring isn't rocket science, and any good developer knows that. The problem is that refactoring is often seen as a binary proposition: we have to refactor everything, otherwise we cannot refactor anything. However, that's simply not the case. You can make your code better bit by bit and block by block, and you have time to do that right now. Here's how...

Step 1: Identify

Where does it hurt most when you have to touch your codebase? While you're working on new features or fixing defects, identify the things that you'd like to make better. You don't need to make a fix now (or even know what the fix would be), just document the parts of the codebase that are painful to deal with. The thing to keep in mind here is that you don't have to go looking for huge chunks of code to fix. In fact, the smaller the problem the better, because it's easier to deal with.

Step 2: Justify

Why is that code so awful to work with? It could be any one of a number of things... the important thing is that you don't change code without justifying the change. If you don't know why the code is bad you have no realistic chance of making it better.

Step 3: Design

How would you improve the code? Your solution should directly address the pain point(s) from Step 2 that you used to justify why the code needs to change. You need to design your improvements in order to make sure that your code will still meet existing requirements without introducing new side effects. Designing a solution to the problem will also help you to quickly see if your solution is just as painful as the problem itself.

Step 4: Evaluate

Once you've completed steps 1-3, ask yourself: is it worth the time and effort to refactor? If the benefit of your change doesn't outweigh the implementation and testing costs associated with it, then it's probably not worth it. How do you know? Well, you'll need to estimate some things:
  • Future technical debt resolved by refactoring (benefit).
    • Technical debt encompasses many things, including: readability, cohesion, coupling, and regression, among others.
    • You should not use past technical debt as a measure, as it is considered a sunk cost.
  • Future non-functional improvements, if any (benefit).
    • Non-functional improvements include improvements to performance, security, and administration.
  • Estimated time to implement and test the refactored code (cost).
  • Future non-functional costs, if any (cost).
Remember that you're just estimating the items above, so you don't need to be too scientific; you're just trying to ballpark some figures to see if there's an obvious disparity in costs vs. benefits.

Step 5: Implement

Once you've evaluated that your change is worth making, you can (and should) make the change. This is where I usually hear the excuses and reasons for not refactoring. If you've identified a reasonably small piece of code to change, and have designed a solution for it, then the implementation should take a relatively small amount of time. Heck, I'd even argue that you don't need to put it on the production schedule - just do it when you have a few minutes between tasks.

If you need to implement a larger change, see if you can break it down into smaller chunks and do it one piece at a time. If that's not possible, then put the refactoring task on your production schedule and get it done in the next sprint!

Step 6: Test

The only time I've ever seen a refactoring effort fail (and thus refactoring becomes taboo...) is when refactored code is not tested as if it's a new feature or change request. Seriously folks, you need to test your changes, regardless of how small or insignificant you think they are. "This code does the same thing as the old code, only better!" is not a good justification for not testing.

Armed with the 5 steps above, refactoring your code should be a much easier and more organized process, and you should now see it as a process that happens in small chunks rather than as a large paradigm-shifting effort.

So, now, go forth and REFACTOR!

What are you waiting for?


Anthony Thomas said...

Good advice, the first step 4 is especially important.

side note, you have 2 step fours.

Brian Driscoll said...

I noticed the two step fours, albeit too late! Thanks for the heads up.

Kutloisiso said...

Love the approach put forward here, nice one. Especially the emphasis on Test. Would add that if you do not have unit tests for the re-factored code, write them.