Refactoring: Finding Dead Code

There’s a “dead code” code smell mentioned in Refactoring. The refactoring is to delete the code. OK, easy enough to do. Over the years, I’ve identified a few handy ways of identifying the dead code laying around in your code base. That way you can ferret it all out at once and get rid of it. This specific example is for C++, but you can apply the techniques to any language.

This post talks about the Visual Studio way of doing it. If you develop under emacs, I know that emacs has a way to invoke grep combined with find to search over a directory hierarchy. I’m not familiar with other IDEs like Xcode or Eclipse, so I can’t say if they have a similar search feature, but it seems likely.

The trick is to exploit Visual Studio’s “find in files” feature. This will bring up each occurrence of the dead code in the Find Results window so you can navigate to each instance of dead code quickly. Here are some regular expressions that I use to find dead code:

//.*;
//:b*(if|while|for|do)
//:b*#
\#:b*if:b+[01]:b*$

The first two look for code commented out with the C++ single-line comment token (//). The second two look for either commented-out preprocessor directives or preprocessor directives that are always true or false. Looking for code commented out with the multi-line comment tokens (/* and */) is a little bit harder, but you can find likely candidates with something like this:

/\*:b*$

You might need to adjust that for the style of commenting used in your code-base. You’ll notice that commented-out code always tends to be commented out in a certain way. I don’t know why people comment out code permanently. The compiler isn’t seeing it. Putting it in the middle of stuff the compiler does sees just plays tricks on your brain. Your brain can’t turn its visual analysis on and off based on comment strings, even with syntax highlighting. Its still code in your visual field and it goes into your brain whether you like it or not and you have to spend brain cycles purposefully ignoring it. Just do your brain a favor and delete it! If you ever should need it again for some reason, you can always get it back out of the source code control system.

While I’m on the subject of source code control systems, let me make a few recommendations about how you should delete dead code. First, get all your other checkins done before you go hunting for dead code. Once all your code is checked in and your unit tests are passing, go dead code hunting and ferret as much of it out of the bushes as you can. Kill it mercilessly. Don’t do anything else while your killing dead code. If you don’t have enough time in a single commit cycle to remove all the identified dead code from your code base, try working on it one project at a time instead of comprehensively. After you’ve deleted it all and your code is compiling and all unit tests are passing, then commit the changes and only these changes. Use the phrase “Deleting dead code” or something similar on your commit message. This way, when people look at the commit log, they can quickly identify commits that were deleting dead code. If for some reason you need to turn that deleted dead code into walking zombie code (“living dead” code?), then you can quickly find it in the commit log.

Now, here’s one more Visual Studio trick for you that will make it easy to navigate through all these potentially dead pieces of code and remove them. You see, “Find in files…” sends its output to the Find Results window. (There are two find results windows and you can select which one gets the output of this particular search in the Result Options section of the Find and Replace dialog.) You see, I like to stay keyboard centric when I’m operating in Visual Studio. However, the standard keyboard bindings for Visual Studio doesn’t contain a shortcut to display the find results window. Of course it will display itself when you run the search. However, getting the keyboard focus back to the search results is the important bit of this trick.

So go to Tools / Options… / Keyboard in Visual Studio. Show commands containing “View.FindResults”. You should see two entries in the list box underneath reading “View.FindResults1” and “View.FindResults2”. Select the Find Results 1 item and use the new shortcut in the Global scope by selecting Global in the combobox. To the right of the combobox type Alt+1 and then click Assign. Repeat the process for the Find Results 2 window if you use both find result windows in your searches.

OK, so now that we’ve got the keyboard binding created, the dead code hunt begins with you invoking “Find in files…” on whatever portion of your code base you want to search for dead code. I like to go project by project on large solutions containing many projects. I’ll eliminate all the dead code from one project and commit that before moving onto the next project.

Once you have your search results, the dead code hunt looks like this sequence of key presses: Alt+1, DownArrow, Return, //delete dead code. Let’s break that down:

  1. Alt+1: display Find Results 1 window and send keyboard focus to that window
  2. DownArrow: in the Find Results 1 window, move the cursor down one line. This advances to the next line in the search results. Each individual item matching the search expression is shown on its own line, so this advances to the next match to the search expression.
  3. Return: when you press return in the find results window, it navigates to whatever source file and line are listed on the line of the find results window that contains the cursor. This navigates to the source code matched.

Now you can examine the offending code in question and decide whether or not to delete it. Most of the time, you will. As you repeat this process, you can quickly get into a rhythm of keypresses that will rapidly take you through most, if not all, the instances of dead code. Thanks to the keyboard shortcut applied to the View.FindResults1 command, we don’t have to leave the keyboard to use the mouse to navigate over to the window and double-click the next find result. For lots of sprinkled single-lines of code commented out, this really makes quick work of that.

Refactoring is like backpacking. You always plan on packing out more trash than you brought with you. Deleting dead code is like getting rid of that dead fish at the campsite. You leave the world a better place. Your team will thank you for it.

4 Responses to “Refactoring: Finding Dead Code”

  1. Harald M. Says:

    Well – that’s not really “dead code” removal, but “absolutely totally dead code” removal :-).
    Dead code, technically, is code that still is compiled (or looks as if it is compiled – e.g. between #ifs), but will never get executed because the preconditions of its execution are never true (never as in “never never”; or never as in “never in real life”).

    But I agree wholeheartedly with your posting that commented code should be deleted whenever and wherever you see it.

    The one exception I accept is a piece of “future code”, with heavy commenting why it (a) is not yet up and running; and (b) why it is still a good idea to already have it in there (e.g., to point out an existing bug which will be removed by the code, but this depends on some other, unfortunately still unavailable code or environment change).
    Regards
    H.

    Like

  2. Blaise Pascal Says:

    While useful tips, this doesn’t give information on how to find the form of dead code I run across more often: methods who’s invocations have been refactored away, or even never written in the first place.

    Like

  3. legalize Says:

    Yes, this technique discusses ways to find code that is commented out. But commented out code is worse than the kinds of dead code you describe here. Its absolutely worthless and totally distracting! First get all this commented crap out of your code base. I’m currently looking at a code base where it feels like the programmers were afraid to ever delete anything. Instead, they just commented out what it was and wrote something to replace it. I can maybe understand having the code like this for a few minutes while you try something out, but such things should never be committed to source control!

    For the kinds of dead code where it is still compiled, but never called, I use things like Find All References in Visual Studio, or any of the add-on packages like Visual Assist X. They can show you when code is defined and compiled, but never executed, except possibly by tests. It requires greater care though because their analysis is only solution-wide and not global across a large code base spread out over multiple solutions. For instance, it might only be called by test code in the current solution but be a public/protected member on a class that is used by some other code that consumes this project’s output as a library. For that sort of far-reaching code analysis, Visual Studio tools tend not to be a good solution as they limit themselves to a single solution. Of course you could create one “monster solution” containing all your projects and do it that way, but its probably pushing the limits of what Visual Studio could handle.

    Visual Assist X (and possibly earlier versions of Visual Assist) contains a preprocessor analysis that will change the color of inactive #define blocks. This can also help identify dead code from the point of view of the preprocessor.

    Like

  4. brone Says:

    One quick time-saving tip: the Edit.GoToNextLocation and Edit.GoToPreviousLocation can also be usefully bound to keys. (They are F4/F8 and Shift+F4/Shift+F8 for me — I don’t remember which of these I set up, if either.) These step you through the locations in whichever output or find results window last had the focus, but with just the one keypress. Very useful!

    (These also do a passable job with the output window, so if you print warnings and the like to the output window with a “FILE(LINE)” prefix then you can step through them this way too. This isn’t something I ever ended up using much myself, even though it sounded handy.)

    Like


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: