Wednesday, April 06, 2005

[Java] When Java just doesn't Swing

Josh recently asked Why don't you ship Swing apps?. There's a lot of Java-based applications out there (and more of them are starting to be based on the Eclipse Rich Client Platform) and some of them look really nice; for example, the Azureus BitTorrent client. And then you find out that they are all based on the SWT, and not Swing.

The reason that Swing has fallen out of favour is that it doesn't evolve fast enough. SWT has been evolving as part of the Eclipse platform for some time now, and has gone through several version changes. Here's how they looked:

Date Release
 * For Eclipse 1.0 and 2.0, SWT was not a separately downloadable component
November 2001Eclipse 1.0 *
June 2002Eclipse 2.0 *
March 2003Eclipse 2.1 and SWT 2.1
June 2004Eclipse 3.0 and SWT 3.0
June 2005?Eclipse 3.1 and SWT 3.1

Now compare this with Java releases:

DateRelease
November 1996Java 1.0 (AWT)
August 1997Java 1.1 (AWT)
December 1998Java 1.2 and Swing
May 2000Java 1.3 and Swing
February 2002Java 1.4 and Swing
September 2004Java 1.5 and Swing

The difference is that an Eclipse major milestone release is (a) probably a significantly larger codebase, and (b) about 50% shorter release cycle than the equivalent Java base is updated. As such, wedding the UI to the core Java causes problems in updating the UI. For example, in the early days, in order to run server-side Java on AS/400s and other green-screen systems (mainframes), IBM had to invent a VNC-type solution to be able to pretend to run AWT components, just so they could pass the test kit. Note to anyone inventing the Next Big Language: don't wed yourself down to components and the base language; let them evolve independently.

I've gone on about the difference between SWT and AWT before, so I won't repeat any of it here. But even more than that, the problems with Java GUIs are more than just the UI toolkit; you've got to have a VM installed.

Now, if you're one of the lucky ones reading this who are using Mac OS X, good on you. You know that you're running a version of Java, built into the operating system, but for other less fortunate operating systems, you've got to get Java in the first place. That's a big download; between 40 and 50 Mb depending on your platform.

What's worse is that the update mechanism is diabolical; like other Sun products, they view the 'network as the computer' and so don't mind paying large amounts of money to use it. (Are they co-owned by Cisco?) But if you're on a slow dial-up connection, or are using metered bandwidth (Wake up America! Metered bandwith exists outside your country) then downloading a big file isn't that practical. What's worse, the update mechanism seems to download the entire thing again, instead of being intelligent and downloading just the changes. (Software Update on Mac OS X now does exactly that; when it finds an update, you can download a Delta update, which is just the fixed files.) Would you believe that in order to download new recommended updates from Sun for Solaris, you have to download the entire set of fixes as a ZIP or a CD image, even if you've already got one? And then, when it installs the patches, it runs through every patchset *again*, this time complaining with error code 8 (already installed)?

Their versioning numbers are almost laughable too. Whilst the major numbers outlined about (1.1, 1.2, 1.3 etc.) are a good idea of what version you are using, there's a minor one. It started sensibly enough with 1.0.0, 1.0.1, 1.0.2, 1.1.0, 1.1.1, 1.1.2, 1.1.3 etc. up to 1.1.8. But Sun eventually got embarrassed with the fact they took 8 attempts to get something right, and changed their strategy to have underscores on the end. Here's a complete list of the versions you could download for Java:

