Dienstag, Oktober 10, 2006

Knowing J2ME, Knowing J2YOU

I've been working on a project for about six months now (including a three-month "freak-out quitting and doing other things" period in the middle) and thought it was about time I share with you some advice in case you're considering a similar project in the future.

For those of you who are unfamiliar with the J2ME environment, Java, or programming in general, allow me to explain. J2ME is a toolkit I use for developing programs (MIDlets) on cellular phones running SymbianOS (it stands for Java 2 Mobile Edition). Because a cellphone isn't a computer, the Java libraries are not exactly as full-featured or robust as those in the standard Java library, but when it come to development this is only a problem in certain areas. For most purposes the reduced libraries are, for lack of a more descriptive word, suitable. When it comes to finding and fixing bugs, especially in a threaded environment, however, you're better off taping every possible solution to a giant wall and throwing a knife at the right one blindfolded.

The good folks at Sun are easily bored and must live very dull lives, because it would seem from a debugging standpoint that the exception handling abilities of J2ME were a cruel joke to provide them with brief amusement and the programmer with nothing. Normally when an error occurs and the code catches it, an exception is thrown and one is able to view the procedural stacktrace to track down which function caused the problem. Despite the performance loss due to having to include dozens upon dozens of try {} catch {} statements, Java's exception handling saves countless hours of scouring a very large program for errors. And indeed, as some may have noted while reading this, there is a printStackTrace() method for Exceptions in J2ME. Let's compare the output of two stacktraces: the first is one I pulled off the web that illustrates how well a bug or unexpected error is documented by the JVM, and the second one illustrates why mobile programmers often take three month freak-out vacations from a project:

Standard stacktrace:

java.lang.ArrayIndexOutOfBoundsException
MESSAGE: 8

STACKTRACE:

java.lang.ArrayIndexOutOfBoundsException: 8
at com.mysql.jdbc.ByteArrayBuffer.readInt(ByteArrayBuffer.java:224)
at com.mysql.jdbc.MysqlIO.unpackField(MysqlIO.java:607)
at com.mysql.jdbc.MysqlIO.getResultSet(MysqlIO.java:414)
at
com.mysql.jdbc.MysqlIO.readResultsForQueryOrUpdate(MysqlIO.java:1962)

at com.mysql.jdbc.MysqlIO.readAllResults(MysqlIO.java:1419)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1728)
at com.mysql.jdbc.Connection.execSQL(Connection.java:2988)
at com.mysql.jdbc.Connection.commit(Connection.java:2161)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at
com.ibatis.common.jdbc.SimpleDataSource$SimplePooledConnection.invoke
(SimpleDataSource.java:946)
at $Proxy0.commit(Unknown Source)
at
com.ibatis.sqlmap.engine.transaction.jdbc.JdbcTransaction.commit(Jdbc
Transaction.java:66)
at
com.ibatis.sqlmap.engine.transaction.TransactionManager.commit(Transa
ctionManager.java:83)
at
com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.commitTransactio
n(SqlMapExecutorDelegate.java:759)
at
com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.commitTransaction(Sql
MapSessionImpl.java:133)
at
com.ibatis.sqlmap.engine.impl.SqlMapClientImpl.commitTransaction(SqlM
apClientImpl.java:110)
at
com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.autoCommitTransa
ction(SqlMapExecutorDelegate.java:866)
at
com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.insert(SqlMapExe
cutorDelegate.java:451)
at
com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.insert(SqlMapSessionI
mpl.java:81)
at
com.ibatis.sqlmap.engine.impl.SqlMapClientImpl.insert(SqlMapClientImp
l.java:58)
at net.saf3.biblio.Test.main(Test.java:265)



Simplified mobile stacktrace:







Are you asking yourself where the second stacktrace is? That's a coincidence - so am I! It turns out it's sent to the error stream, which is defined by the System class. In regular Java you can easily view this stream because it prints to your console or wherever you have it piped. You can even use a method called System.setErr to send it somewhere else! In J2ME there is no such method, so the only way of retrieving it is to view the error stream. Where is that? Good fucking question. It turns out that for anyone using SymbianOS 7.0 prior to Feature Pack 3, there isn't any possible way to view the error (or the standard output) stream (for those using FP3, you still can't change it; you can, however, download an external program to run in the background and capture the error stream). So why do they have an error stream you: a) can't view; b) can't change; and c) provide as the only means of viewing useful error messages considering points a and b above? Those are three good questions that deserve answering. But considering this is Sun Microsystems, the answers probably cost $3,000USD for a 4-hour executive programming seminar to learn.

If that weren't bad enough, for security reasons you do not even have access to FileStreams. In other words, if you want to try and do your own debugging and save it to a file, you have to use binary-format RecordStores that slow your program down to the point of making debugging real-time apps where milliseconds make a difference almost worthless.

Did I forget to mention threading? What a fun place to track down bugs. It's difficult enough in the World of PCs and Servers to quickly debug multi-threaded applications. But if you ever get cocky and think it's not so hard, try it on a platform where a synchronising error crashes your program with an extremely helpful message from the OS along the lines of: "java.comms.38af01@ab5550f Monty Thread -7"

Is -7 the error code or the thread number? If it's the thread number, can I just send a list of all the threads to the RecordStore I'm using to make debug logs with and track the error down within that particular thread? Sure, but ask yourself this: is the inclusion of all that expensive RecordHandling having an effect on which threads are created in what order, or is it the same order as without? Will the error appear again or did the addition of all those costly debug lines make it just squeak by this time exception-free? The fun thing about J2ME is, you haven't got a fucking clue if your program is running fine or just dependent upon a careful balance of shitty, slow code that gives the illusion of success. Have you ever watched a slapstick comedy or a cartoon where a character is unknowingly in danger but keeps bending over or turning around at just the right time to avoid some sort of attack or peril? That's essentially a very elaborate flowchart for the design of most multi-threaded mobile applications.

