Chapter 7. Wallowing in Filth

As a dog returns to its vomit, so fools repeat their folly.

Psalms 26:11

We’ve all encountered it: quicksand code. You wade into it unawares, and pretty soon you get that sinking feeling. The code is dense, not malleable, and resists any effort made to move it. The more effort you put in, the deeper you get sucked in. It’s the man-trap of the digital age.

How does the effective programmer approach code that is, to be polite, not so great? What are our strategies for coping with crap?

Don’t panic, don your sand-proof trousers, and we’ll wade in…

Smell the Signs

Some code is great, like fine art, or well-crafted poetry. It has discernible structure, recognisable cadences, well-paced meter, and a coherence and beauty that make it enjoyable to read and a pleasure to work with.

But, sadly, that is not always the case.

Some code is messy and unstructured: a slalom of gotos that hide any semblance of algorithm. Some is hard to read: with poor layout and shabby naming. Some code is cursed with an unnecessarily rigid structure: nasty coupling and poor cohesion. Some code has poor factoring: entwining UI code with low-level logic. Some code is riddled with duplication: making the project larger and more complex than it need be, whilst harbouring the exact same bug many times over. Some code commits “OO abuse”: inheriting, for all the wrong reasons, tightly associating parts of code that have no real need to be bound. Some code sits like a pernicious cuckoo in the nest: C# written in the style of JavaScript.

Some code has even more insidious badness: brittle behaviour where a change in one place causes a seemingly unconnected module to fail—the very definition of code chaos theory. Some code suffers from poor threading behaviour: employing inappropriate thread primitives or exercising a total lack of understanding of the safe concurrent use of resources. This problem can be very hard to spot, reproduce, and diagnose, as it manifests so intermittently.

(I know I shouldn’t moan, but sometimes I swear that programmers shouldn’t be allowed to type the word thread without first obtaining a license to wield such a dangerous weapon.)

Key

Be prepared to encounter bad code. Fill your toolbox with sharp tools to deal with it.

To work effectively with alien code, you need to able to quickly spot these kinds of problems, and understand how to respond.

The Survey Says…

We’ve already looked at techniques for navigating a new codebase in Chapter 6.

As you build a mental model of a new piece of code, you can begin to gauge its quality using benchmarks like:

It can be hard to perform this initial survey. Maybe you don’t know the technology involved, or the problem domain. You may not be familiar with coding style.

Consider employing software archaeology in your survey: mine your revision control system logs for hints about the quality. Determine: how old is this code? How old is it in relation to the entire project? How many people have worked on it over time? When was it last changed? Are any recent contributors still working on the project? Can you ask them for information about the code? How many bugs have been found and fixed in this area? Many bugfixes centered here indicates that the code is poor.

Working in the Sandpit

You’ve identified quicksand code, and you are now on the alert. You need a sound strategy to work with it.

What is the appropriate plan of attack?

  • Should you repair the bad code?

  • Should you perform the minimal adjustment necessary to solve your current problem, and then run away?

  • Should you cut out the necrotic code and replace it with new, better work?

Gaze into your crystal ball. Often the right answer will be informed by your future plans. How long will you be working with this section of code? Knowing that you will be pitching camp and working here for a while influences the amount of investment you’ll put in. Don’t attempt a sweeping rewrite if you haven’t the time.

Also, consider how frequently this code has been modified up to now. Financial advisors will tell you that past performance is not an indicator of future results. But often it is. Invest your time wisely. This code might be unpleasant, but if it has been working adequately for years without tinkering, it is probably inappropriate to “tidy it up” now, especially if you’re unlikely to need to make many more changes in the future.

Key

Pick your battles. Consider carefully whether you should invest time and effort in “tidying up” bad code. It may be pragmatic to leave it alone right now.

If you determine that it is not appropriate to embark on a massive code rework right now, that doesn’t mean you are necessarily left to drift in a sea of sewage. You can wrestle back some control of the code by cleaning progressively.

Making Adjustments

The single most important advice when working with messy code is this:

Key

Make code changes slowly, and carefully. Make one change at a time.

This is so important that I’d like you to stop, go back, and read it again.

There are many practical ways to follow this advice. Specifically:

Have courage in your ability to change the code. You have a safety net: source control. If you make a mistake, you can always go back in time and try again. It’s probably not wasted effort, as you will have learnt about the code and its adaptability in doing so.

Sometimes it is worth boldly ripping out code in order to replace it. Badly maintained code that has seen no tidying or refactoring can be too painful and hard to correct piecemeal. There is an inherent danger in replacing code wholesale, though: the unreadable mess of special cases might be like that for a reason. Each bodge and code hack encodes an important piece of functionality that has been uncovered through bitter experience. Ignore these subtle behaviours at your peril.

An excellent book that deals with making appropriate changes in quicksand code is Micheal Feathers’ Working Effectively with Legacy Code.footnote::[Michael Feathers, Working Effectively with Legacy Code (Upper Saddle River, NJ: Prentice Hall, 2004).] In it, he describes sound techniques to introduce seams into the code—places where you can introduce test points and most safely introduce sanity.

Bad Code? Bad Programmers?

Yes, it’s frustrating to be slowed down by bad code. The effective programmer does not only deal well with the bad code, but also with the people that wrote it. It is not helpful to apportion blame for code problems. People don’t tend to purposefully write drivel.

Key

There is no need to apportion blame for “bad” code.

Perhaps the original author didn’t understand the utility of code refactoring, or see a way to express the logic neatly. It’s just as likely there are other similar things you do not yet understand. Perhaps they felt under pressure to work fast and had to cut corners (believing the lie that it helps you get there faster; it rarely does).

But of course, you know better.

If you can, enjoy the chance to tidy. It can be very rewarding to bring structure and sanity to a mess. Rather than see it as a tedious exercise, look at it as a chance to introduce higher quality.

Treat it as a lesson. Learn. How will you avoid repeating these same coding mistakes yourself?

Check your attitude as you make improvements. You might think that you know better than the original author. But do you always know better?

I’ve seen this story play out many times: a junior programmer “fixed” a more experienced programmer’s work, with the commit message “refactored the code to look neater.” The code indeed looked neater. But he had removed important functionality. The original author later reverted the change with the commit message: “refactored code back to working.”

Questions . Why does code frequently get so messy? . How can we avoid this from happening in first place? Can we? . What are the advantages of making layout changes separately from code changes? . How many times have you been confronted with distasteful code? How often was this code really dire, rather than “not to your taste”?

See also

Example 7-1.

Employ the Boy Scout Rule. Leave every piece of code you touch better, if even only fractionally.

bbpg 07in01