Java 1.0
1.0.0, 1.0.1, 1.0.2
Java 1.1
1.1.0, 1.1.1, 1.1.2, 1.1.3, 1.1.4, 1.1.5, 1.1.6, 1.1.7, 1.1.8
J2SE 1.2 formerly known as Java 1.2
1.2.0, 1.2.1_004, 1.2.2_004, 1.2.2_005, 1.2.2_006, 1.2.2_007, 1.2.2_008, 1.2.2_009, 1.2.2_010, 1.2.2_011, 1.2.2_012, 1.2.2_013, 1.2.2_014, 1.2.2_015, 1.2.2_016, 1.2.2_017
J2SE 1.3 formerly known as Java 1.3
1.3.1_14, 1.3.1_13, 1.3.1_12, 1.3.1_11, 1.3.1_10, 1.3.1_09, 1.3.1_08, 1.3.1_07, 1.3.1_06, 1.3.1_05, 1.3.1_04, 1.3.1_03, 1.3.1_02, 1.3.1_01a, 1.3.1_01, 1.3.1, 1.3.0_05, 1.3.0_04, 1.3.0_03, 1.3.0_02, 1.3.0_01, 1.3.0
J2SE 1.4 formerly known as Java 1.4
1.4.2_07, 1.4.2_06, 1.4.2_05, 1.4.2_04, 1.4.2_03, 1.4.2_02, 1.4.2_01, 1.4.2, 1.4.1_07, 1.4.1_06, 1.4.1_05, 1.4.1_04, 1.4.1_03, 1.4.1_02, 1.4.1_01, 1.4.1 , 1.4.0_04 , 1.4.0_03, 1.4.0_02, 1.4.0_01, 1.4.0
J5SE 5.0 1.5 formerly known as J2SE 1.5 formerly known as Java 1.5
5.0, 5.0_01

(If you are still confused about naming, Sun posts a helpful document about it J2SE 5.0 Name and Version Change)

Now imagine that you've had auto-update, or you are someone who downloads a new VM whenever it is out. Assuming you got on the 1.2 bandwaggon rather than before, there have been 18 (1.2) + 22 (1.3) + 21 (1.4) = 61 releases of Java since 1.2 was released. Assuming an average download size of 30Mb, that's about 1.8Gb worth of data, or 4 DVDs worth of information. Realistically, the updates can't have changed every class every time, and if there had been an intelligent update mechanism in place from the start, it might have been practical to keep up to date with Java. (Even the current updater is broken; I'm running Java 1.4 at work, and it tries to persuade me that an update is available; despite the update being for 1.5.) Even more foolishly, each install tries to put itself in different directories, with the result that you end up wtih paths like c:\j2sdk1.4.1_02. What this means is that every time you do an update, you've got to change your JAVA_HOME variable and paths to point somewhere else. Unless, that is, you're intelligent enough to realise that if you install it into C:\Java\J2SE_1-4 then each time an update runs, you can put it in the same place (after backing up the previous directory, of course).

And, just in case Java wasn't taking enough space up for you, when you install it on Windows, it installs a second copy in a JRE directory (with, of course, the same stupid naming conventions). So you can develop and test with a JAR in your lib/ext directory, but when you try and run it in the browser, it fails because it's using a different VM. I mean really -- why do you need two copies of the damn thing installed?

So the conclusion is; there's nothing specifically against Swing that is causing the problem about adoption of Java Swing apps. The problem is that Java on the client side still sucks, and although technologies like Java WebStart help, the problem is that the Sun VM is packaged and updated in probably the worst possible way. No wonder vendors like IBM produce their own VM, and even then only release it as part of a mainstream product when it's had time to go through the 20+ service packs.

I personally think that Eclipse RCP applications will take the lead, because it's a framework for building apps. Creating a subclass of JFrame is never going to be a sensible way of building reusable application components; one of the reasons that there are far more Mac OS X applications than Java applications (and let's face it, Java's been around longer than Mac OS X has, if you excuse its NeXT heritage) is that Mac OS X has always had a good set of frameworks for building applications. As an example; if you want to enable drag-and-drop in your application, you simply tell the component what type of data it knows about. The framework handles the rest. In Swing, you've got to register the listener, register the drop area, provide the hooks for detecting when a drag is started (or cancelled) and do everything at the lowest possible level, even to the extent of animating the icon of what you're dragging under the mouse. With the Mac's frameworks, It Just Works.

I think that a new language will become the new Java in the next five years, and that that language will be an open-source implementation (though probably hosted from somewhere like Eclipse or Apache). When Eclipse is re-written to use that language, Java will be officially dead. Furthermore, this language will have a separate VM download from core component libraries, in much the same way that Eclipse uses plugins to activate its code, and these plugins will be easily obtainable and downloadable without having to agree to proprietary closed licenses. Nor will people complain if they put up the documentation at useful sites like JDocs citing copyright infringement.

In short, Java is dying along with Sun. They're even trying desparately to make people download NetBeans as part of a Java runtime environment, rather than selling it on its own merits. And frankly, the reason why Sun claims so many downloads of Java is because there have been so many patches downloaded by so many people ...

5 comments:

Björn said...

It seems a bit unnecesary to release so many versions of the JRE. But then again I think the average developer will have plenty of bandwidth and the end user will only need the JRE (now ~15MB for windows).


The Eclipse Rich Client Framework is neat and has evolved quickly. It's a pitty that Sun don't develop its libraries in a similar fashion.

AlBlue said...

"I think the average developer will have plenty of bandwidth" -- this misses the point. The developer is likely to have a fast machine, good displays, graphics etc. But at the end of the day, it's the users that take the brunt of the download, not the developer. Users aren't always good at managing updates to their software (how many non-techincal people ask you for advice on configuring their machine?) and it should be considered from their perspective, not the developer's.

Bjorn said...

My point was that the users can download the smaller JRE and not the big SDK. I should have expressed this clearer.

kevin said...

First, I have to disagree with all the releases bothering the client. Unless you are forcing clients to update their JVM each time a patch comes out, I can't imagine why they would need to. Generally, at least from what I have seen, users get a CD with an installer, such as install4J, InstallAnywhere, etc that do a very good job of making the installation painless including the JRE that will be used to execute the program.
At any rate, our project, www.platonos.org, is attempting to provide, eventually, Swing developers a robust, pluggable framework to build from. The site is a bit outdated (updates soon), but it should explain enough of what we are trying to do. If we could get more developers on board to write plugins, the framework could come along pretty fast.

AlBlue said...

"First, I have to disagree with all the releases bothering the client. Unless you are forcing clients to update their JVM each time a patch comes out, I can't imagine why they would need to."

When you install a (newer) JRE, it installs an auto-updater that checks for new versions (either daily, weekly or monthly). When it finds a new version, it bugs you to download it. Given that the _0x releases come out on average monthly, then the user might end up downloading these newer versions without external involvement from the producer.

In principle, that isn't a bad idea, but if I sell a Java app based on Java 1.4, and the installer installs a basic 1.4.1_01 JVM, then I end up making the client download all future versions because of the updater. Hopefully, we're educating our end users to pay attention to items in the taskbar (ala Windows Update) to click on 'download' newer versions. Realistically, a release every three to six months (and with a more obvious version, like we had with the 1.1 releases) would mean less download time and an ability to more tightly specify what to download.

The other end of the problem is when a user already has a Java 1.4.? and you are trying to put the application on top. It might work on your 1.4.2_10 VM, but fails on a 1.4.2_03 VM, because some behaviour in your code exhibits a bug that has since been fixed. If the client files a bug report, or (worse) wants their money back, you've just potentially lost a sale. And asking them to download the latest-and-greatest VM to test a theory may not go down well either.

You therefore end up with the problem that you define your code needing a particular version of Java, say, 1.4.2+, when in fact it would run perfectly fine on a 1.3 VM. Thus, you either lock out more clients, or force them to upgrade.

Note that all of these are problems regardless of the windowing UI toolkit chosen; they're just as applicable for applications based on Eclipse as they are on Swing.

The difference is that if a bug is found (and fixed) in Swing, you are reliant on the version of the VM being updated to fix this. On the other hand, if you are using an external framework, you are less bound by the version of the VM and can just work with updates to the framework. Thus, if you have a framework (such as platonos), if a bug is identified then it can be fixed in the framework level, not the VM level.

The next killer language will have a much more micro-kernel type VM, and libraries (such as AWT, Swing or JDBC) will all be optional add-ons that can be put on top. Amusingly enough, this is exactly what happened with the J2ME family; an ultra-small VM was defined, then sets of libraries available for individuals to append, and then finally, those VM+libraries being wrapped up in a distribution.