Archive for April, 2004

TestNG: Testing, the Next Generation

It’s been a few weeks since I announced another killer app, hasn’t it?

I have complained about JUnit many times, both in
terms
of
design and
implementation
I think my complaints are justified, but if there is something I don’t like,
it’s people who complain but don’t do anything to solve the problem they are
complaining about.

Therefore, without further ado, I give you… 
TestNG, the JUnit killer.

For quite a while, I have seen very little reason to write a replacement to
JUnit since I didn’t think the added value would be enough to convince the vast
number of JUnit users to switch.  After reading up about NUnit, it occurred
to me that using JSR 175 annotations for testing was an interesting evolution,
but still not quite the quantum leap I expected (besides, in its effort to
mimick JUnit, NUnit repeats a lot of its flaws).

So I went back to the drawing board, in search of one last killer argument to
justify taking on this endeavor, and I came up with another ultimate complaint
that, strangely, I hadn’t voiced about JUnit:  the test Suite.

I have always been confused by JUnit’s Test Suites.  Where should the
method belong?  In the test class?  Separately?  Should it be
static?  And if I want to change the tests run, why do I need to rebuild my
code?

With these changes in mind, I came up with the design principles that are the
foundation of TestNG.  To quote the documentation:

TestNG is a testing framework inspired from JUnit and NUnit but
introducing some new functionalities that make it more powerful and easier
to use, such as:

  • JSR 175 Annotations.
  • Flexible test configuration.
  • Default JDK functions for runtime and logging (no dependencies).
  • Powerful execution model (no more TestSuite).

I think the combined use of JSR 175 annotations and Test Groups make TestNG a
very flexi…  (augh, sorry Hani)…  a very supple testing framework
that should compare decently with JUnit.

Check out the documentation, take it
for a run and let me know what you think.

About the grammar quiz

Somebody rightfully pointed out that the page seems to install some nasty spyware if you’re not careful. I didn’t notice, using Thunderbird, so if you are using Internet Explorer, watch out.

Sorry about that.

Grammar quiz

Grammar God!
You are a
GRAMMAR GOD!

If your mission in life is not already to
preserve the English tongue, it should be.
Congratulations and thank you!


How grammatically sound are you?

brought to you by Quizilla

 

Outlook 2003 vs. Thunderbird

After using both tools for quite a while, I decided to write down my impressions on their respective strengths and weaknesses. Since the post ended up being longer than I thought, I posted it directly on my Web site.

JSR 175 war stories

After making
such a
comment
, and
being
called on it
, I had to step up to the plate.

I have been working with JSR 175 quite a lot these past months and I have
identified the following points of interest:

  • Shortcut notation.
  • Defaults.
  • Multiple annotations.

Let me go through this list in order.

Shortcut notation

If the annotation type you are defining only needs one value (or none at
all), the syntax can be simplified by using a shortcut notation.  You
define that your annotation type supports this notation by providing only one
annotation called "value()":

public @interface Algorithm {
  String value(); 
}

Then you can use any of the following constructions:

@Algorithm(value = "RoundRobin")
public class MyRobin {

or more simply:

@Algorithm("RoundRobin")
public class MyRobin {

Note that the following is incorrect:

@Algorithm
public class MyRobin {

because value() doesn’t have a default value (i.e. it is required).  In
order to make this syntax valid, you would need to define your annotation type
as follows:

public @interface Algorithm {
  String value() default "LastInFirstOut";
}

Which brings me to…

Defaults

JSR 175 distinguishes a mandatory annotation from an optional one with the
"default" keyword.  For example:

public @interface Person {
  // name is required
  String name();

