J2ME: Write Once, Be Disappointed Everywhere

We developers and other nerdy folk are used to using strange and klunky applications that do something special, and we’re used to that trade-off.

Eclipse is an IDE so it’s hard to imagine it not being baroque and difficult to use, requiring weeks of effort to become productive. JBidWatcher has saved me a lot of money on eBay so I could probably put a dollar value on how much it’s worth to endure its bizarre UI. Azureus is fairly fugly also but it does a very good job and has a deep, sophisticated UI that’s fairly easy to understand, so despite the eyesore, it’s at least fairly clear. The common thread among all of these is that they are all written in Java, and that they are so valuable that it’s worthwhile to overlook the ugly UIs.

Now imagine those sorts of trade-offs, but on already difficult to use mobile devices, and aimed at consumers. Are you making a strategically wise choice by sacrificing usability and control over the user interface, and probably access to platform-specific features such as dialing the phone, in order to save money on development? Adam Breindel talks about this in When Building a Smartphone App, Resist the Siren Song of J2ME.

Adam and I worked on a J2ME application and I totally agree with him about the disillusionment of trying to write a single app that would work across phones. Issues include:

  • Complex and difficult application installation procedures for end-users: How do you install the JVM on the phone? How do you get the plain J2ME app packaged up so that the phone will accept it? Does the app require manual user configuration before use? Is there a different launching process from other apps?
  • Lack of control of the user interface: hardware details such as how many buttons you have, whether there’s a stylus, etc. differ from phone to phone, and the API to let you code once and let J2ME handle the layout for each device leaves your code very disconnected from what’s actually happening on the screen.
  • Not being able to use recent J2ME APIs because even the latest phones only support older, more minimal J2ME APIs
  • Not being able to do things on a phone that would seem obvious, like dialing the phone, opening a hyperlink in the phone’s browser, sending an SMS, or making a network connection. Either these are entirely impossible or require phone-specific or JVM-specific tools and procedures to sign your application, or having the runtime nag the user to request permission to do something that they just asked the app to do for them.

For all the noise Sun is making about broad J2ME penetration, the developer experience is quite disappointing, and as a result, the user experience is also quite disappointing. You can look up J2ME features and APIs and get excited, but when you actually deploy your app to a handset, it won’t load, or runs terribly slowly, or looks awful, or simply doesn’t do the things that the API says will happen when you call it a certain way. Suddenly the strict J2SE and J2EE logo certification programs make sense, because the J2ME approach of making so much functionality specified but optional leaves developers high and dry. The phone supports J2ME version xyz, but write an app coded to that API that works on the emulator and deploy it to a handset and lo and behold, all those optional APIs turn out to be missing even though the handset is capable of that functionality, and some mandatory API functions are not working. Here be dragons.

Case in point: can’t dial the phone on a Treo 650 (at least, not as of a year ago). The J2ME API tells you how to do it. The PalmOS JVM (made by IBM) lets you make the API call, and returns a successful response. Nothing happens. IBM says they’re aware of this issue. The end. The docs say you can, the code you write says you did, the phone just doesn’t do it.

Case in point: Every time you start an application and it accesses the network for the first time on a Treo 650, the user is nagged for permission to access the network. Quit the app and start again, nagged again. IBM has a tool that you can use to sign the app, but you have to use their VisualAge Micro Edition IDE which costs hundreds of dollars to do that. Try and find and download the trial version. A year ago, it was not possible. So, making that persistent nag go away probably costs several hundred dollars. (I never verified that it actually works, just that IBM says the way to sign the app so that it’s trusted is to do that, and that there was no available free way to get that tool.)

These are minor issues, but they certainly interfere with the quick usage pattern of a mobile app, and make it annoying to use your app. Imagine what that would be like if you had a competitor with a native application for that phone, whose application probably cost them more, but their app is better and the user likes it a lot more.

The important distinction here is not cost, it’s ROI. It costs a lot to develop a similar application for each smartphone platform, using that platform’s native tools. It would seem to cost a lot less to develop a J2ME app. But that’s only if you assume that it’s OK to abandon features and settle for a horrid user experience in the course of development.

It’s likely that your goal as a development team is to develop an app that has a predefined feature set that you know the device can support, and a predefined UI design that your mobile-savvy UI people are sure will go over well with users accustomed to that particular kind of smartphone. In that case you will almost certainly fail to accomplish that goal using J2ME. You have to scale back your goal so that you’re satisfied that you got something kinda like what you wanted working on a bunch of phones, and determined users will probably be able to figure out how to install it and make it work.

I call that phenomenon “write once, be disappointed everywhere.”

Let’s continue talking about cost, though. The native apps may require (or suggest) different programming language skills for different devices. It might seem wise to just write everything in C, but I think that’s a false economy as well. The phone APIs will differ so much that you will really need a native developer for each platform, not a team of generic C developers who will figure out the individual phone stuff and be freely floating resources that you can assign to whatever app version needs their attention. Smartphones may run Linux, may run Windows Mobile, may run PalmOS, may run Symbian… these are different operating systems with very different ideas of how applications run and coexist. The platform specific knowledge (APIs, appropriate UI feel, device capabilities) is probably an order of magnitude harder to learn and maintain than the ability to get an application working in a given programming language.

How much of a great C programmer’s skill is really the C language, and how much of it is proficiency with the available libraries on the platform he or she is accustomed to? I think close to 90% of their professional skill set is platform and library familiarity, and 10% syntax and low-level understanding of how the language actually works.

In light of this (just using C doesn’t mean developers or code are portable across smartphones), consider that there are high level languages available for some smartphones. What if that 90% platform familiarity means they can use a language and/or development environment that makes them 5 or 10 times as productive, after spending just a few days or a couple of weeks learning the language syntax?

After our very disappointing J2ME-on-PalmOS port experience, Adam found Handheld Basic which initially appalled me (oh no, BASIC!) but turned out to be a great choice. It’s a flavor of BASIC, so learning the language didn’t take long, and the support happens to be quite good (lots of code samples) so picking up the library portion of that 90% didn’t take long at all. I imagine that C# on Windows Mobile is similar. As more and more phone start to use Linux as their OS (which will be a particularly huge improvement for PalmOS based phones), you’ll be able to use Python, Ruby, Mono, J2SE (a whole different animal from J2ME), TCL, or pretty much any other high level language available for Linux. At LinuxWorld 2006 I saw a development device running unmodified GNOME desktop apps running on a PalmOS device alongside PalmOS apps. There are more options appearing all the time, and with the exception of Handheld Basic, most of them are ports of familiar, mature, well understood desktop languages, with class libraries relevant to mobile devices.

So, I recommend that you work in whatever high level language lets you do all the platform specific stuff you want, and if that means a different language per phone, that’s actually going to be the least expensive way to get to the apps you actually wanted to build. A big chunk of the scary cost of developing native apps goes away, because native doesn’t necessarily mean abandoning Java for C. (In fact I found Handheld Basic to be a more productive environment for me after a couple of weeks than J2ME was, despite my ~8 years of full time Java experience before starting that project.)

That pretty much means no reuse for you. Sorry, but that’s the deal right now.

If that unique-app-per-platform cost is too scary, consider a few ways to save money:

  • For networked apps (aren’t they all?) ask yourself if there’s some logic that could just as easily be done on the server as on the client. Is there some complicated parsing code on the client that could be simplified by changing the response format from the server to something that’s easier to parse?
  • Can you remove or alter certain features from a subset of platforms you intend to support, so that your premium supported platforms get your ideal app, whereas a few less popular phones still get a nice app, but perhaps one that doesn’t have every feature available on your premium app. You might be reading this and thinking “but that’s what you said J2ME would force me to do! Why is this any better?” The distinction is that you are in control of the decision of what to leave out to save money, whereas with J2ME it’s the platform vendor who makes that decision for everyone using their platform. If you’re writing an address book, not being able to dial the phone is lethal; not writing the code to let the user attach a photo to the entries is not.
  • Can you move some user-facing functionality to the server to make the client simpler? Maybe there are some rarely-used features that could be done via a desktop or mobile web browser, so you can focus on putting the ten-times-a-day features on the handset, and making those features fast and convenient. You probably already made that trade-off in general, but perhaps for some kinds of handset, you’ll move the dividing line a little further, so that for users of particularly rare phones, some moderately frequent features can’t be done on the phone. This could also be a good approach for new handset types: design a “lite” app and a “full” app version, build the “lite” app first on each platform, and let user demand tell you whether the full app is worth it. Your developers can tell you much more accurately how much the incremental functionality would cost, since they already have done the lite version. Maybe you’d provide a VoiceXML interface, or mobile web browser interface, for that feature so that the user can still do whatever the feature requires while they’re far from a desktop PC.

