Monday, June 9, 2008

Refactoring to show the rules

A team mate and myself had a good time refactoring some non-OO spaghetti code into a more robust OO version. We didn't set out to do pair programming or refactor the code to the extent we did (partly because we were approaching a test freeze and did not have the time and partly because the code had been in this state for over 4 years!).

The nice end effect of this was that pair programming helped us share knowledge, not only business knowledge but also design knowledge. We constantly discussed micro-design decisions like:
  • I'm naming this method/variable this as it better reflects the intent...
  • Restructuring the code like this will have this advantage but may have these disadvantages...
  • If we create more classes and distribute the desired behaviour across them we will factor the code better and get rid of all these conditionals, but now this complex method has become a system of objects messaging each other. Which is more simple? ...
and so the discussions went on.

We both feel that the structure may feel more foreign to juniour programmers or to 'procedural OO programmers' for instance 1 comment was:
when debugging it is more difficult to see what is actually executing this code because of all the indirection/polymorphism
But the end product clearly factored the monolithic conditional-laden method into objects that had well defined responsiblities and that encapsulated the high-level policy (heuristic/algorithm/rules).

To give an example the code has 4 variations of calculating a value based ultimately on what is in the DB and the state of a policy (medical insurance policy). The code originally used many conditionals to determine what the DB says the rules are for a given state. These different strategies were interwoven in one method so the high level policy/heuristic/rule whatever you want to call it could not be easily understood.

The end result was that we refactored the code into
1 high level interface, 4 strategies, with 1 strategy being unique and the other 3 having a inheritance relationship (not only for sharing of behaviour but also sharing of implementation).
The sharing of implementation was a by-product of the refactoring exercise and although not ideal the main concern was that we had a well typed polymorphic hierarchy and as a by-product an implementation sharing hierarchy (ala some implementations of Smalltalk collection libraries where the main concern is subclassing for implementation).
The one complex method became 3 lines of code, and the rules were spread over 3 objects. Almost all the conditionals were removed in favour of polymorphic calls and for me this became the crux of the refactoring: Everything seemed more simple and easy to change and maybe even faster (polymorphism-at-its-best)

No comments: