Refactoring Without Unit Testing – Like Traveling Back In Time And Stepping On Butterflies, Only More Dangerous


Refactoring, rewriting existing code to make it as small, efficient, and ultimately as testable as possible, is something of a double-edged sword.  In the Test-Driven world, it’s an absolute necessity.  In the non-TDD world, however, it becomes a potentially very dangerous activity that can make things worse off than where you started.

If Only I Knew Then…

Refactoring is something of a hindsight practice.  It’s like traveling back in time with the knowledge you have of the present, and seeking to “set things right” with the code in question.

In TDD, you refactor all the time.  And that’s perfectly fine; in fact it’s expected.  You write tests and code for them, and armed with new insight, go back and tweak, rewrite, move around, and otherwise morph that code into something better.  Rinse, repeat.  And it’s a good thing – your tests, if you’ve written them well – will alert you if you break something.

I’ve Got Something On My Shoe…

But without unit tests, refactoring can very easily degenerate into an exercise in reckless time travel.  Yes, you are going back to make the code better… you can clearly see how this method here is bloated and/or redundant, so why not just take some stuff out, move it around, etc.?  It all looks fine, now let’s just hop in our time machine and get back to present-day.  By the way, what was that thing I just stepped on?…

It’s easy to squash a few butterflies when refactoring “blind”, so to speak.  You can’t really be sure the code you just modified will work, or work as expected, or worse yet… something totally new and unexpected will now crop up.  You’ve altered your entire environment, and you have no measures to tell you just how bad, or just plain different, things might be.  If that doesn’t scare you, it should (in a healthy, makes-you-a-better-programmer way, of course).

The Refactor Paradox

If you have the urge to refactor whenever you’re coding… that’s great.  It means you’re thinking about how to improve things, and that’s an excellent mindset to have.  But if you happen to be in an environment where you can’t unit test, or if you’re averse to testing, then tread a bit more carefully as you refactor.  You’re still writing new code, even though it’s often old code.  The act of altering it makes it new again, and even if you’re absolutely sure there’s no new logic there, it’s good just to assume it’s all brand new and that you don’t really know how it’s going to behave.

I have done my fair share of refactoring sans tests before, and I’ve learned my lessons the hard way.  These days I try to be a lot more careful.  If I refactor code that has never been tested before, I do my best to enforce a “no new code without unit tests” policy, and treat all that old code as brand new.

Technorati Tags: ,,

2 Responses to “Refactoring Without Unit Testing – Like Traveling Back In Time And Stepping On Butterflies, Only More Dangerous”

  1. 1 R. Eric Geiger

    Lately I’ve been thinking “small” with all my code: as few lines as possible, etc., and I’ve probably been getting a bit carried away with it. I try to refactor downwards… reducing as much code as I can yet still maintaining good design. However, I really like your definition, with expressiveness as the goal, rather than just spartan code.But ending up with “more code”? I think I feel some hives starting up… 🙂

  2. 2 J.P. Hamilton

    I couldn’t agree with the last paragraph more. I can almost guarantee that if I refactor something without a unit test behind it I am going to break something. Literally, this has probably happened 95% of the time. I think our definition of refactoring is a little different, though. I am not thinking about making code small and efficient when I refactor. I think about making it more expressive. I want my code to read better. Sometimes, this leaves me with more code than when I started.

%d bloggers like this: