Go to content Go to navigation Go to search

Monday, 8 August 2005

I Have Seen the Future, and It is Pain

The Future

About six months ago, I noticed that my PowerBook, an old (i.e., born in 2002) 550 MHz G4, seemed to be running a little bit slower than normal. So I zoomed over to Apple’s web site and perused their offerings. I decided to get a PowerMac for the extra horse power and because I no longer needed to carry my work with me.

Ball, tree, and ivy. Apple had three PowerMac configurations: a single 1.7 GHz G5 for $1,500, a dual 2.0 GHz G5 for $2,000, and a dual 2.5 GHz G5 for $2,500. The price difference between the OK option and the sweet-machine-make-all-my-Mac-friends-drool option was $1000. Big price difference. I kept asking myself if I really needed a dual 2.5 GHz machine. The answer, in all honesty, is no. I have not yet dived into Cocoa, do no work in Java, and have not touched C/C++ in years, so I did not need the machine to do handle any heavy development. I do not, nor do I have plans to ever, do video. PhotoShop? Only for web graphics.

So I resigned myself to getting the modest and adequate single 1.7 GHz G5. sigh

But then I got to thinking, “What about a year from now? What kind of computer will I need then? In two years? Five?” When I bought my PowerBook, it was the 550 MHz G4. After three years with that bad boy, I sometimes wished I had purchased the 660 Mhz G4. Apps like OmniGraffle were just plain poky.

So, I changed my mind and decided to get the Dual 2.5 GHz PowermMac. I was not buying my computer for today, but for the next five years.

The Moral of the Story

“What is your point?” you ask? Is it not obvious? Write your code for tomorrow, not today.

You Will Never Remember

As crazy as it sounds, when you write a function, and return to it five, ten, fifty, 494 days from today, you will not understand it. It will look, behave, and function like code written by the the two-headed dwarf who sits in the cubicle next to you who just found out about switches. You just will not recognize it.

Guard Lion So do not hurry. Take your time. Use good variable names. And, the rule from today’s lesson, use well named variables for boolean expressions.

You see, last week I was doing some refactoring on one of our web services. In our original design, we were using Microsoft’s Soap Tookit. While it is a pretty good toolkit, it did not support GUIDs (i.e,. _G_lobal _U_nique _ID_entifiers; e.g., EAE98EEA-ADB7-4B8A-ACCF-E65168DA2B40). The net result being that when our applications talked to each other, all our guids had to be changed to/from strings.

Back to last week. We had decided that, because we no longer used the Soap Toolkit, but used Microsoft’s .NET (which supports GUIDs), we refactored all the IDs from being strings back to being GUIDs. All was right with the world.

Until we went in to refactor one of the applications that consumed the web service and all hell broke loose. When trying to track down the code which was causing problems, we ran into an if/else statement that looked a little bit like this:


     if( account.AccountNumber != "" &&
         account.ID == "" &&
         account.AccountNumber == account.ID &&
         account.FlyingMonkeys.Source == MonkeySources.Rectum &&
         account.CursesToSendToOriginalDeveloper == Double.PositiveInfinity )
     {
         // do some work
     }
     else if( account.AccountNumber != "" )
     {
         // do something different
     }

OK, I admit that some of those tests are not quite accurate (I made up the `account.ID == “”` part), but you get the point: we had no idea what the test did. I looked at it, the maintainer of the code looked at it, and our development lead looked at it and we just could not understand what was going on.

Advice

In the book Code Complete, by Steve McConnell, two critical pieces of advice are given that have helped me tremendously in writing code that I could come back to in one, seven, nineteen, or 239 days. First (which has already been given, but with less emphasis this time), use well named variables for boolean expressions. Second, use comments to express the intent of your code, not what your code is actually doing.

A Rebuke

If you are a developer, and have not read Code Complete, shame on you.

An Example

Let’s say we have an application that matches accounts (yes, the ones with money in them) a user enters into the software with accounts downloaded from another system. The account object (for simplicty’s sake), looks like this (C#):


    public class Account
    {
       // leave the logic to the reader
       public string Number { get; set; } 
    }

Now, later in our code we have to determine if the account we are working with has been matched with an account from the outside system. The code might look like this:


    // if the account number is not empty and the account ID is not empty,
    // save the account mapping
    if( account.Number != "" &&
        account.ID != "" )
    {
       SaveMapping( account );
    }
    // now, save any changes to the account.
    SaveAccount( account );

I bet you can probably guess what this code is doing, but you are not 100% sure. Let’s apply our two principles and make this code much easier to maintain. (Yes. I know we could do a much better job at encapsulation by moving those boolean tests into the `Account` class, but I have to have something to write about later, don’t I?)


    // if the account has been matched, save the match.
    bool accountSaved = (account.ID != "");
    bool accountMapped = (account.Number != "");
    if( accountSaved && accountMapped )
    {
        SaveMapping( account );
    } 
    SaveAccount( account );

Which code would you rather maintain?