Or rather Inter-Package Inheritance Part 2, as last time I got caught up in my circular dependency WSAD rant. So what does Inter-Package Inheritance allow? As far as I can see; bugger all. After all if a package in a collection of coherent functionality then how on earth can separating the implementation of something across multiple places be good?
But on the other hand what harm can it do? Well firstly it makes it bloody hard to find out what is happening with a given piece of code in the usual inheritance way. Namely which method is actually executing, which variable is getting updated and are those the methods and variables that should be getting touched. I also find it particularly hard to have to trace up a hierarchy of three classes just to find out what the full set of variables a particular object should have.
But the killer feature that Inter-Package Inheritance has over normal inheritance is that once you’ve made an unfinalised class with protected instance variables and methods accessible then practical refactoring is a nightmare. The root class can be in use anywhere and is effectively lava-flowed. The inheriting objects are similarly rooted as even though they may represent discrete functionality they always need to be able to read their parent objects.
This has had some weird implications in my current job (for example because there is a dependency on the GNU Regexp class somewhere in the “common” code all the projects need to import it into the classpath, even if they don’t use the class or the package anywhere else) but also lead to my circular build wreck. I moved the factory but the objects it served out had to stay in the lava flow because their parents were (incorrectly I may add) in the EJB layer. This lead to a dependency circle where the factory (in the business layer) depended on the EJB layer which depended on the factory. In addition the client layer (which resides in the shared object layer, natch) also depended on the factory and the EJB layer also depends on shared layer.
So what does this gibberish mean? Well everything basically bloody depends on everything else. and the most frustrating thing is that this has all arisen because someone wanted to inherit a few instance fields rather than encapsulating and compositing them like normal.
Actually I say like normal but this seems a relatively common kind of problem so I turn (by the power of Safari) to Fowler’s Refactoring for advice but he doesn’t seem to have a magic bullet. I can see the problem but collapsing the hierarchy is probably going to be major work because the package hierarchy is not just split between packages, it is also split between ClearCase/WSAD projects one of whom is read-only in the normal composite stream.
The answer perhaps lies in doing some selective duplication in the supporting business layer. Creating objects to represent the inherited instance values, one root class to provide the default class implementations that may be required for backwards compatibility and then switching the affected classes to use these new objects that exist in their own project space (or at least in their immediate project space). Still this is not a trivial change that you can skip past the management one Friday afternoon and that means some kind of detailed plan of action.
I always feel that if you present a correction plan and it gets turned down then you’ve done your professional duty (and covered your arse if you are so inclined) and you can carry on with a clear conscience. Here though there are so many things wrong in so many areas so corrective action may need to be taken sooner rather than later.