Why I will also never deploy with Java Web Start again

Keith Lea pointed out that he will never deploy with Java Web Start again.

With Web Start in its current form, he’s be deploying with it long before I will use it again.  “Never” is much too soon.. here is why, echoing and expanding on Keith’s experiences. Some of these things are not Web Start’s fault per se. But they are unavoidable with Web Start.

A key piece of background: the most important point of Web Start for us is the notion of auto-update. We periodically put a application Jar up, update the JNLP to point to it, and our users get the new version running on their PC without a re-install process.

Java Web Start doesn’t work for a large number of users

We have the same trouble here. With a large number of users, inevitably Web Start does not work for all of them. For a few percent of users, it simply does not work. We don’t know why. Yes, we upgrade them all to the current Java, the current browser version, etc. Most of the time we get around this with a cycle or two of completely removing then reinstalling Java. In a few cases, the solution was to repave the machine entirely. Both of these are a considerable burden on our customers.

Users don’t like the experience

The part they hate most is this: the auto-update to the current application version is not optional. We upload a new version, and the next time a user runs the application (if Web Start’s update works… see below), they get the new version… even if the new version is a couple of megabytes of bloat… even if the user is on a slow, wireless link… even if the user only wanted to use the application for a minute or two.

Java/JWS detection in the browser is necessary, and unreliable

Mercifully, we have been able to avoid the problem by other means; our customers install Java on a machine right before they launch our application with Web Start.

Users don’t know what JNLP files are

… and they unwittingly misuse them

There is only one right way to use a JNLP file with Web Start, if you want Web Start’s auto update capability to work: pass around / link to / email the URL that points it it. But in the Real World, user misuse JNLP file in many ways:

  • Email the JNLP to a group of users. The users then click on it in the email… so they get the old JNLP each time they click on it. From there the auto-update (based on the URL in side the JNLP) might or might not work.
  • Copy the JNLP file on to the desktop. They do this because the “feature” in web start to create desktop icons, appears to semi-randomly work or not work.
  • Put the JNLP file on a machine, then disable web browsing on that machine… thus disabling Web Start’s auto-update… invisibly.

You cannot make the user experience much better

Most of the unpleasantness happens outside of the application’s control.

Random Caching

Web Start has a cache. The browser has a cache. Between the two of these, sometimes it is not possible to persuade Web Start to update an application to the current code (in the current JNLP file on the server). There is no visibility in to where/when/how-long the old JNLP data is cached. Sometimes clearing the browser cache fixes this, sometimes it is necessary to remove and reinstall the Web Started application. This is enormously frustrating when a field user needs the current application version Right Now, which you deployed to your Web Start web server some weeks ago.

Wireless Hostillity

Wireless network connections are sometimes slow and unreliable. Web Start always downloads a whole file or fails, as far as we can tell; thus a user on a weak connection might repeatedly wait several minutes for a Web Start update, have it fail, then start again at the beginning. Of course they can’t cancel the update as noted above.

If Not Web Start, What?

Like Keith, I have concluded that a native, non-Web Start solution is the way to do. We’ve built this sort of this for several past applications, and while it takes some coding and testing to get it right (work we planned to avoid by using th off the shelf Web Start approach), it tends to work very well. Here are some key design points for auto-updating applications:

  • The user is in control. Tell the user you have a new version to offer. Perhaps start downloading it in the background. But don’t try to force them to update now.
  • Tell the user about the new version in the application, perhaps in the status bar; not only at application startup.
  • Keep the old version, and expose it to the user. The new version might not work, so if they user can click a button to run the old version instead, you have transformed an emergency in to an inconvenience. (It has been suggested that we should not update our JNLP files, rather put up a new JNLP and pass out its URL. This is totally unfeasible for our, since most users would update rarely or never.)
  • Download in the background. The user can keep getting their work done with version N while version N+1 is downloading.
  • No silent failures. If the application can’t access its update information, expose this fact clearly to users and support staff.
  • Dodge the browser cache. Do whatever you must do, to have as few layers of caching as possible; ideally just one layer, in the application auto update mechanism itself. One way to avoid the browser cache is to use a “raw” HTTP-over-TCP library in the application.
  • Incremental Download – if a new version download retrieves 1.9 megabytes of a 2.0 megabyte file, keep the 1.9 and start there next time.

Rhino and Web Start

We discovered today that by default, Rhino (the Mozilla project’s Java-based JavaScript interpreter) does not work inside of a Web-Start-launched application; it fails with a permission error due to loading of dynamically created classes. After a few minutes of furious searching, it seems that there are surprisingly few mentions of this issue, which affects lots of other tools when used under Web Start; it makes be wonder how many projects are using Web Start.

A solution was forthcoming from Heng Yuan, who described it in detail in a Rhino Bugzilla entry, and provides a solution/workaround as part of his CookXml JavaScript Extension. Mercifully, you need only two classes from that package (which has a BSD-like license). These two classes depend on no other files therein; I’ve posted those for easy download:

CookXmlRhinoWebStart.zip

The lines needed to invoke them look like this:

// org.mozilla.javascript.Context

context.setOptimizationLevel(-1);

ProxyJavaAdapter.init(context, scope, true);

Hints at Win32 Deprecation

I just read today (wow, where have I been?) about the issue with Win32 binaries under the (delayed) Vista version of Windows – most notably, that Win32 binaries will need to be signed, otherwise they will provide a, er, “downlevel” user experience. A proposed workaround is to code to another runtime environment (.NET, Java, Ruby, you name it) so that getting the actual Win32 binary signed is someone else’s problem.

This reminded me of comments I made a few years ago, closer to the dawn of .NET: that if .NET works out well, native binaries will end up deprecated, supported for a long time but in the same way that we can still run an ancient DOS “.com” binary on Windows XP… i.e. not really as first-class citizens. At the time I got rather negative feedback to such a comment, but now the Vista feature above seems like the first step in that direction.

Update: As far as I know, this feature did not make it in to Vista – unsigned EXEs are still OK.

To Wrap, or Not To Wrap (Jemmy)

Yesterday I mentioned a talk by Mike Feathers about API design.  One of the topic of API wrapping, which we do frequently here at Oasis Digital, for a variety of reasons.

By coincidence, today the question came up of whether we should wrap the API of Jemmy, a Swing GUI testing tool.  Our natural inclination is to wrap.  But there are oppossing forces as well.  Here’s where I ended up:

  • The Jemmy API is large, and thus tedious to wrap.  (Which might be a good reason to wrap it…)
  • We haven’t used Jemmy much yet, so we don’t have any real idea what subset of its API we will use.
  • We haven’t done much GUI test automation yet, so we have little reason to think we know much about API design for that.
  • There are developers “out there” who know how to use Jemmy. Perhaps we will hire one, and benefit from them already knowing how it works.
  • Thus, we should start out using Jemmy as-is.
  • Once we have a moderate body of code (enough to understand out use, but not so much that revamping it would be burdensome), review this decision and decide whether to wrap it.

Michael Feathers at XPSTL

This evening at XPSTL, Michael Feathers (blog) (book) was in from out of town (and from around the world) and gave a talk on API design. He’s been thinking a lot about API design recently, driven by issues that come up with working with legacy code, which talks to lots of APIs, to cajole it in to a more testable state. I think there is a lot to say (maybe a book’s worth?), and a lot of what has been said elsewhere turns out to yield APIs that are unduly difficult to build testable code with.

What we end up doing here, and a thing that Michael says is not at all unusual, is to “wrap” most APIs with some application code, to enable:

  • a simplified way to call the external component / API, more suited to our needs
  • easy testing, as we can design our wrapper to make it trivial to substitute a test/mock implementation
  • a buffer from future changes in the external component / API
  • easier migration to alternate implementation of the same underlying services

Our wrappers tend to be “flatter” and simpler than the underlying APIs we wrap. For example, most of our use of Hibernate is behind a class we call DataSession, which represents the connection/session, transactions (it encodes our policies on how to use transactions) and many named methods for query operations (thus we avoid scattering HQL or SQL around the project).

Also, we had a big crowd at XPSTL – the room was packed.

The J2EE / Rails / TurboGears / etc. Video

Lots of people are linking to this excellent video (presentation and screencast) by Sean Kelly at JPL (380 megabyte, 30+ minutes, worth it):

http://oodt.jpl.nasa.gov/better-web-app.mov

Watch it all the way through. Wow.

It’s a little over-the-top in its J2EE example; but the disparity is still stark… and near to my heart as we have a time tracking web application in development.

But I think he stopped short of a fundamental point: that the benefits of dynamic languages, XML-free convention over configuration, fast turnaround, etc. are not specific to GUIs or web applications; he experienced them there and showed them there, but as far as I can tell the same issues and benefits apply equally to the non-GUI tiers of a system.