Thursday, March 22, 2012

Abstraction by methods..

I recently wanted to refactor a database connectivity framework to support another type of key in the system.

At first glance, this seemed easy.  Every object implements an interface called IPathWithObjectID, that specifies the object must have a property:
object  ObjectID { get; }

Since ObjectID can be any object, it should be trivial to switch things to a string or something else.

The problem, however, lies in the details.

Most methods did this:

int ID = (int) MyObject.ObjectID;

At the time it seemed simple enough, but in hindsight, this is very limited.

A better approach would be to encapsulate the type cast into a method, which is what I refactored the code to do:

public int GetObjectKeyAsInt(IComparable ObjectKey)
{
    if (ObjectKey != null)
    {
        if (ObjectKey is int)
            return (int)ObjectKey;

        throw new ArgumentException("The ObjectKey property is expected to be of type 'int'.");
    }

    throw new ArgumentException("The ObjectKey is null!");
}

Now, in reality all this method does is do a type cast, with some checks. But the power in it is later on I can refactor what is stored in the ObjectID.

So, my code goes from:

int ID = (int) MyObject.ObjectID;

To

int ID = GetObjectKeyAsInt(MyObject.ObjectID);

Maybe I want an ObjectID to be a new class called MyDataKey. Rather than changing hundreds of different places across the code base, I just change one. The GetObjectKeyAsInt method.

Methods provide a powerful mechanism of abstraction. Use them as often as possible, even if the action seems as trivial as a typecast.