Not quite the class inheritance error I had originally planned to write about, but something that is currently biting me in the ass.
The project I’m working on uses a Java Swing table. The way they use the table is, um, “unique” in that “Oh My God What Were They Thinking!” sort of a way. The fundamental problem here is that rather than using the existing Swing class and interface hierarchy in order to create a new table model to feed a JTable object, they instead rolled their own code that sort of kinda uses the JTable stuff, but in their own unique way.
They have their own ‘model’ object, for example, which doesn’t have anything to do with the TableModel interface in Swing, and which uses their own ColumnSpecification class–which again has nothing to dow with the TableColumnModel interface in Swing. Perhaps once I wade through this pile of code I’ll find that their way is more streamlines and more efficient to the task at hand. But right now, none of the stuff makes any sense. I even found one case where they appear to be using a table model object as a ‘flyweight’ table object–which makes no sense, as there are only two tables here.
At home I’ve been tinkering with a piece of code which creates a database connection to a remote SQL server and runs a whole bunch of queries in parallel. I came up with what I thought was an extremely clever way to queue requests up into a pooled connection manager which would pull my requests off and run the request by translating it into a SQL query in one of several pooled background threads.
I plan to rip it all apart.
Why? Because there is an accepted way to do J2EE cached connections and cached prepared statements–and while my design is probably fairly clever, it also doesn’t do things the way it’s normally done in J2EE world with a DataSource object obtaining connections from the database.
And that’s the anti-pattern: rather than sort your way through a whole bunch of puzzling interfaces and use the accepted pattern that the designers of a class expected you to use when writing SQL queries or creating JTables in Swing, you instead decide to roll your own. While your creation may be quite solid and impressive–because it’s not the standard way to do things the next maintenance developer to come along will bang his head against a brick wall trying to sort out what you did while you move on to create new ‘self-rolled’ anti-patterns elsewhere.
For me, what should have been a 30 minute change to their source base–adding two new columns which can be dynamically turned on and off as needed–has turned into a three day nightmare of wading through foreign (and completely unnecessary) class hierarchies and odd-ball problems, such as the apparent abuse of the fireTableStructureChanged() method to indicate a request to change the structure rather than a notification that the structure has changed.
Many years ago Apple had a technical note describing this very problem. They called the problem a failure to understand not just a particular interface, but also a problem to understand the “Gestalt” of that interface. You may be using the interface in a way which accomplishes what you want–but if you don’t use the interface in the way it was intended to be used (because you don’t understand the gestalt of that interface)–you may be screwed heavily later on down the road.
Sun provides a number of Java tutorials on the different Swing components–including tutorials on the JTable class. What these tutorials are good for is not in learning how to build a table–someone could in theory roll their own table class without ever touching the JTable class–but in learning the gestalt of the existing table implementation.
And even though you may not run into dire problems by not understanding the gestalt of an interface (Apple’s tech note was dealing more with interface abuse, such as reaching into a memory handle and fiddling the bits there in a way which was documented as private–but documented nonetheless), you will make the maintenance programmer’s (or you, six months or a year later) life a living hell.