A final consideration: labor. Maybe you have some Java developers, or C developers, and don’t have developers good at Handheld Basic or C#, so you’re not inclined to fire them all and hire new developers to do native apps, you’re thinking maybe C on every handset, or J2ME, is still the right choice. I still say that you should probably use native apps in native high level languages on every smartphone platform. If you’re committed to a strategy of good apps on a bunch of different phones, I think I’ve made clear that native apps are the only way to currently get there; J2ME simply doesn’t let you make good apps. So what’s left is C code written by C developers vs. high level code written by C developers who have to retrain.

As I said above, I don’t see much chance that your developers or your code will be portable across different smartphones if you use C. Maybe you’ll get 5-10% savings that way (some code ported across phones, or some developer hours shuffled between platform teams). But you’d get a 5-10x cost saving from using something very modern and high-level instead of C, and the overhead of training for the language would be very very small as compared to the large and unavoidable overhead of having to learn what the handsets can do and how the APIs for the handset’s OS work.

I suppose that means that if you have a bunch of C developers who lack smartphone skills, you’re in a pickle, but that situation seems kind of unlikely to me (a mobile app company hires a bunch of Unix and Win32 C developers with no mobile phone skills?). More likely is that you’d find a mobile developer who is proficient with one or more handset OSs and the best tools for each one, and they may be of the opinion that C is the best choice since they can reuse skills and some code across platforms. I would say that in that case you need to convince them to (or more likely encourage them to do what they were already considering, which is to) go ahead and find a highly productive high level programming language/environment for each smartphone platform.

A final possibility if you have a ton of platforms to target and a pile of killer C programmers is to try and port something like Python across most of your target platforms, or to make a very high-level API or domain-specific language that runs inside your own custom C portability layer. You might be able to find an open source option that you can invest some developer hours in, so that the actual application-specific code that you write on each platform is minimized and portable. But I suspect that this would still be expensive and would result in some J2ME-like UI abstractions that ended up being very unsatisfying in the end.

Best of luck!

2 thoughts on “J2ME: Write Once, Be Disappointed Everywhere”

  1. http://en.wikipedia.org/wiki/Standard_Widget_Toolkit

    Your second paragraph doesn’t make much sense.

    Eclipse and Azureus use SWT. SWT is a wrapper for native widgets. It uses native visual interface elements. If Azureus is an eyesore and Eclipse is difficult to use it has nothing to do with Java.

    However, the fact that they consume an obscene amount of memory and have dreadful startup times has everything to do with Java. ;-)

  2. >SWT is a wrapper for native widgets.
    >It uses native visual interface elements.

    True, but SWT adds its own widgets as well.
    http://www.eclipse.org/swt/widgets/
    (This makes perfect sense from a SWT designer’s POV; if I were developing a portable GUI layer like SWT I’d want to make sure I included a bunch of commonly used widgets to make my toolkit complete and robust for developers.)

    Sadly, just because some platform somewhere has a widget that you like doesn’t mean that cloning it and putting it on all platforms as-is is a good idea for usability. Strange widgets that are unique to this one funky application do not make users happy.

    Examples: CTabFolder is SWT specific. CoolBar is as well. Most of the SWT widgets are similar in concept and general look and feel to native widgets, or widgets found in popular applications but they are not native.

    The Eclipse and Azureus UIs are quite similar in the ways that they suck, and I don’t think that’s a coincidence.

    In particular, the oddity of the single paned window with lots of docked tabs is very clumsy. Try using Eclipse on 2 screens (laptop with external monitor), or generally in any multi-window configuration, and you’ll quickly see how poorly it works. Compare this to Photoshop’s support of multiple windows on the same document, drag and drop working well within or between documents, oodles of dockable closeable resizable collapsible tabbed palettes, and it all works.

Leave a Reply

Your email address will not be published. Required fields are marked *