OOPSLA'04: Static Classes or Dynamic Objects?
More reflections from OOPSLA'04.
In the same session as the Mirrors paper were two presentations on automated tools to help programmers work with OO software.
One presented a tool for automatically refactoring class and interface hierarchies to improve cohesion based on usage patterns of class features. The result? For simple type hierarchies the tool neatly factored out distinct concepts. For example, given some code that used the Java collection framework it detected that some client code only read from collections and other code also modified them, and so extracted an "immutable collection" interface that was the supertype of a "mutable collection" interface. Cool! However, when given a larger type hierarchy the result was less helpful - a straightforward tree was transformed into lots of classes connected by a tangle of multiple-inheritance relationships.
Another presented a tool that automatically generated UML class diagrams from code to help maintenance programmers understand the system they are working on. The novel contribution of this work was an algorithm to determine the binary relationships between classes from the unidirectional references in the code. However, my experience of maintenance - most recently, I've spent the last six months performing maintenance on a million-line plus Java system - is that static class diagrams are not very helpful. Most of them would show that classes A, B and C use interface I that is implemented by classes X, Y and Z. That's of little use when you're trying to diagnose running code.
Both of these tools have the same limitation, in my opinion: they concentrate on the static relationships between classes instead of the dynamic relationships between objects. When it comes to refactoring, I find it is usually better to refactor to composition rather than inheritance. When doing maintenance I need help grasping the dynamic interaction between objects in the running system; static relationships are visible in the code and easy to understand. I would find a lot of use for a tool that would detect where I could replace inheritance with composition and a tool that would create instance diagrams to visualise a running system.
However, I'm not a huge fan of UML. When sketching out instance diagrams I find that an "instances with interfaces" notation, borrowed from the RM-ODP, to be very useful and easy for people to understand.
In these diagrams, the class of an instance is indicated by the name inside the instance bubble and the interface through which an instance is used is indicated by the name next to the "T" of the interface poking out of the instance.
I like this notation because it's quick to sketch on a whiteboard during a design discussion or on paper while debugging. I can easily extend the notation to express attributes of interest depending on what I want to portray. I either name the relationships between instances, as above, or use instance variable names. In the example I've also used dotted lines to represent that one object is passed to another as a message parameter, and only used for the duration of the method. I sometimes distinguish public vs. private relationships by starting the arrows of public relationships from the edge of an instance bubble and those of private relationships from inside the instance bubble.