Monday, November 5, 2007

Refactoring to Strategy

The getRecommended() method presents several problems. First, it's long—long enough that comments have to explain its various parts. Short methods are easy to understand, seldom need explanation, and are usually preferable to long methods. In addition, the getRecommended() method chooses a strategy and then executes it; these are two different and separable functions. You can clean up this code by applying STRATEGY. To do so, you need to

Create an interface that defines the strategic operation

Implement the interface with classes that represent each strategy

Refactor the code to select and to use an instance of the right strategic class

Three steps involved.

Why is this important? Because, in turning this Rubik`s cube, we will make mistakes. We do not know exactly many parameters and many design decisions will have to be taken without them. Educated guesses are informing all cognitive models in the market. So if we know that we will make mistakes, we should be able to undo those mistakes easily. So here is a design principle for our architecture:

Whenever a design decision is based on an educated guess, the implementation should not be done through class methods, but with the strategy pattern.

I don`t know to what extent we will be able to follow this. That is precisely why we need to start getting used to the refactoring involved and master these three small steps.

We want to create a strategy pattern to deal with potentially different activation curves and potentially different decay curves. We are not sure of which is the best (i.e., psychologically plausible) curve, hence we want this to be easy to change. The easier to change, the higher the productivity. The higher the productivity, the most mistakes we can make without major backtracks. And mistakes we will make, lots of mistakes. On that you can be sure.

But the strategy pattern also gives us something enormously valuable. It gives us the ability to change code on the fly. It gives us the ability, for example, to change behavior should a global signal be received; we know from experience that our memory of intense moments is registered; while expected, boring, moments do not register as well. I used to believe that in the mind there was no space for global variables, or global events. I was wrong. A spike in adrenaline makes you alert, opens your eyes, raises your heart rate, raises your blood pressure, feeds your muscles with blood, preparing them for action, and halts numerous "background" processes, such as digestion. There are global signals, and behavior changes on the fly. (BTW, where in NUPIC does this happen?)

The strategy pattern gives us this ability. And this is something we do want. So we want to be masters at the craft of transforming refactoring a class method into a strategy pattern. So here we go. Here's our current class definition for activations:

(3.3)Kill the previous code, by commenting out the method and its declaration. Compile... and it doesn't run anymore! Great, because the compiler will point out to you all the previous calls made to the method, so just substitute them for your strategy. In our example, we substitute calls to Recompute_Level to the function Level:=Activation_Strategy. Recompute_Activation (Current_State).

Compile and run, and functionality should be restored!

(3.4) Now, test whether or not the whole strategy is working by changing the pattern at runtime. In my case this means including the following piece of code in the end of the DeployChange method: if Level>0.5 then set_activation_linear;

Here's to the strategy pattern. This one is truly important. Everybody should master this technique. This MUST be trivial to do, anytime. Unless you are so overconfident to believe that you'll never get paralyzed because of a bad design decision taken ages ago.