Sunday, June 7, 2009

New designs, bad habits?

Here's a poser for the Object-Oriented development crowd.

OO tells us to encapsulate; to keep our object methods small (or, in the word of the jargon, atomic). Build objects that have simple methods, and that helps make the objects reusable. By the same token, objects also have state that is resposed in one or more member variables that may or may not be exposed by public properties. State, however, is tyically expensive, because persistence implies the memory and similar resources necessary to implement it.

Atomicity and state indirectly tend to work against each other. If my methods are too small, it necessarily suggests I'm going to push out elements to the class level. But if I push too much to the class level, I run the risk of creating classes that may need increasingly complex persistence mechanisms which, in turn, suggests a class that may be too broadly scoped. Yet if I decompose (or factor) an object too much, the fragmented design becomes a nightmare to maintain. It's not clearly a vicious circle, but it's a cautionary cliff to avoid.

Here's a shadowy example.

Suppose you have a class:

public class Something
{
    public void InterestingMethod1()
    {
    int ImportantVariable;
   ....do something interesting...
    }
}


And, without typing them here, suppose you have several similar methods in this class, each with a similar "ImportantVariable" declaration. Now, the casual observer would probably suggest that the repetition of that variable could indicate that it should be declared at the class level, as such:


public class Something
{
    int ImportantVariable;

    public void InterestingMethod1()
    {
    }
}


If, however, we start referencing "ImportantVariable" in our atomic methods, don't we reintroduce an old villain in our nice, object-oriented code? It seems to me that in a class of any appreciable size that does any appreciable work, factoring out common variables to the class level starts to look a lot like our old nemesis - global variables. We all know they're bad, don't we? That is, a substantive module wherein we declare a variable once, then it has scoping across all methods, allowing a single change to wreak all manner of unintended consequences. But isn't that precisely what member variables are allowing us to do in even moderately complex classes?

I won't pretend that I have the answer here, nor that this microexample is anything but a strawman example of the point. So I'll throw out the question- what is the "right" answer? When do our atomic methods have elements like local variables factored to the class scope, risking global behavior; when do our classes have members pushed down to methods for the sake of atomicity?

When, indeed? The floor is open for debate...

No comments:

Post a Comment