The folly of re-use

November 7, 2006

Today I want to talk about re-using code in your programs. Firstly I want to discuss what re-use is, and the benefits it gives you, and then I want to talk about what it is not. It’s the latter that I believe is more important.

Code re-use is following the principle of “only do it once”. Writing an identical line of code in two separate places means

* modifying two lines of code if you want to add/remove/change functionality
* have the potential for introducing a bug or inconsistent behaviour between the two lines
* larger bytecode/binaries

If you are doing exactly the same thing in two places, it makes sense to move that functionality in to a separate method and replace the two lines with method calls. This solves all three of the problems listed above.

So, re-use is a Good Thing.

However, I believe that there is confusion as to what re-use actually is. Re-use is the removal of identical pieces of repeated code and placing them in methods. Re-use is not the removal of identical concepts and placing them in methods.

A common example used in programming tutorials is to add or subtract an amount from a bank balance. A function to do that might look like this:

void ChangeBalance(double amount)
{
_balance += amount;
}

Enthusiastic programmers look at that method and think – “Aha! I can re-use that method to do both deposits and withdrawals, thereby making my code more efficient!”. So they write method calls like this:

// add the deposit on
account.ChangeBalance(newDepositAmount);
// subtract the ATM withdrawal
account.ChangeBalance(-newWithdrawalAmount);

The ChangeBalance() method has been re-used to provide two different pieces of functionality – increasing the balance of an account, and reducing the balance of an account. That is absolutely fine as-is. However, back in the world of real applications, the ChangeBalance() method is going to be far more complicated. The method may have to check whether the account is exceeding its overdraft limit; whether the account is eligible for withdrawals; whether a new level of interest needs to be applied once a balance threshold is reached. All of these complicate the code, and yet they only apply to one of the two scenarios – either increasing or reducing the balance. It is not the code that has been re-used, but the concept and mistakenly so. Given the new conditions we’ve added above, let’s re-write the ChangeBalance() method:

void ChangeBalance(double amount)
{
  double tempNewBalance = _balance+amount;
  if (amount < _accountAllowsWithdrawals)
  {
    if (tempNewBalance > _overdraftLimit)
    {
      _balance += amount;
    }
    else
    {
      throw new Exception(Account.OverdraftLimitExceeded);
    }
  }
  else
  {
    if (tempNewBalance > _currentInterestThreshhold)
    {
      moveToNewInterestThreshold();
    }
    _balance += amount;
  }
}

Our original one-line method has suddenly increased to 30 lines, and that’s just to support the three conditions that I thought up off the top of my head. Real systems have plenty more conditions, account types, special cases and the like that need to be dealt with.

If you look back over the code, what we find is that although we’ve re-used the concept of modifying the account balance, all we have actually done is pollute the ChangeBalance() method with a lot of code that may not be relevant to us at all. And even worse, we have three copies of the line “_balance += amount”!

What we have to do is recognise that increasing an account balance is NOT the same as reducing an account balance. It is far more sensible to have a class interface that looks like this:

void IncreaseBalance(double amount);
void DecreaseBalance(double amount);

You can then implement separate rules for increasing and decreasing balances. If you find a condition that must be fulfilled by both methods, you can factor that out into a function on its own and call it from each method.

I believe that inappropriate complexity is added to programming because coders try to re-factor up-front. Combining functionality into single methods, believing that this constitutes “re-use”, is as dangerous as trying to optimise code for performance without benchmarking it. I think that programmers lives could be made much easier by writing everything in a separate method, and only combining methods together when it is obvious that it should happen.

Make your lives easier, don’t re-use unless you’re really eliminating duplication.

Advertisements

One Response to “The folly of re-use”

  1. I see this all the time. This is just one of those thigs that come with experience and then having an experienced developer point out what you just said above.

    Today I had a member of my team doing something like this with a stored proc. I had him break it out into 2 stored procs instead. In the case of stored procs, not only does it not make sense from the reuse point, but it can impact the performance because the 2 execution paths are so different.

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: