:::: MENU ::::
Browsing posts in: Refactoring

Implementing the strategy pattern without an explosion of classes – part 3 of ??

I feel uncomfortable when I see large switch statements. I appreciate how they break the Open Closed Principle. I have enough experience to know that they seem to attract extra conditions & additional logic during maintenance, and quickly become bug hotspots.

A refactoring I use frequently to deal with this is Replace Conditional with Polymorphism; but for simple switches, its always seemed like a rather large hammer.

Take the following simple example that performs slightly different processing logic based on the credit card type:

Its highly likely that the number of credit card types will increase; and that the complexity of processing logic for each will also increase over time. The traditional application of the Replace Conditional with Polymorphism refactoring gives the following:

This explosion of classes containing almost zero logic has always bothered me as quite a lot of boilerplate overhead for a relatively small reduction in complexity.

Consider however, the functional approach to the same refactoring:

Here we have obtained the same simplification of the switch statement; but avoided the explosion of simple classes. Whilst strictly speaking we are still violating the Open Closed Principle; we do have a collection of simple methods that are easy to comprehend and test. It’s worth noting that when our logic becomes very complex; converting to the OO Strategy pattern becomes a more compelling option. Consider the case when we include a collection of validation logic for each credit card:

In this case the whole file starts to feel too complex to me; and having the logic partitioned into separate strategy classes / files seems more maintainable to me.

To conclude then, the fact that languages treat functions as first class constructs, gives us the flexibility to use them in a “polymorphic” way; where our “interface” is the function signature.

And for some problems, like a refactoring a simple switch statement; I feel this gives us a more elegant solution.


For a software craftsman, reducing technical debt should be as much of a habit as typing

I was involved in an interesting group discussion with fellow craftsmen yesterday on Technical Debt at the 2009 Software Craftsmanship conference.

The question put to the group was: “How should a team make time to reduce technical debt?”

I was interested that there was a totally unanamious response – “You shouldn’t”. “You should be doing tiny pieces of technical debt reduction all the time”.

Previously I have advocated creating technical debt reduction stories, and trying to schedule those into the iteration plan. People thought this was in principal the wrong strategy; and indeed in my experience this approach doesn’t work.

The group felt that in general tackling technical debt reduction though large scale refactorings was the wrong approach – rather a craftsman should be making incremental improvements every time they touch the code.

Bob Martin’s Boy Scout Rule:check in your code a little cleaner than what you checked out – encapsulates this principal. Its the little refactorings that you make – removing a tiny piece of duplication, changing a variable name to better reveal intent; extracting an expression into a intention revealing method – that, over time, result in a clean, maintainable code base.

In a way, this is similar to implementing the “Fixing Broken Windows Theory” in software development. The theory is that having a zero tolerance attitude towards the little things makes a huge impact on the so called “bigger” things.

Its perhaps easier understood if you consider what happens if you don’t care about the little things. Its about the attitude – if I couldn’t care enough to clean up a messy bit of code; will my team mates care about a few broken tests? If its okay to have a few broken tests; then it’s probably okay to ignore some bugs. If its okay to ignore bugs; then who really needs to care about well defined acceptance tests? And if the team doesn’t care about precise acceptance tests; why should the business care about unambiguous requirements. You get the picture.

Its the little things, added up, that result in technical debt reduction.