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.

More reflections on OOPSLA'04.
Before heading to the Vancouver Aquarium for the main social event of the conference I stuck my head into a BOF session about the SeaSide web application framework.
Wow!
SeaSide makes writing web apps startlingly simple and straightforward. In comparison, web app frameworks in the Java world, such as JSP or Struts, and even Ruby on Rails look like dinosaurs.
It does so by turning the conceptual model of most web-app frameworks on its head. Instead of dispatching requests from the client to objects that send back responses, a SeaSide application is written as a single thread of control that sends requests to the user and waits for their response. The application processes response data using the normal control flow statements that programmers are used to: no need for complex configuration files mapping forms to actions to JSP pages, etc etc. I commented, only partly tongue-in-cheek, that the configuration file of a Struts app would be larger than the entire domain logic of a typical SeaSide application doing the same thing.
SeaSide's model of a single thread of control per user is only a conceptual model. Under the hood, SeaSide takes care of what happens when the user navigages backwards and forwards or creates multiple browser windows to interact with the same application. The important thing is that the programmer doesn't have to care: SeaSide maintains the simple programming model as an abstraction above its complex internal implementation. SeaSide also makes it easy to run transactions, compose HTML pages from components and bind HTML links to program actions, all in a natural Smalltalk style.
SeaSide is able to present such a simple API because it takes advantage of "esoteric" features of its implementation language/platform, Smalltalk, such as continuations and closures. Java, in comparison to Smalltalk, is designed on the assumption that programmers using the Java language are not skilled enough use such language features without making a mess of things, and so the language should only contain simple features to avoid confusing our poor little heads. Paradoxically, the result is that Java APIs are overly complex, and our poor little heads get confused anyway. SeaSide is a good demonstration that powerful, if complex, language features make the job of everyday programming easier, not harder, by letting API designers create elegant abstractions that hide the complexity of the problem domain and technical solution.

More reflections on OOPSLA'04.
Gilad Bracha presented a paper cowritten with David Ungar on Mirrors, an architectural style for reflective APIs that cleanly separates meta-level and domain-level concerns — the authors term this "stratification".
Mirrors would address problems I have encountered recently: business logic had called meta-level getters and setters intended for use by the persistence layer and evolved over time into a confusing tangle of "train-wreck" statements. I imagine an OR mapper using a "persistence mirror" to view the persistent state of an object, rather than calling the object directly, and thereby dissuading programmers from using meta-level calls in domain code.