Java Dependency Analysis and Modularization |
Written by Jens Dietrich | ||||
Monday, 03 October 2011 | ||||
Page 1 of 3 Everybody agrees that modularization is good, but how do we go about transforming a big ball of mud architecture to something like OSGi?
IntroductionMost experienced developers have experienced some form of system rot: the quality of a program deteriorates over time and it becomes more and more expensive to update and maintain it. This is often caused by poorly managed dependencies. Dependencies between software artifacts (classes, packages, functions,.. ) are created when an artifact is referenced by another artifact, for instance, when a method of a class invokes a method defined in another class. These dependencies are then propagated to other units of code: a package depends on another package if there is a class dependency between classes in the respective packages etc. Dependencies can become problematic when they are created to solve short-term problems but bypass rules defined as part of the system architecture such as “the persistency layer should not depend on the presentation layer”. These dependencies then become technical debt that starts piling up. And eventually, this will become a problem. Remember the late 90s when everybody wanted to port their applications to the web. That was easy to do for applications with a clear separation between user interface and logic layer, and difficult to impossible for applications where the logic depended on a particular user interface (usually a desktop UI). Now Java programmers face a similar situation. There are many use cases that require modularity - creating plugin ecosystems around products, product lines and the ability to make incremental updates to name a few. And there are several great platforms for modularity available, in particular OSGi and its extensions (Eclipse, declarative services, Spring dynamic modules). But all of these platforms have strict requirements when it comes to dependencies. A common theme is that these frameworks have containers to manage dependencies automatically. This requires that programmers adhere to the following two principles:
The question arises how existing applications can be refactored to modular designs based on one of these platforms. The State of AffairsTo answer this question, we have investigated a large set of open-source Java programs (the qualitas corpus) in order to find out how many of those programs suffer from dependency related problems. The short answer is: almost all of them. In this experiment, we checked the dependency graph extracted from the respective program for instances of the following antipatterns which compromise package and interface separability, respectively:
Surprisingly, almost all programs analysed were ripe with instances of these patterns. Here are some examples. In tomcat-7.0.2, there is the following circular dependency between jars (CDC):
Tomcat jars and their relationships - click to enlarge Dependency chains traversing several packages are even more abundant. For instance, the OpenJDK (both versions 6 and 7) contains such a chain linking AWT (java.awt) and Swing (javax.swing). The critical edge is a reference to javax.swing.JComponent in java.awt.Component. This tightly couples the two alternative toolkits together and makes it impossible to deploy them separately. This implies that an application that only uses the older AWT will also need Swing to run! |
||||
Last Updated ( Monday, 03 October 2011 ) |