Spot the Difference

At 13:26 this afternoon, more than a day and a half after the deadline I set my students, I finally got the Tapestry/Hibernate warmup exercise working to my satisfaction. The final bug took several hours to track down; when I found out what it was, I almost decided to throw Tapestry away and use something a little more predictable.

The problem turned out to be the difference between this:

<!-- Buggy version -->
<tr>
  <td colspan="2">
    <input type="submit" jwcid="@Submit"
           listener="ognl:listeners.returnSubmitAction" value="Return"/>
  </td>
  <td colspan="2">
    <input type="submit" jwcid="@Submit"
           listener="ognl:listeners.borrowSubmitAction" value="Borrow"/>
  </td>
  <td><span jwcid="@TextField"  value="ognl:formBorrower"/></td>
  <td><span jwcid="@TextField"  value="ognl:formEmail"/></td>
  <td><span jwcid="@DatePicker" value="ognl:formBorrowDate"/></td>
</tr>

and this:

<!-- Working version -->
<tr>
  <td colspan="2">
    <input type="submit" jwcid="@Submit"
           listener="ognl:listeners.returnSubmitAction" value="Return"/>
  </td>
  <td><span jwcid="@TextField"  value="ognl:formBorrower"/></td>
  <td><span jwcid="@TextField"  value="ognl:formEmail"/></td>
  <td><span jwcid="@DatePicker" value="ognl:formBorrowDate"/></td>
  <td colspan="2">
    <input type="submit" jwcid="@Submit"
           listener="ognl:listeners.borrowSubmitAction" value="Borrow"/>
  </td>
</tr>

Can you spot the bug? In the first version, the three text fields used to submit the borrower's name, email address, and borrow date come after the button that the user clicks to borrow books. In the working version, the text fields come before that button. That is the only difference---I made no changes to the application's .page and .application files, or to the Java class.

After half an hour of Tapestry in Action and on Google, I still have no idea why the order matters. If anyone knows why it does, I'd welcome an explanation...

The real problem here, though, isn't this bug in Tapestry (and yes, it's a bug---even if there's some obscure engineers-rule "but we had to because..." explanation for it, it's a bug). The real problem is the "spooky action at a distance" [1] nature of framework programming. Everything that happens between me clicking the "submit" button on an HTML form, and the corresponding action method being invoked in my Java class, is, for all practical purposes, hidden from me.

Oh, sure, I could run Tomcat (or Jetty, or some other container) under a debugger, and watch Tapestry snatch the form data from the HTTP stream, read my .application and .page files, load my class, subclass it on the fly to create implementations of my abstract methods, add some data members to store form values, and finally invoke the method I actually wrote, but saints and small mercies, how long would that take to set up? Or to run? And how much of it would I actually understand?

On the other hand, how much of that do I want to write myself, over and over again? The whole point of Tapestry is that it takes care of these routine tasks for me, so that I only have to worry about application-specific code. I've written enough CGI scripts and naked servlets to recognize just how much grief a good framework can save.

So, in the end, this turned out to be another example of what Joel Spolsky dubbed a leaky abstraction. Tapestry really does try to present a high-level model for web programming, but every once in a while, you can still see what lies beneath. As he said:

Ten years ago, we might have imagined that new programming paradigms would have made programming easier by now. Indeed, the abstractions we've created over the years do allow us to deal with new orders of complexity in software development that we didn't have to deal with ten or fifteen years ago, like GUI programming and network programming. And while these great tools, like modern OO forms-based languages, let us get a lot of work done incredibly quickly, suddenly one day we need to figure out a problem where the abstraction leaked, and it takes 2 weeks. And when you need to hire a programmer to do mostly VB programming, it's not good enough to hire a VB programmer, because they will get completely stuck in tar every time the VB abstraction leaks.

The Law of Leaky Abstractions is dragging us down.

[1] In 1935, several years after quantum mechanics had been developed, Einstein, Podolsky, and Rosen showed that under certain circumstances quantum mechanics predicted a breakdown of locality. Specifically, they showed that if quantum mechanics was true, then someone could put a particle in a measuring device in one place and, simply by doing that, instantly influence another particle light years away. Einstein called this "spooky action at a distance", and felt it was proof that quantum mechanics couldn't be the whole story. Unfortunately for him, Bell's work in the 1960s, and experiments in the years that followed, proved that this actually does happen. To quote another physicist (Haldane this time), "...the universe is not only queerer than we suppose, but queerer than we can suppose." (Unfortunately, the same seems to be true of many software systems.)

comments powered by Disqus