About to upgrade to Leopard...

I'm opting for the Archive and Install upgrade, hoping to easily recover most of my existing applications and settings that way. If all goes well, my aging Powerbook G5 will soon be up to date again with the newest Apple Fanboy Technology ;-)

Controlling the Maven release cascade

In my previous post, I showed one of the pitfalls of maven's transitive dependency mechanism.

Luckily, there is a good workaround to this that will allow your team to stay focussed on development without getting bogged down too much into the release-cascade trap.

The thing to do is to create another level of indirection between your framework and the clients using it, this can be accomplished by providing a POM dependency.

For our framework it would look something like this:


<project>
<modelVersion>4.0.0</modelVersion>
<groupId>my.framework</groupId>
<artifactId>client-components</artifactId>
<version>2.0.1</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>my.framework</groupId>
<artifactId>main</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>my.framework</groupId>
<artifactId>A</artifactId>
<version>0.6</version>
</dependency>
<dependency>
<groupId>my.framework</groupId>
<artifactId>B</artifactId>
<version>0.8</version>
</dependency>
<dependency>
<groupId>my.framework</groupId>
<artifactId>C</artifactId>
<version>0.2</version>
</dependency>
<dependency>
<groupId>my.framework</groupId>
<artifactId>X</artifactId>
<version>0.4</version>
</dependency>
<dependency>
<groupId>my.framework</groupId>
<artifactId>Y</artifactId>
<version>0.5</version>
</dependency>
</dependencies>
</project>
Notice how this POM dependency is nothing more than a flattened dependency tree. We've pulled all our dependencies into one POM and we control their versions from there. This works pretty well, and all our clients have to do is to declare it like this:
<groupId>my.framework</groupId>
<artifactId>client-components</artifactId>
<version>2.0.1</version>
<type/>pom<type>
Using this, we can avoid the release cascade for module Y, our work is effectively reduced to:
  1. release module Y
  2. change version of Y in client-components POM
  3. release client-components POM
That's IT. Swift and fast like it should be.

The POM dependency can even be used from assemblies and the like. It behaves like a normal dependency in all aspects. Additionaly, it is a great way of quickly eliminating rogue dependencies: just exclude them in there and worry about tracking it down later.

That's it for now, I promise my next post will not take 4 months this time :-)

The Maven release cascade

Imagine you've got the following component structure in your framework:

  • main component (the included by your clients), let's call it MAIN
  • MAIN depends on functional components A,B,C
  • There are 2 helper components, X and Y, used by most modules
A rough graph of above situation could look like this:


Now, the great thing about maven's transitive dependency resolution is that when a client wants to include your framework it can do so by just declaring one artifact in their POM, namely that of the MAIN component:

<dependency>
<groupId>my.framework</groupId>
<artifactId>main</artifactId>
<version>1.0</version>
</dependency>

Maven will then automatically add modules A,B,C,X and Y to the client's project, neat !! The root component here effectively serves as a dependency abstraction, clients do not need to know anything else when they want to use my framework, this is a Good Thing really.

Imagine now that I (the framework maintainer) make a small one-line fix to module Y and I'ld like to do a new release. There were minimal code changes, and I only changed one module, so I expect the release process to go fast and swift and in a few minutes my clients will be able to use the 1.0.1 release:

<dependency>
<groupId>my.framework</groupId>
<artifactId>main</artifactId>
<version>1.0.1</version>
</dependency>

Right ?

Wrong.

Here is what maven typically will force you to do:
  1. Release module Y
  2. Update the dependency of Y in module X, release module X
  3. Update the dependency of X in module A, release module A
  4. Update the dependency of X in module B, release module B
  5. Update the dependency of X in module C, release module C
  6. Update the dependency of A B C in MAIN and (finally) release MAIN
In other words, I would need to coordinate a new release for 5 modules !! The effort is just not justifiable for that oneliner fix, so I decide to wait until I've got something more substantial to release. This is a problem.

If the effort for a release turn-around becomes far too great then this can impact your project in different ways:
  • no more release-early release-often
  • each release will contain more code changes
  • regressions become much harder to detect
  • clients get frustrated because of the slow release cycle
  • developers get frustrated by their inability to "get something out of the door quickly"
These symptoms are to be taken very seriously. They end up diverting so much energy away from the team's core business, namely to develop all those features that will make the framework dominate the world !

(This post is getting too long already, so I'll offer a solution to this in a next post.)

Apple Update 10.4.11 + Safari + Sogudi

I ran into a little snag with Safari the other day, after updating to 10.4.11. Entering an address in the address field and hitting enter no longer worked.

It turned out that Sogudi was the culprit. After installing the latest beta everything worked again.

Quote

The average quality of the code on a project equals the quality of the code written by the second worst developer on the team.

Why ?

Because the rest of the team is too busy fixing bugs introduced by the worst developer on the team.

Eric Evans, SpringOne 2007

Using the maven embedder

I was doing some work on Hudson's maven2 integration last night. It currently uses an old and unsupported version of the maven embedder. My aim was to 'upgrade' Hudson to use a more 'supported' embedder version, so the project can benefit from better maven2 build support. Those of you that don't know what the embedder is, read this mini guide as a starting point.

Getting the embedder to run inside your application is actually quite easy if you avoid the pitfall of using the old and unsupported 2.0.4 binaries. Instead, make sure to use the latest 2.1-SNAPSHOT all-in-one binary (at the time of this post it is called maven-embedder-2.1-20070830.163428-16-shaded.jar). Adding this jar to your Eclipse/IDEA project is all you need to do to get the example from the guide going.

In summary,

  1. Create a new project in your IDE, add above all-in-one jar as a dependency.
  2. Copy-paste the code from the mini guide.
  3. Change the first line to point to a little sample maven2 project.
I also recommend having a look at the embedder integration tests for examples of how to do more non-trivial things with the embedder.

Eclipse 3.3 + Mac = crash ?

So I downloaded Eclipse 3.3 for Mac today, in an effort to upgrade my (aging) powerbook development environment. I haven't been doing much development lately, but got inspired by a cool OSS project I've been using lately. Their integrated maven2 support could do with a revamp me thinks, so I plan to have a deeper look at its integration layer and see if there is anything I can do to vamp it up a little (support for profiles, settings.xml etc - but I digress).

So after having tar-x-z-vf'ed the download package, I fire up Finder, double click the Eclipse logo and get presented with this instead of the new funky Europa splash screen:


No biggie me thinks. This is the most anticipated Eclipse release crashing on the most stable and expertly-used development platform, ergo Google must be full of helpful links right.

Not so.

Update:
Installing Release 5 of Java for Mac OS X 10.4 did the trick.

Indeed, looking at Eclipse's own readme.html (always the last place to look for any seasoned developer) I can see now: