Today on my current project I had to spend some time creating a client JAR file for use by downstream systems. I needed to keep the JAR as small as possible, with (more importantly) no external JAR dependencies.
There are tools out there for dependency analysis, such as IBM’s Structural Analysis for Java (aka Smallworlds), Compuware’s Pasta or the open source JDepend. As nice as these tools are, they are for analysis and the gathering of metrics. As I’ve mentioned before, unless ‘good metrics’ are in some way enforced by the build process, it becomes very easy for even automatically gathered metrics to be ignored.
JDepend can be run via Ant, but just like Emma or Findbugs the information gathered is used for reporting purposes – it is not capable of failing a build because someone has introduced an invalid dependency between packages.
Japan is a tool which comes with an Ant plugin that will fail a build if your code violates the allowed package dependencies. For example, our downstream systems only need to use classes in the
client package – I don’t want to have to include any other code in the client JAR file. So in a Japan config file I place the following code:
Now if any of the classes in
client include any other packages in my codebase, the build will fail. It’s important to note that Japan requires that you define all your dependencies at the package depth you define (the
package-depth="4<a href="http://www.c2.com/cgi/wiki?AcyclicDependenciesPrinciple" <2>> means that all source code in com.company.app.xxx and below will be checked) – so for example if our
gui package depended on
client, I’d have to add the line:
By defining these configurations you can quickly discover circular dependencies) – for example if to get the build passing you find yourself defining something like this:
You know something is up. The other thing I like about Japan is the fact that because I can now enforce sensible package dependencies, I feel better about spending some time cleaning our packages up, safe in the knowledge that we won’t backslide (assuming no-one goes and sticks everything in one giant package of course). There was one little problem I had though – I had to disable transitive dependency checking as it caused a stack overflow error, but I think once we remove our existing circular dependencies that should sort itself out. I still of course like to have tools like Pasta to help me define acceptable inter-package dependencies, but I feel much happier having Japan in the build just in case I start getting sloppy :-).