But we Java mobile developers are not completely without assistance with these strange messages. There's a handy little program called Panix one can download which runs in the background and, upon an error such as this, will provide you with some useful information. Of course, a few times I've tried to run it after getting an error like this the added cost of having a second program running in the background has altered the behaviour of the program I'm trying to debug so that the error doesn't appear anymore. Close Panix and try again, and there's the error just as before. Ah, the magic of threaded programming. One change in timing and your programming suddenly appears bug-free until some date later in the future when the alignment of the stars causes it to show up again and disappear just as quickly.

Perhaps some of you, most likely Java programmers who haven't had the misfortune to have to develop mobile apps, are shouting, "What an idiot! Why doesn't he just use the emulator to debug?" Ye poor, naive bastards, ye. While the emulator is handy (no pun intended) for working out the early-stage bugs, when it comes to things like Bluetooth or networking under changes in signal strength, the emulator either doesn't support it at all or would be completely unreliable as an accurate test of the real hardware. You end up commenting-out the unsupported objects and methods just to keep the emulator from exiting with an Exception, which creates a much different application from the one you're attempting to roll-out.

In conclusion, I'd just like to say that you people who use your cellular phones blindly, complaining about how Program X is always crashing or not giving a fig about what kind of work went into developing something that isn't always crashing...you people can kiss the biggest part of my ass. If it were up to me we'd all go back to using old-timey wooden telephones with hand-cranks and Java would go back to being put to use where it is best: making shitty games for Yahoo and BitTorrent programs that require tons of RAM.

Freitag, Oktober 06, 2006

Limbo Security

Because my comments posted to BBC News almost never get accepted (I believe my success rate in the past 3 years is something like 1 out of 8 with 7 unexplained rejections), I'm going to save it here for the benefit of the newsreading public:

http://news.bbc.co.uk/2/hi/uk_news/magazine/5406552.stm

The Pope may be about to abolish the notion of limbo, the halfway house between heaven and hell, inhabited by unbaptised infants. Is it really that simple?


Here is my comment:

I welcome these changes for one. For too long have babies been living it up in limbo while the rest of us non-Catholics go to Purgatory or Hell. For anyone who says they're free of sin, have you ever tried getting a full night's rest or enjoy a weekend with one of these criminal masterminds around? Pack your bag, infants. Your "get out of Hell free" card just expired.


Let's see if it actually makes it. I am not going to be optimistic.

More Political Nuttiness

The right-wing anti-immigrant party the BZÖ has encountered some more hilarious trouble. A few weeks ago a top party official quit and started saying a lot of shit about them. Her PR man just happened to be in a pub-restaurant in Vienna where a lot of right-wingers go, when Peter Westenthaler (the spokesman of the BZÖ) came in with his bodyguards. He told his bodyguards to "get this asshole out of here," after which they picked him up, kicked the shit out of him, and threw him outside. Oh, I forgot to mention something: Peter Westenthaler, while being anti-immigrant to the point of comic tragedy, is really named Peter Hojač. He switched to his mother's maiden name to hide his origins.

I've said it time and time again, and how many times must I tell people? When you let right-wing parties led by short men pretending to be German come into your pub, it only causes trouble.

Edit: I forgot to include this hilarious image taken in Vienna of the still (for now) chancellor of Austria, whose party lost the elections on Sunday: Click the image for a bigger version.

Montag, Oktober 02, 2006

Parliamentary Elections

The elections are over (barring any surprises from next week's completion of the yet uncounted 400.000 mail-in ballots). The Socialists are celebrating their "victory" over the conservative party, which in a way is deserved. Technically they did get the most votes out of any of the parties. But if you look at the change in numbers since last year, the victory seems a little smaller. Did the SPÖ win because more people voted for them than last year? No, they won because the ÖVP got -8,1% compared to the last election and the SPÖ only got -0,3%. In other words, both parties lost votes, but the conservatives lost 26 times more than the centre-leftists. That's not really very impressive, is it? It's like winning on Jeopardy despite the fact you've got a negative amount of money just because your two opponents have even larger negative amounts of money. That is only a "victory" in a very semantic interpretation of the word.

Where did those votes go, I wonder? Well, as it turns out, the two Nazi parties, the FPÖ and the BZÖ, gained since last election (technically the BZÖ did not gain anything as their party wasn't in the 2002 elections), as did the Greens. Most surprising (to me) of all is that the Communist Party also gained considerably, although they are not as media-interesting as the Nazi parties and they did not win enough votes to capture a seat in parliament, so nobody really talks about them. It's worrying that the two nutty parties floating a mixture of National Socialist welfare programmes and anti-Turkish sentiments (two of the slogans of the Freedom Party were "Daham [Viennese dialect for "Daheim"] statt Islam" and "Mut zur Heimat" which loosely translate as "Our Home instead of Islam" and "Courage for the Homeland") should gain so many votes.

For me the best outcome of this will look like this: in a week the ballots from Austrians who are living out of the country will be tallied, none of them or very few will be for the BZÖ, which mathematically will push them down from 4,2% to under 4% (the bare minimum for getting a seat), which will kick them out of parliament and they'll lose their 8 seats, the Greens will gain at least a few fractions of a percent, enough to be able to create a Red-Green coalition with the Socialists and force the conservatives and the Freedom Party fascists into a weak minority incapable of pushing through the conservative platform of privatising everything in sight.