Refactoring approaches

I'm working on a fairly large codebase right now.  Unfortunately it has significant problems.  Right now we have the time to work through some of these problems, so we are.  What does that mean?  Refactor, refactor, refactor.

An unfortunate addition to our poor codebase is the lack of unit tests for huge portions of it.  Not the perfect situation when you're starting a major refactoring exercise.  So what is the best way to handle major refactorings which lack suitable test coverage?

After a couple of weeks working on refactoring I think I've managed to screw up a couple of things well enough to have some lessons learned.  The first attempt we made at a major refactoring we started working on a method that was a major culprit for fragility and complexity.  We refactored and refactored in that method.  By the time we were done, the guilty method had been reworked, but we'd failed to see the logic in delegated calls.  Not only did we miss that code, but we didn't see the patterns that were embedded in the existing code.

In the end we managed to work our way out of our pickle and get a nicely formed code base in that area.  The next set of code that we refactored was approached in a different way though.  Instead of diving into the problem area and ripping and tearing, we opened up the code and mapped the high level functionality first.  We traced the majority of the delegated code so that we understood more than the skin of the problem.  The last step was coming up with a game plan.  The game plan wasn't anything formal.  Instead it was a rough idea of how we wanted to interface with the problem code (single line call or calls to multiple discreet public methods or other means).  We combined that with an overall riding guidance to testability and dependency injection we ended up with the basis for our approach.

One of the challenging things that we're running into is refactoring that removes an excessive use of Singletons and static classes/methods.  Refactoring isn't as straight forward as changing a class/method name and then working on the logic that it is abstracting away.  Instead we're spending a lot of time finding the usages and figuring out how we're going to remove the single line usages that were originally coded.  It's not a huge problem, but it adds to the workload.  Thank goodness for ReSharper and Alt-F7 (Find Usages).

Using this approach we managed to get the code into a more respectable state on the first pass through.  I don't know if it's the best result, but so far it's proving the most effective for us.

posted @ Thursday, March 22, 2007 8:08 PM

Print

Comments on this entry:

# re: Refactoring approaches

Left by JoeyDotNet at 3/22/2007 9:11 PM
Gravatar
The really important thing you pointed out was... "An unfortunate addition to our poor codebase is the lack of unit tests for huge portions of it. " You can refactor with so much more confidence with tests to back you up. Otherwise, it can be quite risky as you noted. When I take people through refactoring exercises on un-tested code, I often will first focus on getting some tests written against the current codebase and incrementally show them how we can improve bits and pieces little by little. This of course is assuming you're able to at least write *some* unit tests against the current code, which I know is not always the case. Especially when you have singletons and statics hanging out all over the place. And yeah, R# is downright priceless when it comes to being able to quickly perform common refactorings!

# re: Refactoring approaches

Left by Tom Opgenorth at 3/22/2007 10:11 PM
Gravatar
YOu might want to pick up a copy of the book "Refactoring: Improving the Design of Existing Code". Might give you some good strategies/tips.

# re: Refactoring approaches

Left by David Stennett at 3/23/2007 3:58 AM
Gravatar
You may also want to check out Joshua Kerievsky's book "Refactoring to Patterns" -- which you can pick up at Amazon: http://www.amazon.com/Refactoring-Patterns-Addison-Wesley-Signature-Kerievsky/dp/0321213351/ref=pd_bbs_sr_1/102-4920473-1484113?ie=UTF8&s=books&qid=1174647283&sr=8-1 I personally have NOT read it, but I have heard good things about it, and it did win a Jolt Award if memory serves me correctly. Check it out, it may help and give some good advice. David Stennett Team JetBrains http://blogs.jetbrains.com/dotnet/

# re: Refactoring approaches

Left by JoeyDotNet at 3/23/2007 8:19 AM
Gravatar
Absolutely! I can attest to both of those books being very important in improving your refactoring skills. The Kerievsky book in particular is really great at giving you practical examples of when to refactor toward or even away from particular patterns.

Your comment:



 (will not be displayed)


 
 
 
Please add 4 and 6 and type the answer here:
 

Live Comment Preview: