March 2003

« February 2003 | Main Index | Archives | April 2003 »

31
Mar

Thread.run()

  • 8:04 PM

I was hanging around at work late, doing a few practical checks on the effects of different isolation levels on overlapping entity bean accesses under Websphere. Oh, the exciting things I get up to in my day-job!

Anyway, the methodology was pretty basic. I had an Entity Bean with two fields. I had a session bean implementing the Command pattern. I had a JUnit test that would throw two commands at the session bean in different threads. By putting delays in the command objects, I could overlap the EJB writes in different ways and then test the outcome.

I know, all the answers to these things are in The Fine Manual, but sometimes it's just better to remove all doubt. It's like that Knuth quote: “Beware of bugs in the above code. I have only proven it correct, not tested it.”

Anyway, the most bizarre thing happened when I ran the tests. No matter what I did, I couldn't get two threads to enter the session bean at the same time. Now I know this is wrong. I messed around with transaction settings. I changed the timing a bit. I thought maybe it was a resource-allocation issue, and the cut-down version of Websphere running inside the IDE was being frugal with bean instances. I checked the spec, which helpfully told me that a container should either allocate a new bean, or throw a RemoteException, nothing in between.

It was while I was writing code to spam the session-bean with about 50 requests in an attempt to convince it to spawn more damn instances that I noticed my mistake. Thread.run() is not the same as Thread.start(). The requests were being processed serially because I was sending them serially. I was never spawning multiple threads.

I was going to rant about how this is all bad design on the part of the Thread class. Maybe it is. But in truth, I'm just an idiot.

Peter Ghali asks about testing private methods:

So how do people test private methods....my opinion is that you should test private methods at all. Adequate test coverage should cover these methods through testing of the public and protected methods that use the private methods. However....

I don't test private methods. Being able to quickly create, move around, and change the functionality of private methods is vital to remaining agile while developing.

There is a significant cost involved in changing the behaviour of your public interface: you have to make sure each caller can cope with the change. Sometimes you even have to write new tests for each caller because you have introduced some new edge-case that wasn't there before. Private methods, on the other hand, can always be tested by running the tests for the enclosing class. If you've introduced a new edge-case, you only ever have to write new tests for that one class. It's all self-contained.

If you have to test your private methods, or if you have to change your tests every time you change your private methods, this becomes a barrier to refactoring. The amount of work you have to do to improve your code becomes the amount needed to change the private methods, _plus_ that required to change the tests. As such, you're less likely to make the improvement.

If you have a thorough suite of tests for a class's exposed (non-private) interface, those tests should, by their nature, verify that any private method within the class also works. If this isn't the case, or if you have a private method so complex that it needs to be tested out of the context of its public callers, I would consider that a code-smell.

Code Kata

  • 7:35 AM

Pragmatic Dave has posted a “Programming Kata”. It looks like a worthwhile exercise, I might post my answer when I've finished it, but I'm way too busy today with work, and the office Christmas party this evening1.

A minor nitpick. While I can see the appeal of picking a cool, martial-arty name for the exercise, it's really not a kata. While I've never done these things myself and could be wrong, my understanding is that a kata is a repetitive exercise to be performed over and over, in order to train the muscles to move and react a certain way. For the un-initiated, think “Wax on, wax off”. Programming kata are, by their nature, problems that once solved can't be repeated.

Still, just because the name is wrong, doesn't mean the exercise isn't beneficial. Other creative pursuits have been doing this sort of thing for years: my friend Lonita, for example, keeps a list of writing prompts for precisely the same purpose.

1 Yes, it's a bit late. We sort of didn't get around to organising it last year. Officially, it's been renamed the Autumn Party, but we all know the truth.2
2 I've been writing far too many footnotes lately.

The specs are very clear. When you get an EJB Home object from the naming service, or when you get an EJB Remote reference back from a finder method in an Enumeration or Collection, you can't immediately cast it to the type you are expecting, you must first pass it through the PortableRemoteObject.narrow() method. This has something to do with IIOP, I believe.

I'm left with only one question. Why in the nine layers of Hell should I care about this CORBA shite?

Why didn't the writers of this spec take that tiny step back and think “OK, they're writing this in Java, so we should obey simple Java casting semantics”. PortableRemoteObject.narrow() was the first step in my steady, and now complete disillusionment in Enterprise JavaBeans. The first time I saw it, even though I was a relative newcomer to OO modeling at the time, something clicked in my head, something said to me this is so very, very wrong.

A part of me is convinced that the only reason there's so much CORBA stuff tied to the EJB spec is because IBM was one of the big backers of J2EE, and WebSphere Application Server was built on top of Component Broker, their CORBA ORB. (Understanding this fact is a crucial step towards understanding some of Websphere's more weird behaviours)1

PortableRemoteObject can bite me.

Update: From the comments so far, it seems I was a trifle too flippant. Yes, I know the technical reasons that a CORBA object needs to be explicitly narrowed. An EJB, however, is not a CORBA object. It's an Enterprise JavaBean. It may be implemented as a layer on top of CORBA, and may be implemented in such a way that CORBA clients can talk to it. But when I'm talking to it in pure Java, I don't care how it's implemented under the hood, and I don't want to care.

What I object to is that even if one accepts that EJB is a Java layer on top of CORBA, I would expect that Java layer to hide the CORBA implementation details, and expose EJBs to me in the idioms of the Java language. If I wanted to talk CORBA to the damned things, Java comes with a perfectly good CORBA API that I can use.

1 Disclaimer: My employer is an IBM Business Partner. Websphere pays my rent. As such, the above is obviously said in the context of a deep and abiding affection for the product. ;)

The Referer request-header allows a server to generate lists of back-links to resources for interest, logging, optimized caching, etc. It also allows obsolete or mistyped links to be traced for maintenance. The Referer field MUST NOT be sent if the Request-URI was obtained from a source that does not have its own URI, such as input from the user keyboard. — RFC2616: HTTP/1.1

I've written about this before. So has Mark Pilgrim, and he's got a much bigger audience than me. If you are writing a news aggregator, web robot, blog indexing tool, whatever, you MUST NOT advertise your product's website in the Referer header. If you do, your product does not comply with the HTTP standard. More importantly, you're being incredibly annoying.

I'm not just being a standards-nazi here. Referer logs are an important tool in running a weblog. Only about one in ten people who link to me use Trackback, so keeping an eye on my logs is really the only way I have to notice any discussion of things I may have said off my site. Referer logs are the link to the wider community. Spamming these logs with irrelevant links to tool sites or portal pages increases the time I need to spend maintaining my weblog.

It's just like e-mail spam. Sure, it gets you a few click-throughs, but by subverting the intention of the medium, you're imposing your advertising on people by getting in the way of what they're really looking for.

The biggest culprits by volume are RSS newsreaders (Although many have stopped since Mark Pilgrim brought it up), but they're only a minor annoyance because they all just hit the RSS feeds, and since there can't really be any legitimate referers for RSS feeds, you can ignore them all. In fact, I rather like the idea of RSS readers leaving behind the site of the newsreader's user in the referer header, so you can see who's reading you. That's useful information, and almost related to the purpose of the header.

The biggest culprits by annoyance-value are the spiders, that hit random pages of the site, and leave their advertisements behind. You generally have to follow the link just in case it's somebody pointing to a bunch of your stuff at once, and it almost always turns up on some portal page that might be quite useful, but isn't what you're looking for at this particular time, so it puts you off ever going back.

The place for advertising is the User-Agent header. Use that instead.

As I was paying for my copy of NetNewsWire, it occurred to me that I've bought quite a lot of Mac software in the last year and a half.

Since buying my Powerbook in December 2001, I have paid for OmniOutliner, OmniGraffle, LaunchBar, and of course Jaguar.

I tried, but didn't buy Spring and Tinderbox, because while both looked neat, they failed my ‘am I experiencing a tangible benefit after five minutes?’ test. I sadly no longer have time or inclination to fiddle endlessly with software in the hope that it'll change my life.

This isn't really much. You'll notice a distinct lack of big-ticket items like Office or Photoshop1 but compared to my software purchases in a decade of using Windows... I think the only thing I bought that wasn't a game was Windows 2000. Everything else was either free, came free with the computer2, or was shareware I never felt sufficiently attached to to register3.

And no, I didn't pirate software either. I just didn't use it.

I'm not sure whether this software I've bought for the Mac is a sign that Mac software is inherently more likely to convince me to buy it, whether it's a sign there's less good free stuff available for the Mac, or whether it's just because I earn far more now than when I was a student, and can afford to pay twenty bucks for something that lets me launch programs faster.4

1 I installed the 30 day Photoshop demo twice, once on each computer. I'm trying to work out if that's immoral or not.
2 I bought a new PC just after Windows 95 came out. I asked “How much is it without Windows?” and the guy in the shop said “Doesn't matter. It's the same price”, so I ended up with Windows 95.
3 I'm aware that technically I should pay for shareware if I use it, not just if I feel like paying for it. I made an exception for mIRC, though, partly because I was only keeping it around to test compatibility with various IRC server hacks I was playing with, but mostly because I refuse to be responsible for a cent going to the guy who perpetrated horrors like CTCP SOUND, or that fucking trout.
4 If you've got Mac OS X, and you don't have LaunchBar yet, run, don't walk to get it. There is no better way to launch applications than this.

I've been meaning to write an article about why I'm discouraged from using Prevayler by the over-blown and annoying hype of its supporters, but Alan has beaten me to it.

What follows is the half-baked rant that would otherwise have been cooked into a real article, had Alan not already said everything I was going to say.

Essentially, I'm sure that Prevayler is a good thing, and solves a particular problem very well, but I'm put on my guard by the fact that I can't find any critical coverage of it. And by critical, I mean articles that say “These are the good things it did for me. This is where I had problems. This is a situation in which it sucked.”. On the Prevayler site, I just get admonishments that whatever my storage requirements, memory technology will speed up to cover them. (Sure. And in the DB2 magazine I glanced through last time I visited the office, there's an article on the new generation of Petabyte databases)

I see declarations in the Prevalence Skeptical FAQ that 25GB of RAM will just cost me $3000, without mentioning the six- to seven-figure hardware I'd have to buy to host that much memory efficiently.

Give me a break.

Even better, give me some balanced, critical commentary that doesn't sound like zealotry.

The brainstorming on JSR-666 continues. The JSR-666 expert group has noted that since Java source is essentially Unicode, there are thousands of potential operators going begging, simply because they don't appear on regular keyboards. This minor inconvenience should not deter us from improving the language, so we are proposing the following additions:

(Note: All these characters display on my Mac. YMMV)

