Friday, October 06, 2006

Ridding (not riding) the Range

I added a suggestion to David's list of potential improvements that we all discussed in Minneapolis. He asked me to describe why it's a problem and what I think the solution is...

Why the Range global is a problem
  • It's like a master key that tightly couples all parts of the system. We will not be able to separate annuity from life w/o either eliminating it or duplicating it for both.
  • It's a global (or rather a collection of globals; same thing). Reference my blog post for reasons why this is bad.
  • It prevents the furtherance of OO development in the system.
I Object!
Objects are objects for a reason. They should encapsulate their data. The range object is a circumvention of OO. A given product will manipulate any number of range variables for varying functionality. So rather than being able to look at the product class methods and members to determine it's behaviour, you may have to guess what range variables it manipulates to do so. Variables should be owned by the proper object that manipulates them. Range variables are manipulated by any other object in the system. This leads to conditional code multiplied all over. So instead of this:

BaseObject.DoThis;

We have this:

If Rng.Something then
SpecificObject.DoSomething
else if Rng.TheOtherThing then
OtherSpecificObject.DoSomething;

If the individual objects properly encapsulated their data, we wouldn't have this problem.

Solution
I don't see any other way than to:
  • Forbid adding any new variables to the range object (with exceptions for exigent circumstances).
  • Start removing it's variables. For each:
    • Search the system for it's use.
    • Determine which object at which level in the heirarchy should encapsulate the data.
    • Move the variable to the appropriate object.
    • Adjust the code that references it.
  • Whenever sets are encountered, this should be seen as an indicator that a new object may be needed. Sets (and their brother case statements) should be rare in OO (1). Unlike an object, they encapsulate nothing. So if you look at a set in code, you learn nothing. In order to learn how the system manipulates the members of the set, you would have to search the system for all references to the set. When you do this search, you will no doubt encounter many case statements and for loops. If the business logic were instead object based, you would simply call BaseType.DoSomething and polymorphism would handle the conditional behaviour of the members of the set. Thus you don't end up with case statements and for loops that usually start out at a manageble size, but enevitably grow into something that is very difficult to maintain.
No doubt this will initially lead to some other objects becoming bloated, but this is a process. The bloated objects should, in turn, be distilled into more granular objects.

1) Refactoring, p. 34, 82

No comments: