Mastodon

How to Detect Circular Dependencies with Degraph

Recently, a good friend of mine blogged about Degraph. Degraph is a tool to visualize dependencies between packages. Not only are these dependencies shown in a graph, but the nodes of the graph can be expanded so that dependencies can be traced into packages. In this article, I want to document my first use of Degraph and how it helped me to discover a flaw in the architecture of my application SimFX.

One of my goals with SimFX is to build a nice architecture. That made a look at Degraph worthwhile because the structure of the packages are an important part of a software architecture. So I went to the Degraph wiki and had a look at how to use it. The application scans a folder with sources and generates a file with the graph information. I ran Degraph with the following configuration file:

output = simFX.graphml
classpath = ../../workspace/de.stevenschwenke.java.javafx.SimFX/target/classes

exclude = com.**
exclude = org.**
exclude = java.**
exclude = javafx.**

layer = {
main.java.(*).**
}

Jens told me that it is important to let Degraph scan only the source OR the binary folder; that is what the classpath-line is about. If you scan both, there might be multiple classes in the resulting graph. I also excluded some packages, so libraries like Apache Common would not appear in the graph. Finally, I predefined the first layer of my application. This makes the three main packages visible right at the start. Running Degraph with that configuration generates a simFX.graphml that can be viewed with yEd.

Letting Degraph analyze SimFX resulted in a surprise right at the start. I didn’t expect to build in huge flaws at this early stage of development, but I did. My nice and clear top-level package structure already included a circular dependency, as you can see by the red arrows:

Resolving Dependencies with Degraph 1

There is one dependency from the business package to the package ui that shouldn’t be there. Let’s zoom in to have a look (within yEd, click at the “+” at the packages. This is not shown here at these pictures).

Resolving Dependencies with Degraph 2

World, the class that handles all business objects, notifies the user interface about changes that should be displayed at the screen. I placed it in the ui package because clearly, it had something to do with the user interface. I simply wasn’t aware that the business object World would need a reference to the ui package. The solution is a simple one: I placed the UserInterface in the business package. That resulted in a far better architecture:

Resolving Dependencies with Degraph 3

Now, there is a clear calling stream from left to right without any (red) circular dependencies. However, not all work is done … let’s have a look atthe packages ui and business:

Resolving Dependencies with Degraph 4

Well, there’s still room for improvement in the business package.

After learning dealing with yEd, I spend a couple of hours to trace and fix wrong dependencies in my application. Some dependencies didn’t seem to be wrong at first. However, after thinking it through I allways concluded that the architecture was badly broken and that a refactoring had to be done. I would not have seen this without the easy to understand graphical representation of Degraph. And I absolutely like the approach of a zoomable graphical representation of call hierarchies. It helps me to explain my application on a 10.000-feet level while at the same time, I’m able to zoom in whenever and wherever I want, right down to single classes.

It would be nice to have Degraph as an executable jar in some Maven repository. I could add my configuration file to the project and push it to github. This would allow other coders to watch my architecture grow. Also, this could be a first step to an automated architecture documentation of the code.Integrated into continuous integration, Degraph could be executed every night and the resulting file could be stored and analyzed. I imagine a timeline of package structures that allow watching a system develop.

Thanks for this tool, Jens!