@Ignore unit tests immediately if they fail!

In development teams, there is often discussion about using the @Ignore tag for failing tests.

In particular, developers who are very enthusiastic about writing unit tests often tend to be very dogmatic about it. They argue, “A test should never be ignored! It’s better to have the build server on Yellow if tests fail. That way we always have an overview of our problems and are forced to fix them!”

What might sound good at first is not a good idea, at least when it comes to large development teams.

If you have several commits from multiple developers and maybe even additional deliveries from different branches to the main development line, the build will definitely break from time to time. How long does it take to fix such an error? Sometimes it may be easy, but in some cases, it may take days to fix a broken test. Now let’s assume that we have implemented the rule that you should never ignore a test. This means that the build may stay Yellow for a long time.

If another developer now updates his workspace with the latest version from the trunk and runs the unit tests locally, he will see failing tests even if he didn’t make any mistakes! That’s pretty bad itself. But he then checks the build server and, after some time looking around, he realizes it wasn’t his fault, as the server is already in the Yellow state. Should he commit now? If he does, he will receive endless emails from the build server about the broken build state that he didn’t cause. If not, his work and maybe the work of others will be blocked until the test is fixed. In a typical, pretty hectic IT project, with it’s almost impossible to meet deadlines, this is not really an option.

What is the solution?

  1. If you cause a build to break, @Ignore the failing test immediately and commit the change.
  2. Now that the build server is Green again (or Blue in the case of Hudson), start fixing the test.
  3. After you have fixed the test, commit the change and check to see if the build stays Green.
  4. Have some kind of statistic page on the build server that lists all ignored tests – this allows you to easily track the tests that are currently disabled.

Don’t get me wrong: all failing unit tests should be fixed as fast as possible! But my failure when committing a change should never constrain other team members from doing their work.

 

Large software projects and icons – it depends on the style!

Have you come across similar conversations in the context of large software projects?

Developer: I need an icon for a button.
Boss: You have MS-Paint on your computer. Why don’t you draw it yourself?
Developer: No… I am not a graphic designer… Why don’t we purchase the icons?
Boss: Hmm…We have got an intern, haven’t we? He can do it!
Developer: But he is no graphic designer either… And there are great low-cost icon libraries available to download.
Boss: I wouldn’t know how to book that… The intern will do it!

Sometimes I wonder what makes large companies tick…They spend millions on software and skimp on a few hundred dollars for nice graphics. Unfortunately, the completed applications often look as if an intern has designed the icons.

A leading supplier of icons offers his entire catalogue (approx. 250 sets with around 850,000 icons) for 399 USD. Commissions for individual icons in addition to an existing set cost approx. 50-75 USD per icon. In return you will get designs which are visually pleasing to the end user who interacts with the finished piece of software.

Anyone who allows his developers or interns to design icons, must be crazy.

The Specification Pattern

I recently stumbled across an older article from Greg Young about something called the Specification Pattern. I haven’t heard about it before but the problem sounds familiar to me as I already implemented something similar.

Digging deeper I found an interesting paper from Eric Evans and Martin Fowler explaining the idea in depth: Specifications.

There is also a small Java implementation of the pattern available at Google Code that unforunately seems to be inactive since 2008.

Contracts for Java

I personally like the idea of Design By Contract very much. The bad news is that Java does not support this natively.

The good news is that there are several libraries out there that try to implement DBC for Java:

http://jcontractor.sourceforge.net/
http://c4j.sourceforge.net/
http://oval.sourceforge.net/
http://springcontracts.sourceforge.net/
http://custos.dev.java.net/
http://code.google.com/p/javadbc/
http://www.contract4j.org/

Another bad news is that most of these projects are inactive or don’t support all aspects of DBC.

Most feature complete is the Java Modeling Language (JML). There are many tools based on this behavioral interface specification language. I checked some of them but they all seem to be very Academic and not very handy to use.

Now there is a more practical approach that uses annotations to express pre conditions, post conditions and invariants:

A detailed report that introduces the ideas behind the framework can be found here.

This looks very promising and is definitely worth giving it a try!

Parsing a Maven POM II

Due to popular demand here is the code that does the parsing described in this article some time ago:

http://www.fuin.org/files/MavenPomReader.zip

It’s just a quick hack but it works fine for all projects at fuin.org – The dependency information as on this page is actually parsed using the above Maven Pom Reader.

Here is a short example how to use it:


// Path to your local Maven repository
final File repositoryDir = new File("/data/maven/repository");

// Read the model for an artifact and a given version
final Model model = MavenPomReader.readModel(repositoryDir, "org.fuin", "serialver4j", "0.4.2");

// Print the dependencies on the console
final List<Dependency> dependencies = model.getDependencies();
for (int i = 0; i < dependencies.size(); i++) {
    final Dependency dependency = dependencies.get(i);
    System.out.println(dependency.getGroupId() + " / " + dependency.getArtifactId() + " / "
        + dependency.getVersion() + " / " + dependency.getScope());
}

Output:

com.thoughtworks.xstream / xstream / 1.3.1 / null
com.caucho / hessian / 3.1.5 / null
org.reflections / reflections / 0.9.5-RC2 / null
junit / junit / 4.8.1 / test
org.easytesting / fest-assert / 1.3 / test
org.fuin / units4j / 0.2.3 / test
org.fuin / utils4j / 0.6.7 / test