  // but the date of birth is optional
  String dateOfBirth() default "";
}

With this type, I can now annotate my code like this:

@Person(name = "Cedric")
public class Employee {
}

or

@Person(name = "Cedric", dateOfBirth = "January 2nd, 1969")
public class Employee {
}

but not like this:

// error, missing required annotation "name"
@Person(dateOfBirth = "January 2nd, 1969")
public class Employee {
}

It sounds all good and well until you realize that "null" is not a valid
defaut value.  The problem with that is that tools using metadata often
need to know whether the value they are receiving is the default value (meaning: 
the user didn’t specify anything and the tool needs to provide its own) or not (in which case, they need to retain
that value).

As you probably all know, none of the java.lang types have an official
default value, so you will have to come up with one.  It can be pretty easy
for strings (how about "Unspecified"?), a bit more dangerous for numerics ("new
Integer(57381234123)") but where it gets ugly is for booleans.

The problem with booleans is that they only have two values, true and false,
so using one as a default is not enough for the tool to be able to tell whether
the value it received is a default or if it was specified by the user.

The trick I have been using for now is creating my own enum "Bool":

enum Bool { UNSPECIFIED, TRUE, FALSE }

There are a few things ugly about this solution:

  • I have to come up with my own (and probably incompatible with everybody
    else) type name.
  • I can’t use "true" nor "false" since they are reserved keywords.
  • Standard conventions dictate that the enum values should be all caps.

Unfortunately, it’s the only way I have found to circumvent this problem.

Now, all this is not so bad because what is being surfaced to the user is
fairly minimal.  Basically, except for the fact that they need to know
about the "Bool" type and TRUE and FALSE, all the rest is fairly transparent. 
All this dirty business with singular values representing the defaults is
strictly between the annotation author and the code that will consume these
annotations.

For example, let’s add a boolean field to our Person annotation above:

import Bool;

public @interface Person {
  // name is required
  String name();

  // but the date of birth is optional
  String dateOfBirth() default "";

  // optional boolean
  Bool isRegistered() default Bool.UNSPECIFIED;
}

Granted, it doesn’t look that good, but your users only need to write the
following:

import Bool;
import Person;

@Person(name = "Cedric", isRegistered = Bool.TRUE)
public class Employee {
}

Note that static imports can make things a little bit more legible:

import static Bool.TRUE;
import Person;

@Person(name = "Cedric", isRegistered = TRUE)
public class Employee {
}

at the risk of possible name conflicts.

Multiple annotations

A common misconception from people who read the JSR 175 specification a
little too fast is the idea that it is impossible to have an annotation appear
several times.

Strictly speaking, this is true, but it’s pretty easy to circumvent: 
use arrays.

For example, consider the following annotation:

public @interface EnvEntry {
  String name();
  String value();
}

And we want this annotation to be allowed to appear several times in a class
file.  A simple way to achieve this is by introducing a holder type:

public @interface EnvEntries {
  EnvEntry[] value();
}

Note that the holder uses the shortcut notation, which makes the final result
quite readable:

@EnvEntries({
  @EnvEntry(name = "height", value = "1m80"),
  @EnvEntry(name = "weight", value = "75kg")
})

Conclusion

After describing all these little annoying sides of JSR 175, I don’t want to
leave readers with the impression that the specification is flawed or unusable. 
Quite the contrary.

I believe JSR 175 is going to change radically the way we program and I am
betting that in a couple of years from now, all the Java source code we read and
write on a daily basis will contain annotations.

The syntax will undoubtedly look foreign to you at first sight, but I am
confident that it will grow on you as you use it.  It sure had this effect
on me.  Also, wait until we get some decent support for annotations in
IDE’s (code folding, coloring, etc…) and you won’t even notice it’s there any
more.

 

 

SGen and XDoclet

Robert posted an
interesting write-up comparing XDoclet and SGen.  I’d
like to correct two errors he made (Robert, I tried to find an email address for
you but couldn’t…).

  1. XDoclet didn’t start as EJBGen.  I don’t remember what Rickard’s
    original name was, but it wasn’t EJBGen.  I came up with EJBGen on my
    own, and the two tools have absolutely nothing in common.
     
  2. In his presentation, Robert writes about SGen:

    Designed to replace XDoclet use within BEA

    We don’t use XDoclet at all inside BEA.  We have our own
    engine and parser (based on a Java compiler called Javelin), so SGen was
    certainly not created to replace XDoclet internally.

Finally, I haven’t studied XDoclet 2 at all so I can’t comment on the
similarities that Robert sees between SGen and XDoclet 2.  SGen is simply
what EJBGen has been using for a long time internally and recent requests from
users to make EJBGen extensible prompted me to factor out the annotation part
from EJBGen.  Thus SGen was born.

Robert, feel free to email me if you have specific questions or suggestions
for SGen, I’ll gladly help.

 

Cringely on ignorance

Robert Cringely posted
yet another
baffling article
in his pulpit column.  While some of his points
make sense, most of the article is littered with very questionable
observations, such as:

It was only when those companies decided to pay attention to Microsoft and
decided to compete with Microsoft that they got in trouble.

Robert is observing the right phenomenon but interpreting it wrongly. 
What got these companies in trouble is not that they started caring about
Microsoft, it’s that Microsoft entered their space.  And when this happens,
ignore Microsoft at your own peril.

Another company that is competing with Microsoft by ignoring them is Google.

Oh Google is certainly not ignoring Microsoft.  Microsoft has a search
engine of its own, so they are definitely competing.  Why does Google have
the upper hand right now?  Because their product is superior to
Microsoft’s.  It’s as simple as that.

The key to beat Microsoft is not by ignoring them but simply by offering
better products before they enter your space.  And when they do finally
enter your space, you need to keep offering better products, because at this
point, simple technical excellence will not last in front of billions of dollars
and a company that has such a stellar track record at executing.

Please don't seal your classes


Ted is campaigning for the "final" keyword
:

I’m sorry, but your comment "Run, don’t walk, from any code developed by
people who think this way [Cedric:  people who want everything to be
overridable by default]
…" is really appropriate for Smalltalk code, but
wildly out of place for code developed for the JVM, the CLI, or the C++
programming environments.

I disagree with Ted’s firm stance on this issue.  While "final" has some
very good niche uses, I contend that most of the code should be written as being
inheritable by default.  As a developer, you just can’t guess all the
possible ways that future programmers will use your code.  Sure, they could
misuse it and break it, but that’s not your concern.  If your API is well
documented (contract, side effects, parameters, etc…) and that a good
developer then tries to extend it, they will come up with things that will
probably amaze you.

That being said, I see "final" as being useful in core classes of the
libraries, such as String.  For various reasons (security being one of
them), such fundamental classes need to be free of tampering and extension. 
That’s perfectly reasonable.

But for any other type of "user code", please write your code assuming that
one day, someone will want to override the method you are writing.  It will
make you see your work in a very different light.

Commoditization? I don't think so

The author of the "Open
letter to McNealy
" has some severe misconceptions about the software field:

But software technology — operating systems, development tools, application
servers, systems management tools, and the like — all come with a major
handicap. They become commodities so fast that pure technological excellence has
little differentiating power.

None of these industries are anywhere near commoditization. If such were the case

  • Windows would be free, as would be WebLogic and WebSphere.
  • There would be no differentiating factor between Windows and Linux, they
    would all provide the same set of services.  Same for WebLogic and
    WebSphere.
  • Open source software would dominate all these markets.

Even free IDE’s such as Eclipse can’t commoditize the IDE space, as
JBuilder and IDEA have been showing for several years now.

Software doesn’t exist in a vacuum. What drives commoditization is user
needs, not producers. And so far, user needs have constantly brought in new
requirements on all these software stacks, precisely preventing commoditization
from happening.

The author needs to read up on some basic business principles before trying
to patronize a CEO…

 

My Rubik’s cube solution

I just posted a Rubik’s cube solution that I designed to be as easy to memorize as possible. With some practice, it should allow you to solve the cube under a minute.