Wednesday, October 31, 2007

Leopard, Java6, and immaturity

I have never before been ashamed to be a Java developer.

Apple did not include Java6 in last week's release of OS X Leopard. This came only a few short weeks after Apple pulled a Java6 beta that was available on ADC, with no word as to why. These two factors together seem to have triggered a firestorm in parts of the Java community, the most infamous being Michael Urban's disjointed rant over at JavaLobby where he fumes about the above issues at length, and eventually concludes that he's going to take his toys and go home, e.g. abandon OS X as his dev platform. The tone and content amount to nothing more than "I don't have what I want, when I want it, so SCREW YOU!" Judging from the comments he was hardly alone.

This is just embarrassing.

Leopard has been out for a grand total of five days. Five. Having such an extreme reaction to the lack of Java6 in the .0 version of Leopard is just...  wow. I really don't have words for it. Arrogant? Short-sighted? Immature? Completely ignorant of what it takes to get an operating system shipped? It certainly isn't supported by history.

Once Java 1.4 was added to OS X 10.0, Apple has always included Java in its operating system. Always. It is apparent that Java isn't a top priority for the company, but that does not mean that it has *zero* priority, or that those priorities are even skewed. Apple's primary target is and always has been the consumer market. Java simply isn't a player in that space. Further, Java powers much of apple.com -- including the iTunes Music Store -- so it is hardly in Apple's interest to neglect it.

None of the complaints change the fact Macs are still an extremely enjoyable environment to develop Java applications on, far better than Windows or Ubuntu. For me this is the important part: what tool do I feel most comfortable using? Java6 availability changes that not at all.

Even if Java6 were available its lack of penetration even within the Java-sphere would really make it more of a novelty than a must-have. Sad, possibly, but true.

----

Addendum: There are a few words that when I run across in an article cause me to immediately take what is being said less seriously. "Fanboy", "zealot", and their ilk are large red flags. The newest one is "Steve Jobs". From the previously linked to article: "But once again, the part I have really had it with, is the unprecedented arrogance of Steve Jobs and company..." Steve Jobs has had more unsupported adjectives thrown at him than I think anyone since Bill Clinton. For many Jobs has become a rhetorical foil, something used more for emotive effect than anything else.

Thursday, October 11, 2007

JCAPTCHA: Never mind. We hates it.

So after spending numerous hours last night trying to figure out how to create a custom CAPTCHA image using JCAPTCHA, I realized a few things
  1. The documentation is, to be kind, sparse. Also it's written by people whose first language is decidedly not English. That's fine if the code is so elegant as to be self-documenting, buuut....
  2. The API is difficult to grasp. It relies too heavily on inheritance; a few strategies and a Builder would help to clean things up immensely.
  3. If you decide against using one of the built-in image generators, then you must familiarize yourself with an undocumented collection of ImageFilters for which the source code is unavailable.
    TwirlFilter is a perfect example. Figuring out how to implement a TwirlFilter required becoming a monkey banging away on a keyboard: eventually and almost totally by random I got something that worked. Further, some of the methods inherited by TwirlFilter actually cause NPEs when called, and since there's no documentation there is no way to tell what does what or, in some cases, even what units are expected.
    For example, TwirlFilter.setAngle(int) takes radians as its argument, but there is no way to know this in advance.
This is just a workplace shooting waiting to happen.

For posterity's sake, here's how you would implement a TwirlFilter in JCAPTCHA:

  protected void buildInitialFactories() {
   
WordGenerator wg = new RandomWordGenerator(CHAR_LIST);

    FontGenerator fontGen =
new TwistedAndShearedRandomFontGenerator(new Integer(24), new Integer(30));
    BackgroundGenerator bgGen =
new UniColorBackgroundGenerator(new Integer(200), new Integer(100), Color.WHITE);
    TextPaster textPaster =
new RandomTextPaster(new Integer(5), new Integer(8), new RandomListColorGenerator(TEXT_COLORS));

    ImageFilter
[] noFilters = { };
   
    TwirlFilter twirlFilter =
new TwirlFilter();
    twirlFilter.setAngle
(1);    // In radians
   
   
ImageFilter[] textFilters = { twirlFilter };
    ImageDeformation bgDeformations =
new ImageDeformationByFilters(noFilters);
    ImageDeformation textDeformations =
new ImageDeformationByFilters(textFilters);
    ImageDeformation finalDeformations =
new ImageDeformationByFilters(noFilters);   

    WordToImage wordToImage =
new DeformedComposedWordToImage(fontGen,
        bgGen,
        textPaster,
        bgDeformations,
        textDeformations,
        finalDeformations
);

    addFactory
(new ShearedWhiteBackgroundGimpyFactory(wg, wordToImage));
 
}