Friday, September 17, 2010

My "anti-patterns" - 1

Whole books are written about "anti-patterns" in software design, so I probably won't be saying anything new here. There are several anti-patterns however which I consider sort of "my favorites". I first thought about writing about all of them in one post, but then I recalled one of my readers criticizing me for putting too much statements together. So I'm going to publish them one by one instead.

Visitor pattern

It took me quite a time to grasp the idea of this pattern. Perhaps I'm kind of challenged but I still don't think something that complicated should be used unless really (and I mean really) justified. So my first problem with this construction - it's hardly readable. I hate reading a code where methods have obscure names. I always get lost in the labyrinth of 'visit' and 'accept' calling each other.

However, this is not the single reason. Look at the example from the Wikipedia article.
class CarElementPrintVisitor implements CarElementVisitor {
    public void visit(Wheel wheel) {      
        System.out.println("Visiting " +
            wheel.getName() + " wheel");
    }
 
    public void visit(Engine engine) {
        System.out.println("Visiting engine");
    }
 
    public void visit(Body body) {
        System.out.println("Visiting body");
    }
 
    public void visit(Car car) {      
        System.out.println("Visiting car");
    }
}
I guess I'm going to hurt the feelings of the advocates of this pattern, but this snippet makes me wonder how the pattern made its way to the classical book on object-oriented design. Sorry, but what I really see above is nothing else but a 'switch' statement nicely disguised in methods overloading. Wouldn't it be more straight to simply use 'instanceof' instead? At least the code would be more readable and would not require those obscure 'accept' methods.

Finally, my last objection has to do with modularization of the code. Normally, when extending a class, one doesn't necessarily have to place the derived class in the same module where the base class is. With visitor pattern, the family of classes derived from CarElement is a closed circle. Not only when adding a new derivative one has to go over all visitors, but the derivative has to be in the same module the rest of the family is. Surely, any design assumes something about possible future changes. The same design cannot support more than one direction of changes. This specific one supports adding new visitors but makes it practically impossible to add new elements visited.

To summarize, I have an impression that the visitor pattern is an illusion. It creates more problems than it solves and unnecessarily complicates the code. The only positive side is that it sounds cool when one claims at an interview "I have mastered the visitor pattern!"

2 comments:

  1. What you describe as weak points are actually the "pattern" (oh, how I hate that name) main advantages - since you don't use a "switch" but a statically, compile-time checked dispatching, you're assured that any change you (or your successor) might make in the future would either be compatible, or fail the compilation process. The need to place all related files in the same module (same compile unit) is derived from that very same root.
    However, as with all "patterns" (grr!), sometimes they fit, other times they don't. When they fit, it seems natural to be using them (e.g. "handlers", logic statement evaluators, etc). When they don't, you (or more likely, your successor) get irritated and annoyed and starts shouting "who's the idiot that wrote this piece of S#!t!".
    Ran.

    P.S.
    What do I have against "patterns" (and "anti-patterns")? The concept itself is flawed - you can't take bits of programming and declare them sacred and holy ("it's not an iterator if it doesn't have the method 'next'" - come-on!). More important - you can't teach only those bits to junior developers. Like the NRA slogan "guns don't kill, people do" - "patterns do not make your code bad, you do".

    ReplyDelete
  2. Patterns main advantage is creating a jargon for widley used designs. imagine how you would have to explain a singleton before the GoF book was published. Nowadays you only need to document it as such and everybody understands.

    Looking at it that way eliminates the annoyance of considering patterns as sacred and leaves you with the freedom to implement it according to your own specific needs. you just preserve the basic concepts and terminology.

    Regarding visitors - personally i think this is a great pattern, but i must admit that if java had supported closures it would have become pretty useless...

    ReplyDelete