Thursday, June 16, 2011

Setting the Stage

Today I want to three preparatory steps that are vital to actively working on code. My belief in these comes from many painful experiences.

Step 1: Install a version control system and use it.

THIS IS VITAL. About every two weeks I have a situation in version control this saves me major heartache. As the saying goes, "Learn From My Fail."

Presumably the code you are working on is of value or you wouldn't be wasting your time fixing it. In the process of re-working the code, we are going to apply a lot of small changes. Every so often, a change will have an effect that we didn't foresee. The feeling of terror when the compile is fine, but the program suddenly starts giving screwy results is one I don't wish on anyone. In the best case, you still have the editor open and can undo your way back to a correctly functioning version. If not, you are faced with two unpleasant choices; toss all of your work to date to go back to the original program, or try to debug your way from the current version to one that works.

Version control software gives you a third choice: check out the most recent version that did work. This may mean discarding an afternoon's work, but I've found that it is almost always better than trying to debug my way out of a hole.

There are several systems that are: 1) free, 2) easy to set up and use. Probably the big 4 these days are CVS, Subversion, git, and Mercurial. In a Linux/Unix environment, you probably have a couple of these options pre-installed. CVS and Subversion have the simplest day-to-day use for someone working alone; git and Mercurial shine in collaboration within a team. Which you use is less important than using something. All have nice online tutorials, and all have books dedicated to them (if you are a book person, cruise over to look at the books on the Pragmatic Programmer site for a couple of very readable introductions).

Step 2: Get a small problem that exercises most of the code.
Regression testing is a very weak form of validation. But it is absolutely vital to have some verification that we haven't broken the code. Unit tests are certainly preferable, but I often have to deal with a SUBROUTINE that is a "big ball of mud", several thousand lines with a cyclomatic complexity over 100. McCabe's original work suggests values of 5 or less, with the occasional routine allowed to be in the 6-10 range (provided that a special dispensation was obtained from a suitable religious official :-).

Writing a suite of unit tests for such a monster is beyond my tolerance for pain, and would effectively wind up being a regression test anyway. Taking a known problem with known good solution is my compromise between best practice of having good unit tests, and the unacceptable risk of working with no verification that I haven't broken anything.

You are going to be running problem this lots (probably a few times an hour). Anything that takes more than a couple of minutes is going to get annoying really quickly. Take time to pare the problem down to something that runs in under a minute. It is well worth the effort.

Step 3: Automate the verification of the test.
In the programs I work on, even a small example can generate several hundred pages of output. My enthusiasm for trying to eyeball compare two versions of this file is non-existent.

Automation is a must. The goal is something that says a terse "OK" if the file matches, and gives you come info if there is a problem. For simple files, the operating system's file comparison command is sufficient:

fc original_output new_output

This is the simplest thing and it works. If the files don't agree, though, the amount of output that scrolls by can make it bewildering to figure out the differences. You can pipe the output into another file:

fc original_output new_output > results

and then open results in an editor.

If you are using this lowest tech approach, I've found that the best next step is to fire up an editor that supports tabbed documents, and load both copies. Flipping back and forth will allow you to zoom in on the difference(s) you care about.

This approach fails miserably if you have time/date stamps in the output. The file comparison routine will flag every one of these as a "difference", although they are differences you couldn't care less about. We'll need a somewhat sharper tool to deal with this issue, and I'll discuss a dead-simple one I use in a future post.

Summing Up:
So, the preparatory steps are:
1) Install version control and import the original version of the code. This serves as a powerful "undo" for your changes.
2) Find a small problem that runs in under a minute. This will increase your confidence that you haven't broken anything.
3) Automate the comparison of old v. new output. This allow you to get quick, simple feedback on whether you have broken something. The sooner you know, the easier it is to fix.

No comments:

Post a Comment