This reminds me of the situation in the late 90s when Swing was added to the JDK (version 1.2 in 1998), Internet Explorer became the dominant browser that only supported Java 1.1 and suddenly users had to install a rather large browser plugin to run applets. I think it is safe to say that this killed Java in the browser and almost killed Java as a language before it had a strong comeback on the server side. A particular problem was the large size of the plugin (remember that the internet was slow back then and many people were still on dial up). But given the dependencies between the toolkits, even if you were using only AWT you had to download (the much larger) swing as well!

A common point made here is that there might be another reason, not known to the outsider, for having this dependency here. Or, in other terms, that a behaviour-preserving refactoring that breaks this dependency is just not possible. But this is definitely not the case here: in the alternative Apache Harmony implementation of the JDK, this dependency is missing.

The following table shows the size of some programs in terms of their dependency graph (nodes are classes, edges are relationships), and the number of antipattern instances found.

system

classes (nodes)

dependencies (edges)

OpenJDK JRE1.6.0_05-b13

16877

170140

azureus-3.1.1.0.jar

6444

35392

jruby-1.0.1.jar

2093

11016

hibernate-3.3.1.jar

1700

10093

system

AWD

CD

STK

azureus-3.1.1.0.jar

9415

335

290

jruby-1.0.1.jar

2508

32

87

hibernate-3.3.1.jar

2680

74

224

Many programs also have a large number of both class and package tangles. In mathematical terms, tangles are strongly connected components - every artifact in a tangle (directly or indirectly) depends on every other artifact within the tangle. Software engineers often refer to tangles as “big balls of mud”. An extreme example is azureus-4.5.0.4.jar with a package tangle consisting of 373 packages and a class tangle consisting 2698 classes!

Packages inside the large (373) package cluster in azureus-4.5.0.4.jar (click here to explore the dependency graph)

Detecting Dependency-Related Problems

There are a number of tools that can extract, display and analyse the dependency graph. There are two approaches to detect critical dependencies: metrics and patterns.

Metrics associate artifacts and their relationships with numerical values expressing quality. The classical example is distance from the main sequence (D) - a metric for packages. It states that abstract packages should have relatively many incoming dependencies (high responsibility), while concrete (implementation) packages should have relatively few incoming dependencies but will depend on other packages (high instability and low responsibility). The classic tool to detect the D metric is JDepend. JDepend computes several package dependency metrics, and can be easily embedded into IDEs and build scripts. It also supports the detection of circular dependencies between packages.

Some of the general (anti-) patterns are described above. Some tools also allow the user to define project-specific patterns, often relating to application tiers and their dependencies. For instance, if the persistence layer must not depend on the presentation layer, dependencies between classes in the respective layers become antipatterns.

Systematic and scalable pattern analysis is not well-supported by any existing tool, and was reason we started to develop our own set of tools. This tool is based on the GUERY graph query library we have developed and open-sourced. The Massey Architecture Explorer is an HTML5-based front end using this library.