Summary
Managing dependencies is important. JarAnalyzer, an open source static analysis tool for .jar files, can help. Think of it as JDepend for jars.
Advertisement
A while back, I mentioned JarAnalyzer, a utility I created that identifies dependencies among .jar files. Recently, I've put some work into JarAnalyzer, and want to announce a fairly significant upgrade. Here is some of what you can now do with the new JarAnalyzer:
1. Generate a visual component diagram (see Hibernate sample) showing the relationships between your .jar files. To do this, you'll need GraphViz installed.
2. Generate an .xml document (see Hibernate sample) detailing some important .jar design metrics, such as Afferent and Efferent coupling, Abstractness, Instability, and Distance. Included with JarAnalyzer is a stylesheet that generates prettier output.
3. Include JarAnalyzer as part of your Ant build script, so you get the component diagram and detailed xml information each time you build.
4. Run JarAnalyzer standalone, against any directory containing .jar files, to generate the xml or GraphViz output.
5. Filter out packages and .jar files you want excluded from the output, allowing you to focus on only those aspects of the application that most interest you.
If you decide to experiment with JarAnalyzer, and possibly use it on a more regular basis, I'd enjoy hearing from you. Please feel free to suggest any upgrades or revisions you'd like to see built into the utility. Here's my contact information. Also, I've begun posting most of my articles to my personal blog, and that's where I'll continue to provide updates on JarAnalyzer and other topics related to Dependency Management, Agility, and most things technical.
Managing dependencies is important for any larger project and JarAnalyzer is at first sight a very useful and handy tool. Unfortunately many modern frameworks wire up objects in XML files and instantiate them via reflection which makes dependencies invisible at the code level.
Those are run-time dependencies though. Not compile time.
The only way your run-time dependencies will match your compile-time dependencies is if classes are concretely coupled. And in this case, the specification in your xml that wires the objects will match the type references in code. You try to avoid concrete references when you want extensibility.
If classes are abstractly coupled, the code references the abstractions and the configuration specifies the concrete. That's a sign of extensibility.
The fact that run-time relationships do not appear when running JarAnalyzer is not a bad thing...it's a good thing. The results from any static code analysis tool (including JarAnalyzer) shows you where you have room for design improvement...where design improvement = increased extensibility.
Hi Kirk, great to see more people starting to think about dependencies. I think that controlling dependencies offers one of the biggest bangs-for-the-development-buck and the only thing that has prevented it becomming more widespread is that the dependencies that "roll-up" from the code to (in this case) jars have simply been invisible - out of sight, out of mind...
In your post back in April 05, however, you said that jar dependencies are the only ones that it is possible to really manage, e.g. because there are just too many packages. Of course, looking at a flat package dependency graph can be a bit overwhelming, but surely this is why packages are hierarchical? If the hierarchy was truly used to encapsulate design (or is it architecture ;-), then managing the dependencies between at least the top few layers of (meta-)packages would surely be as beneficial as managing them between jars?
Packages, or at least high-level packages, without cyclic dependencies, can then become the unit of reuse, test, deployment, development, etc. as espoused by Bob Martin.
I also believe that it is possible to manage dependencies at even the flat package level if you can identify just the new package-level dependencies occasionally, and then discover the exact code-level causes of these. Structure101 (http://headwaysoftware.com) is a good example of a tool that does this kind of stuff. There are others, but not as good! (I work for Headway ;-).
I feel that package relationships are important. But for large applications, they become difficult to manage just as class relationships become difficult to manage. There can be too many relationships to make things manageable.
Managing package relationships between top-level packages seems reasonable, but the relationships at this level are mostly conceptual since you still have to import the lower level packages. And isn't that where the tangle occurs?
As for reuse and deployment...we don't deploy packages, we deploy .jar files. So it's the .jar file that is the unit of reuse and unit of deployment...not the package.
All dependencies, at any level, roll up from specific lines of code, and yes, if you take a flat view of the world, then there are an impossible number of dependencies to control.
However if you use the package hierarchy not just as an extension of the file-system, but as a "design" (or whatever term you prefer, I prefer "structural control") medium, then the principle of divide-and-conquer can work as in any engineering discipline. If, at every point in the package hierarchy you have a "mind-sized-chunk" of design breakout, a scaleable design process is possible since the volume of dependencies to be controlled is drastically reduced.
For example, if we have a flat package "design" (i.e. a dependency structure we want to control), and in a development iteration Class A.B becomes newly dependent on class X.Y, this has no "design" impact if there was already a dependency from any class in package A to any class in package X.
The volume of notable design changes is further reduced dramatically if we use a hierarchical package "design" since a new code-level dependency is only notable if it creates a new dependency between 2 high-level packages *.P.Q.* and *.P.R.* where none of the code in any of the subpackages of Q previously depended on any of the code in any of the subpackages of R.
Controlling this quantity of dependencies is possible if you have a way of *seeing* how the dependencies roll up through the package hierarchy and a way to automatically detect the introduction of a notable dependency (our tools do this).
Of course, whether you want to maintain the structure of a project in which it has been out of control for a long time is a whole other question ;-).