17 August 2004

That's not my beautiful code

The general consensus in development seems to be: leave crap the way it is. Everyone eventually has to work within existing, often flimsy code, and the etiquette of what to change must be defined. We should not only consider issues of style but also those of refactoring. And just where does style stop and implementation begin? If we don't have a strong grasp of these issues, the scheduling pressures will cloud our good sense, and the political pressures will promote inaction.

There's no excuse for allowing bad code to continue to be bad.

I'm amazed at the pussyfooting that goes on with code refactoring. I was recently told, at this hypothetical company, that you should "obey the local customs" (that is: mimic bad habits) above any decision to clean up existing sloppy code. I might suspect that it's humility that stays programmers' hands (yes, I used "humility" and "programmers" in the same sentence), but those same programmers accede without question that the flaws exist in the code.

It's not boldness or arrogance that pushes me to refactor crap (of which I've produced enough on my own): it's just exhaustion at struggling with unmanageable classes or algorithms. Simply put: if it takes me 20 lines to use an existing class where a better implemented class would take me two, I'll write the new class. Reusable code, easily reusable code, becomes more useful with age.

So what does the notable Martin Fowler say in his book Refactoring? Let's look at the section:

When Should You Refactor?

  • The Rule of Three
  • He begins with the basic statement: [t]he third time you do something you refactor. Good enough. If you're copying and pasting and changing slightly, you probably can do it in a more generic, and more reusable, manner. The obvious benefit is that shared code shares fixes.

  • Refactor When You Add Function
  • He makes the daring statement that he'll refactor to help me understand some code I need to modify. This isn't a clear-cut statement that the code was bad. He's saying that the code was unmanageable (a charge, in my mind, as bad as bad). I can understand more things if I clarify the code as I'm going along. Damn straight. Yet, at this point, you have to trust that you're own understanding is yardstick enough. By that I mean: you have to trust that unreadable code to you is unreadable code to any reasonable programmer. This is a scary decision to make, one where you have to question your humility, but one that must be made.

    He later discusses the code review--a corrolary of these two statements is that multiple viewpoints can help you decide if bad code is bad enough.

  • Refactor When You Need to Fix a Bug
  • This is similar to the argument of refactoring for understanding. One way to look at it is that if you do get a bug report, it's a sign you need refactoring, because the code was not clear enough for you to see there was a bug. In my mind, bug fixes are one of the best times to refactor. You basically have a free pass to get in there and f-ing fix what's wrong. So go a head and do it.

  • Refactor As You Do a Code Review
  • When I come up with ideas [for a code review], I consider whether they can be easily implemented then and there with refactoring. If so, I refactor. When I do it a few times, I can see more clearly what the code looks like with the suggestions in place. I don't have to imagine what it would be like, I can see what it is like. As a result, I can come up with a second level of ideas that I would never have realized had I not refactored.

    A good point here is that clarifying unclear code assists in bringing out the original intent. Sometimes, you can't see the algorithm through the haze of pointer arithmetic and intrusive error handling. Refactoring streamlines local code, and local streamlining leads to more long range streamlining.

At the end of this section, Kent Beck interjects with a sidebar titled "Why Refactoring Works." In it, he lists features that make code difficult to work with:

  • Programs that are hard to read are hard to modify.
  • Programs that have duplicated logic are hard to modify.
  • Programs that require additional behavior that requires you to change running code are hard to modify.
  • Programs with complex conditional logic are hard to modify.

An important point is that sometimes these are necessary aspects of software. All of those features exist to some degree or another. Kent is emphasizing that they are the features that are most difficult about software and that would provide the most benefit if diminished or avoided.

[ posted by sstrader on 17 August 2004 at 8:50:57 PM in Programming ]