My own personal style has shifted a bit recently; I've adopted a few minor tricks, like naming instance variables with a leading underscore and I've stopped naming interfaces with a leading 'I'.
More than that, I've really been trying to adopt an every more spare style in my interfaces. I'm looking for the Perfection and Simplicity that Ken Arnold talks about. I often visualize my object interfaces in terms of a suit of armor, which should have the minimal number of openings. Ken talks about the surface area of an interface, that can expand when there's a lot of inheritance involved ... or my own personal issue: convienience methods.
When the Collections framework first came out, I was aghast that useful things (like sorting) were in a static class. Ugh! Surely that's no OO!
I've since come to understand the usefulness of that. My early OO was in Objective-C. Between categories (an early forerunner of aspects) and a lack of garbage collection, you could end up twisting yourself up. Better to put a method onto an existing class than to have to create a whole new class!
But nowadays, in terms of keeping my surface area small, I seek out places where I can replace convienience methods (often protected methods in some base class) with a static utility method.
I look at methods now (I'm doing this somewhat in Tapestry) and say ... hey, change a few variable references to accessor methods and you could pull this entire method right out of this class. For example:
public class AbstractLineItem implements LineItem { private int _quantity; private double _cost; protected double computeTotal() { return _quantity * _cost; } }could easily be replaced by:
public class LineItemUtils { public static double computeTotal(LineItem item) { return item.getQuantity() * item.getCost(); } }
Note the big advantage: its a public method expressed in terms of the interface not the class. Suddenly, the logic here is so much simpler and more testable. In HiveMind terms, it may not be a static class, but instead of service used to calcuate the total ... same difference.
This does an end run around problems such as multiple-inheritance. Too often, I want MI because there are convienience methods in base class A and base class B that I want access to. Moving those convienience methods out into a static class or service removes the need. Suddenly, those base classes aren't so useful either; I'm more likely to start with java.lang.Object and just implement the right interfaces.
Nowadays, I look at the Tapestry code base and think ... woops; a bit too much of Tapestry is inheritance-oriented rather than interface-oriented. A page or component in Tapestry fills different concerns (model, view and controller) at different times and perhaps the mythical Tapestry 4.0 will address that (Tapestry 4.0 is my personal code word for the total , non-backwards compatible rewrite of Tapestry that I would only think about under the guise of a JSR, so don't hold your breath). I'd love to seperate out the IComponent interface into seperate objects and interfaces to represent property storage, component hierarchy, rendering and request handling.
In the meantime, I'm finishing up at WebCT. HiveMind is going gangbusters (just added a pooled service model). I spent the weekend doing major revisions on chapter 1 of The Book and feel I've nailed it. ApacheCon is coming up, as is my new and changed life as a happy-go-lucky independent consultant. Now if I could just get the Vista application deploying into WebLogic 8.1 properly, I'd be a fully happy camper.
No comments:
Post a Comment