Cyclic dependencies have long been seen as a major code smell. We like to point to John Lakos as a reference [Lako1996], and a Google search about this topic will bring up valuable resources if you are unfamiliar with the negative effects. In this blog post, I take it as a given that you are interested in detecting cycles and that you agree that they should be avoided. If you see things differently, that’s fine by me – but then this blog post won’t be really interesting for you.
A number of static analysis tools exist that can detect those cycles in your code base automatically. SonarQube was one of them, until the Dependency Structure Matrix (DSM) and cycle detection was dropped with version 5.2. The DZone article by Patroklos Papapetrou (“Working with Dependencies to Eliminate Unwanted Cycles”) and the SonarQube documentation (“Cycles – Dependency Structure Matrix”) illustrate the previous functionality.
I noted that some people are missing those features badly and complain about their removal. The comments of the issue “Drop the Design related services and metrics” and the tweet of Oliver Gierke are two examples.
But thanks to the SonarQube ecosystem of plugins, there is a solution: Use the free Sonargraph Explorer and the Sonargraph Integration Plugin to get the checks for cycles back in SonarQube!
I will demonstrate that the setup and integration of Sonargraph into the build is fast and easy.
The following steps are needed to setup the environment (I assume that you are familiar with SonarQube and Maven configuration). Note that Sonargraph requires to be executed on a JDK 1.8:
- It is more fun to explain the functionality with a concrete well-known project. Clone the Guava project and check that you can build it locally with Maven. In case you get compilation errors, make sure you use the latest JDK 1.8.
- Download the latest SonarQube.
- Get and install the latest Sonargraph Integration plugin either via the SonarQube update site (start the server first) or from the plugin’s homepage.
NOTE: Make sure that you installed the plugin compatible with Sonargraph 9+!
- Start the SonarQube server. If you use the default configuration, you can check at http://localhost:9000 that the server is up and running.
- Run “mvn clean package -Dmaven.test.skip=true sonar:sonar” to verify the setup (I skip the tests to save some time). Check that the project appears now in SonarQube.
- Register at hello2morrow’s web site and request a free Sonargraph Explorer license.
Log in to your account and check the license at “Account” -> “Your Licenses”. You will need the activation code of your license later.
- Configure a profile in SonarQube and activate the Sonargraph cycle rules. Make this profile the “default profile”.
Configure a quality gate and set a tight threshold on the cycle related metrics (e.g. Number of Cyclic Packages).
- Integrate the Sonargraph analysis in the Maven build by adding the Sonargraph Maven repository to the pom.xml or globally in your settings.xml:
<pluginRepositories> <pluginRepository> <id>hello2morrow.maven.repository</id> <url>http://maven.hello2morrow.com/repository</url> </pluginRepository> </pluginRepositories>
- Run the Maven build again and add the Sonargraph goal to it (insert your activation code, of course):
mvn clean package -Dmaven.test.skip=true com.hello2morrow:sonargraph-maven-plugin:dynamic-report -Dsonargraph.activationCode=<your activation code> -Dsonargraph.sonargraphBuildVersion=9.1.1 -Dsonargraph.prepareForSonarQube=true sonar:sonar
This will generate a Sonargraph system dynamically at guava/target/guava-parent.sonargraph, run the analysis, generate a report and integrate the findings with SonarQube.
If you do not want to overwrite the same system over and over, you can define the target directory via the parameter “systemBaseDirectory”. You can then re-use that system with the goal sonargraph:create-report.
More information about the Sonargraph Maven integration can be found in the online user manual. (The same functionality is available for Gradle as well.)
- Download the latest Sonargraph application for your platform and open the generated system.
Examine the Results
When the Maven build is running, you should see some logging statements on the console that SonargraphBuild has been executed. Additionally, Sonargraph generates an HTML report at guava/target/sonargraph that contains all issues detected by Sonargraph.
If you refresh the project in SonarQube, you should now see a couple of more issues and additional metrics. The quality gate should have been missed because of the detected package cycles.
Once you drill-down to the issues, you will see that there are only “Component Cycles”, but no “Package Cycles”. This has the following background:
Sonargraph determines cycles on different levels: Modules, system namespaces, module namespaces and components.
Module cycles are usually prevented by the build infrastructure. Maven and OSGi don’t allow cycles between modules.
System namespaces are logical namespaces across modules that have been unified by Sonargraph: If there is a class a.b.c.T1 in module1 and a class a.b.c.T2 in module2, then they are contained in the same logical system namespace.
Module namespaces are logical namespaces within the scope of a module but unified by Sonargraph across all source directories: If there is a class src/main/java/a/b/c/T1.java and another
class src/test/java/a/b/c/T3.java, then they are contained in the same logical module namespace.
Components are defined within Sonargraph as “The smallest unit of design is what we call a physical component (or just component in its short form). For most languages like Java or C# that would be just a single source file…” (see online documentation).
Issues in SonarQube need to be attached to a physical resource. As you can see from the definitions above, this is unfortunately not possible for the logical system and module namespaces. Thus, the number of cycle issues found in Sonargraph and the one’s reported in SonarQube might differ, but the metric values are the same!
If you open the generated system with Sonargraph, you can analyse all detected cycles and their underlying dependencies in great detail as shown in the following screenshots. More information is available in the online user manual.
The commercial “Architect” license even allows to simulate different ways to breakup individual cycles.
Sonargraph offers the possibility to fill the gap caused by the removal of the “design” related functionality in SonarQube.
With little configuration effort you can create similar issues and metrics in SonarQube about cyclic dependencies as was previously possible with the DSM. Even better, you can analyze individual cycle groups in great detail with the Sonargraph standalone application and come up with ideas of how to resolve them. Several views support that use case as demonstrated on our product homepage.
If you have any questions or feedback, please leave a comment below or send an email to support<at>hello2morrow.com.
We love to hear from you!
[Lako1996] Large-scale C++ software design, John Lakos, 1996
Working with Dependencies to Eliminate Unwanted Cycles, Patroklos Papapetrou, 2012
Cycles – Dependency Structure Matrix, SonarQube Documentation, 2014
Issue “Drop the Design related services and metrics”, SonarQube Issue Tracker, 2015
Tweet about missing DSM, Oliver Gierke, 2016