¿
The ‘unless’ alternative ternary operator
double-negation
§
Shift left, then shift right, or, create a new ‘universe’ of objects (the spiral-galaxy operator)
Ø
The empty array.
ø
The little empty array
Ω
The full array
BigInteger.MAX_INT
« »
Canada-friendly comments. e.g. «this comment will be translated into French when compiled in Quebec» or...
«
Shift left, very quickly
Haha, Perl, we've got a real diamond operator!
£
Compress object (may be confused with # in the USA)
Denote a multi-line string literal
©
This object may not be clone()'d without permission.
a ¬ b
From a, subtract most of b or, Sutract b from a, then shift right.

The expert group will continue to ponder any more valuable additions to the Java language that the Unicode instruction set can provide. Submissions from the general public are welcome.

The following would be incredibly simple to implement in the compiler, would require no VM changes, and would tidy up a lot of source code. How about it, Sun. With a bit of a push, you could get this into 1.5 easily.

(Just a spoonful of syntactic sugar helps the medicine go down...)

try {
   // blah
} catch (RemoteException, NamingException, CreateException
    as Exception e) {
   // blah
}

Obviously, the ‘target’ exception type would have to be a superclass of all the exception types being caught in that block. Any exception that does not match the types in the list falls through, even if it is still a subclass of the target exception.

The only downside of the way I've written it is that it introduces ‘as’ as a new keyword, which might break some code, but you could always cheat and substitute some kind of punctuation instead.

It's absolutely insane that there's no way in HTML to associate a caption with an image. Title attributes don't count, you only see them on mouse-over, so they end up being a ‘mystery meat caption’. The closest you can get right now is putting the image in a table, and then using the table's <caption> element to caption it. Semantically, that's Just Wrong.

The <object> tag doesn't help in this regard either.

And, of course, this is never going to get fixed for the mainstream web, because HTML4 is no longer being updated, XHMTL1 is just a transition, and the w3c is going off into their weird fantasy-land for XHTML2.

Mes Souvenirs...

  • 11:22 PM

You find the strangest things in old piles of paper. I've been preparing to move to the new apartment. This time around, instead of just throwing everything I own into boxes, I'm trying to minimise the amount of stuff I have to transfer across the Harbour Bridge, and that involves going through my old piles of paper, some of which have lain undisturbed for up to six years.

Back when I was 21, I fell in love with this girl called Susan. I lived in Perth, Western Australia, she lived somewhere in Idaho. We met on IRC. This is one of those things you can generally explain to people who've been there, and everyone else just shrugs and says ‘You're weird’. Just go with me on this one, OK? If anyone wants to tell me how stupid online relationships are, I'll tell you the story about the girlfriend before Susan, who I met in a nightclub and who I still get sympathy about when I tell the story of our relationship to people in pubs.

Anyway, after a year of being virtually inseperable, Susan flew out to Perth and lived with me for three months. The first two weeks of that three months was enough for us to both decide independently that It Wasn't Going To Work, but neither of us were particularly good at the whole communication thing at the time, so an awful lot of that went unsaid for the whole three months. When she left, everyone tiptoed around me for a while because I should have been depressed, but really I'd already been dealing with that inevitable outcome for ten weeks, and I was pretty much over it.

The basic problem was that both of us were looking to get away from something, and found in the other something quite nice to run towards. If either of us had a moment of introspection (and to be fair, she did and I talked her out of it), we'd have realised that all the evidence had always pointed to us being really quite good friends, but totally incompatible as a couple.

So anyway, near the end of the three months, I wrote Susan a letter, so I could just get out everything that was on my mind without the hassle of it being part of a real conversation. I don't have a copy of the letter, but I recall it was quite bitter: She was over on a tourist visa so I'd been supporting her out of my own pocket for three months, after all. I accused her of never having had any intention of trying to make it work, something which in retrospect I recognise as being really unfair. She wrote me a letter in reply, and that's what I found in the pile of paper. I'd totally forgotten about that letter, I don't even have more than the vaguest recollection of what was in it.

I didn't read it this evening. I skimmed bits here or there, but it may as well have been written to a different person. Time does that to people. The me today is very different to (and very similar to, as well) the me of five years ago, and I imagine the Susan of today is too. But it's nice to know it's around, a reminder of a person I used to be, a memory of a moment in my history.

I've seen Susan since. She went back to the USA and joined the army. When I went to teach a Websphere course in Brussels two years ago, I hopped on a train and visited her on base in Germany. Next time I'm in the USA, I'll have to see if I can pay her a visit, and finally apologise for anything overly bitter I wrote to her, that time in 1998.

Most Wednesday nights, you can find me at the Menzies hotel opposite Wynyard station, playing in the pool competition. I first went four years ago, and I've been a regular ever since moving to Sydney, three years ago. If you're in Sydney, pop down some day and say hi. I'll buy you a beer.

I'm a pretty average pool-player. I play once a week, maybe a little less on average. I have little motivation to improve myself. Most weeks I make it through to the second round, and then lose. Sometimes I fluke my way into the semi-finals, or even the finals. (You used to get strange brewery merchandise for coming second, now it's a $50 voucher for lunch in the hotel buffet).

This week, for the first time ever, I won.

I wasn't even going to go down there. Earlier in the day I'd told Lonita to remind me that I was too tired for the pub tonight, and that I should skip it. But as 6:30pm rolled around and I started getting thirsty, I decided what the hell, why not?

And I won. And I didn't do it by luck. The first two games I scraped my way through (including one embarrassing moment where I forgot which balls I was on, and potted my opponent's). After that, I was suddenly on a roll. I had one of those incredibly rare evenings where I played some damn good shots at just the right time, and made the right tactical decisions to put me in the right place to finish ahead.

Of course, it'll probably be another four years before I do it again, but for now I'm just going to savour the victory.

Mmmmmm. Now just so long as I don't have a hangover tomorrow...

Charles' wacky left-field idea of the day. Incorporate an optional grid-computing client into Everquest. Pop up a window: “Do you want to reduce your monthly bill by allowing us to make use of your computer's idle cycles while you are connected to the server?” (Yes, it'd have to be rephrased for the masses. I'm a programmer, remember?)

Advantages:

  • Existing contracted user base:
    • Includes a significant number of alpha nerds with fast machines
    • Tends to stay connected to the net for a very long time.
    • Has an incentive to get involved
  • Easy to keep client up to date with existing patch system: users are used to frequently having to download software updates.
  • Existing payment structure makes lots of monthly micropayments easy to manage.

