Saturday, June 04, 2005

» Justine has won !

Yes! She did it again ! :) Justine Henin just won her 2nd Rolland Garros. Great to see her win after having had a tough year in 2004, plagued by illness twice. And, well, she definately deserves it, she has the best play. Would just have been nicer to see her play again Kim Clijsters in the final. She should have been there as well, giving away an already won game against Davenport in the 1/4 finals. Hey, Belgium is a small country, don't blame us for cheering on our very rare successes ;)

» Bought myself a Flickr account

Just bought myself a Flickr "pro" account. Great stuff, I love it :-) I'm in the process of uploading the great photos I shot during my holidays in Croatia, in 2004. Have a look and enjoy ;-) To upload the pics from my Linux box, I use juploadr. Written in Java (uses SWT), simple, cool, works.

Friday, June 03, 2005

» Writing good Javadocs

A couple of articles and documents I recently read made me think a little deeper about how to write good Javadocs. Disclaimer: my background is that my coworkers and I are developing a platform (or framework, call it as you want) that's being used by many other development teams, so I definately have a different focus than when you're just writing an end-user application. IMHO, the Javadoc of a public class and/or public method is a contract between the class/method's API and the client (be it the class that uses it or the developer that writes the code that uses it). You should write what the class/method does, not how it does it. One should give as few information about how a method is implemented. That's in the same vein as: it's better to give back a Collection than a Vector, and it's even better to give back an Iterator than a Collection. The less you tell a developer that uses your API, the less assumptions he will be encline to make. Hence, the easier it gets to change the implementation of the API and keep backwards compatibility, both on the API itself and on its behaviour. Let's pick one aspect, null. When using 3rd party APIs (say, JAXP, JDOM, Spring, ...), didn't you ever ask yourself: can I pass null as that method's parameter or may I not ? To me, it should always be specified in the Javadocs of a method's parameter whether it may be null or not. And if it may be null, how the method behaves, what it means. Granted, it's a tedious job. But on critical, public APIs (actually, every public API is "critical") it's a very important aspect that too few developers care about. As an example, say that your method doSomeThing(String)'s implementation doesn't specifically check whether that String is null or not. When passing null, it happens to result in having a NullPointerException thrown. If it's not documented as such, a developer that uses your method may simply assume that it will always be the case. He might think: "well, ok, no problem, instead of checking whether I pass null or not, I just catch that NullPointerException". That's fine. Until you modify that method's implementation and maybe add an explicit check on that String parameter: when it's null, you throw an InvalidArgumentException. That will break the other developer's code, and in a pretty nasty way (he won't notice by compiling). Before:
public String doSomeThing(String value) {
    return value.toLowerCase();
}
The code above will result in a NullPointerException. But then, in a later release, you change the implementation to this:
public String doSomeThing(String value) {
    if (value == null) {
        throw new InvalidArgumentException("value is null");
    }
    return value.toLowerCase();
}
Furthermore, if you actually document the behaviour of your API, and how it behaves when passing null, you should also write Unit Tests that verify that contract. Here's the method:
/**
 * Does something with a <code>String</code> (ok, this is a terrible description ;-P).
 *
 * @param value the value to do something on, may not be <code>null</code><br>
 *              when <code>null</code>, a <code>InvalidArgumentException</code> is thrown
 * @return what results from doing something on the value
 */
public String doSomeThing(String value) {
    if (value == null) {
        throw new InvalidArgumentException("value is null");
    }
    return value.toLowerCase();
}
And here's the Unit Test to verify that contract:
public class FooTestCase extends TestCase {
    public final void testDoSomeThingThrowsException() {
        try {
            Foo.doSomeThing(null);
            fail("Failed to catch expected InvalidArgumentException");
        } catch (InvalidArgumentException e) {
            assertTrue(true); // ok, got expected exception
        } catch (Exception e) {
            fail("Caught unexpected exception: " + e.getMessage());
        }
    }
}