Disadvantages:

  • A significant number of the machine's cycles are already being used up by the game. Certainly more than if they were just word-processing.
  • Benefits of being part of grid may not end up making enough of a noticeable dent on an individual user's bill to be worthwhile.

Worth thinking about, though.

Self-importance

  • 11:48 PM

February was the first time my weblog's exceeded 100,000 hits in a calendar month. And that's even if you ignore the two days where I got hit 11,000 times by the same bot. Go me.

Sometimes, I get amused by the self-importance of webloggers, though. We do have a lot of influence, but only in a very small sphere, one that consists mostly of other webloggers.

My brother Nick is a print journalist. Right now he's the Melbourne bureau of the West Australian newspaper (there's apparently one other guy there who covers the football). The West really doesn't get the Web at all. Nick's articles, published in one lightly-populated State of Australia, still find their way to the eyeballs of more unique readers in a day than I, published worldwide, get total, not-unique, and often not-human hits in a month. It's useful to keep that in the back of my mind when I think blogging might be more important than it really is.

In one of the comments to Alan's Naming Classes Without a ‘Manager’ article, Darren Greaves suggests that Util could be another contender in the list of class names to avoid.

I disagree.

One of the tricky aspects of API design, especially when designing the base APIs for a programming language, is deciding what goes in, and what stays out. Think of a string. There are an enormous number of things you can do with strings, but to put all of those operations on the String class would just be impractical and bloated. So as the designer, you take those operations that you feel would be most generally beneficial, such as finding the length, searching for and extracting substrings, and so on, and leave out the rest.

Some languages, such as Smalltalk, Objective-C, Ruby, Python, Perl, CLOS... Okay, a great many languages allow you to add behaviour to existing classes. So, for example, if your application really needs a method that reverses a string in-place and the language designer has decided that's not necessary for the supplied String class, you can add your method directly to the String class and be done with it.

Some languages, and this is where Java sits, don't let you do this. If you want to extend a class, you have to subclass it. And then you're stuck with whatever the superclass has made visible. And you can't do it with String anyway, because String is final. This is why most projects I work on end up having a StringUtil class, and every project ends up with a DateUtil. There are things we want to do to strings and dates all the time, but there's no way to put those things where they really belong, on the String and Date classes. Which is why having a Util class isn't a code-smell per se, it's a smell in the underlying language.

Thus, ‘Util’ is shorthand for “stuff that belongs somewhere else, but I'm not allowed to put it there, damnit.”.

Of course, Alan also tells me that being able to dynamically add methods to classes is frequently abused, and usually a Bad Thing when writing large systems, but having used both approaches on a small scale, and vastly preferring the more dynamic approach, it's one of those things I'd like to be able to find out for myself, you know?

Update: In a comment, Chris Winters says:

Whenever I get the urge to put something in a 'Util' class, I first look at what the various Jakarta Commons groups have done.

This is incredibly good advice, and worth shouting louder. There's a lot of really useful stuff out there. That said, I recently found myself rather cynically reimplementing something I'd seen in jakarta-commons, because I didn't want to fight any battles over adding another dependent library to the project.

I took my first copy-controlled CD back to the shop today. It was Massive Attack's 100th Window. I had bought it desipite the fact that it is probably not politically correct to buy Massive Attack CDs right now. When I got it home, someone on IRC mentioned that a much better reason to avoid it was that it was copy-controlled, at least in the UK.

So I looked at my Australian copy, and there it was, the small sticker on the front of the jewel-case that proclaimed that what I had bought wasn't really a CD, just an imitation CD that was broken just enough so that it only played in the lower grade of audio CD players, and on Windows systems.

Such a product is totally useless to me. I firmly believe that any CD store that sells something like that to me without clearly warning me that what I am buying is not really a CD, is dealing in misleading and deceptive conduct as defined by our various fair-trading laws. And a little sticker isn't enough, thankyou very much. CDs are covered in stickers these days, and until the copy-control sticker is a widely known and looked-for symbol, nothing short of a warning at the counter by the sales assistant will do.

I took the not-CD back to the store. I may very well download it from the Internet (where it is readily available, despite the copy-control) as an act of protest.