Keeping your codebase healthy

Maintaining a project in a healthy state should have a higher priority in light of recent events. There are a handful of techniques and measures that can be applied to keep the codebase neat and tidy. If your project is built with Gradle then the following list may come in handy when taking matters in to your own hands:

  • ossindex
  • versions
  • license
  • jdeps
  • jacoco
  • checkstyle
  • pmd
  • findbugs/spotbugs
  • codenarc
  • sonarqube

Each plugin takes care of an specific dimension and together they can strengthen your codebase. Let's begin with the ossindex plugin. This plugin scans project dependencies and checks if there are any known vulnerabilities recorded at http://ossindex.net. Here's for example the output of running the audit task on the Griffon codebase

> Task :griffon-guide:audit
org.asciidoctor:asciidoctorj-groovy-dsl:1.0.0.preview2 introduces org.codehaus.groovy:groovy-all:1.8.9 which has 1 vulnerabilities
=> [CVE-2015-3253] Improper Neutralization of Special Elements in Output Used by a Downstream Component ("Injection") (see https://ossindex.net/resource/cve/7149506119)
1 unignored (of 1 total) vulnerabilities found

It looks like the griffon-guide has a potential problem due to a transitive dependency to groovy-all.1.8.9 that has a known vulnerability. As you can appreciate in the report you get a summary of the vulnerability alongside a link that will help you decide in taking action on the particular item. In this case the dependency is not used at all as it's part of the default set of dependencies included by the asciidoctor-gradle-plugin; also the generated documentation is in no way affected by this problem.

The versions plugin generates a report of both build and project dependencies. It can tell you if a dependency is up to date, out of date, or if the configured version is newer than the expected value. Here's a sample report for a large JavaFX (client & server) project I'm currently working on

> Task :dependencyUpdates

------------------------------------------------------------
: Project Dependency Updates (report to plain text file)
------------------------------------------------------------

The following dependencies are using the latest milestone version:
- com.github.ben-manes:gradle-versions-plugin:0.15.0
- com.google.code.findbugs:jsr305:3.0.1
- com.google.guava:guava:22.0
- com.h2database:h2:1.4.196
- com.jidesoft:jidefx-fields:0.9.1
- com.miglayout:miglayout-javafx:5.0
- com.thoughtworks.xstream:xstream:1.4.10
- commons-io:commons-io:2.5
- de.codecentric.centerdevice:javafxsvg:1.2.1
- de.ppi.dbunit.datasetbuilder:dbunit-datasetbuilder:1.4
- eu.mihosoft.jfx.scaledfx:scaledfx:0.4
- io.reactivex:rxjava-string:1.1.1
- jaxen:jaxen:1.1.6
- junit:junit:4.12
- log4j:apache-log4j-extras:1.2.17
- log4j:log4j:1.2.17
- net.nemerosa:versioning:2.6.1
- nl.javadude.gradle.plugins:license-gradle-plugin:0.11.0
- org.apache.commons:commons-collections4:4.1
- org.apache.commons:commons-math3:3.6.1
- org.asciidoctor:asciidoctor-gradle-plugin:1.5.3
- org.awaitility:awaitility:3.0.0
- org.bitbucket.shemnon.javafxplugin:gradle-javafx-plugin:8.1.1
- org.codehaus.griffon.plugins:griffon-glazedlists-javafx:1.3.1
- org.codehaus.griffon:gradle-griffon-plugin:2.12.0
- org.codehaus.griffon:griffon-core-compile:2.12.0
- org.codehaus.griffon:griffon-core-java8:2.12.0
- org.codehaus.griffon:griffon-core-test:2.12.0
- org.codehaus.griffon:griffon-core:2.12.0
- org.codehaus.griffon:griffon-guice:2.12.0
- org.codehaus.griffon:griffon-javafx:2.12.0
- org.dbunit:dbunit:2.5.1
- org.fxmisc.easybind:easybind:1.0.3
- org.fxmisc.undo:undofx:1.3.0
- org.fxmisc.wellbehaved:wellbehavedfx:0.3
- org.hamcrest:hamcrest-all:1.3
- org.jdeferred:jdeferred-core:1.2.6
- org.kordamp.gradle:jdeps-gradle-plugin:0.2.0
- org.kordamp.gradle:stats-gradle-plugin:0.2.0
- org.kordamp.jipsy:jipsy:0.4.1
- org.mockito:mockito-core:2.8.9
- org.projectlombok:lombok:1.16.18
- org.slf4j:slf4j-api:1.7.25
- org.slf4j:slf4j-log4j12:1.7.25
- org.slf4j:slf4j-simple:1.7.25
- org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.5
- org.springframework.data:spring-data-jpa:1.11.6.RELEASE
- org.springframework:spring-aop:4.3.10.RELEASE
- org.zeroturnaround:zt-exec:1.9
- pl.pragmatists:JUnitParams:1.1.0

The following dependencies exceed the version found at the milestone revision level:
- org.fxmisc.richtext:richtextfx [0.7-M3 <- 0.6.10]
- org.reactfx:reactfx [2.0-M5 <- 2.0-M4u1]

The following dependencies have later milestone versions:
- com.google.protobuf:protobuf-gradle-plugin [0.8.1 -> 0.8.3]
- com.google.protobuf:protobuf-java [3.3.0 -> 3.4.0]
- com.google.protobuf:protobuf-java-util [3.3.0 -> 3.4.0]
- com.google.protobuf:protoc [3.3.0 -> 3.4.0]
- io.grpc:grpc-netty [1.5.0 -> 1.6.1]
- io.grpc:grpc-protobuf [1.5.0 -> 1.6.1]
- io.grpc:grpc-stub [1.5.0 -> 1.6.1]
- io.grpc:protoc-gen-grpc-java [1.5.0 -> 1.6.1]
- io.reactivex:rxjava [1.3.0 -> 1.3.2]
- net.engio:mbassador [1.3.0 -> 1.3.1]
- net.sf.jung:jung-algorithms [2.0.1 -> 2.1.1]
- net.sf.jung:jung-api [2.0.1 -> 2.1.1]
- net.sf.jung:jung-graph-impl [2.0.1 -> 2.1.1]
- net.sf.jung:jung-visualization [2.0.1 -> 2.1.1]
- org.codehaus.griffon.plugins:griffon-jdeferred-core [1.0.0 -> 1.1.0]
- org.codehaus.griffon.plugins:griffon-jdeferred-javafx [1.0.0 -> 1.1.0]
- org.kordamp.ikonli:ikonli-fontawesome-pack [1.5.0 -> 1.9.0]
- org.kordamp.ikonli:ikonli-javafx [1.5.0 -> 1.9.0]
- org.kordamp.ikonli:ikonli-material-pack [1.5.0 -> 1.9.0]
- org.kordamp.ikonli:ikonli-materialdesign-pack [1.5.0 -> 1.9.0]
- org.springframework.boot:spring-boot-starter-data-jpa [1.5.6.RELEASE -> 1.5.7.RELEASE]
- org.springframework.boot:spring-boot-starter-test [1.5.6.RELEASE -> 1.5.7.RELEASE]
- org.testfx:openjfx-monocle [1.8.0_20 -> 8u76-b04]
- org.zeroturnaround:zt-process-killer [1.7 -> 1.8]

Failed to determine the latest version for the following dependencies (use --info for details):
- com.github.spring-projects:spring-guice
- gradle.plugin.net.ossindex:ossindex-gradle-plugin
- javax.inject:javax.inject
- net.ltgt.gradle:gradle-apt-plugin
- org.asciidoctor:asciidoctorj-pdf
- org.fxmisc.flowless:flowless
- org.testfx:testfx-core
- org.testfx:testfx-junit

At this particular point in time the project has most of its dependencies in a good shape, perhaps the ones that need a further look are gRPC and spring-boot as they deliver core functionality. The very nature of this particular project requires non GPL licensed dependencies to be consumed. Given that there are so many of them it would take a long time to check each one, fortunately the license plugin defines a task named downloadLicenses that can compile a couple of reports stating the relationship between an artifact and its license. This makes it very easy to find if a particular dependency may need to be evicted and exchanged with an alternative.

Now that Java 9 is upon us it behoves to every Java developer to verify if their projects are compatible with the new rules. I'm not talking about Jigsaw per se, but the API compatibility changes brought by applying Jigsaw to previously private APIs. Granted, the name sun.misc.Unsafe should have warded off many developers however the fact remains that many of its features are desirable in specialized cases. And it's not just Unsafe but also other APIs found in the private space (com.sun for example) that are going away. You can quickly verify if any of your production sources or dependencies may not work properly when running on a Java 9 JVM by simply applying the jdeps plugin. Here's the result I get when running the plugin against the griffon-guice project

> Task :griffon-guice:jdeps
guava-23.0.jar -> /Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/jre/lib/rt.jar
com.google.common.cache.Striped64 (guava-23.0.jar)
-> sun.misc.Unsafe JDK internal API (rt.jar)
com.google.common.cache.Striped64$1 (guava-23.0.jar)
-> sun.misc.Unsafe JDK internal API (rt.jar)
com.google.common.cache.Striped64$Cell (guava-23.0.jar)
-> sun.misc.Unsafe JDK internal API (rt.jar)
com.google.common.hash.LittleEndianByteArray$UnsafeByteArray (guava-23.0.jar)
-> sun.misc.Unsafe JDK internal API (rt.jar)
com.google.common.hash.LittleEndianByteArray$UnsafeByteArray$1 (guava-23.0.jar)
-> sun.misc.Unsafe JDK internal API (rt.jar)
com.google.common.hash.LittleEndianByteArray$UnsafeByteArray$2 (guava-23.0.jar)
-> sun.misc.Unsafe JDK internal API (rt.jar)
com.google.common.hash.LittleEndianByteArray$UnsafeByteArray$3 (guava-23.0.jar)
-> sun.misc.Unsafe JDK internal API (rt.jar)
com.google.common.hash.Striped64 (guava-23.0.jar)
-> sun.misc.Unsafe JDK internal API (rt.jar)
com.google.common.hash.Striped64$1 (guava-23.0.jar)
-> sun.misc.Unsafe JDK internal API (rt.jar)
com.google.common.hash.Striped64$Cell (guava-23.0.jar)
-> sun.misc.Unsafe JDK internal API (rt.jar)
com.google.common.primitives.UnsignedBytes$LexicographicalComparatorHolder$UnsafeComparator (guava-23.0.jar)
-> sun.misc.Unsafe JDK internal API (rt.jar)
com.google.common.primitives.UnsignedBytes$LexicographicalComparatorHolder$UnsafeComparator$1 (guava-23.0.jar)
-> sun.misc.Unsafe JDK internal API (rt.jar)
com.google.common.util.concurrent.AbstractFuture$UnsafeAtomicHelper (guava-23.0.jar)
-> sun.misc.Unsafe JDK internal API (rt.jar)
com.google.common.util.concurrent.AbstractFuture$UnsafeAtomicHelper$1 (guava-23.0.jar)
-> sun.misc.Unsafe JDK internal API (rt.jar)

Warning: JDK internal APIs are unsupported and private to JDK implementation that are
subject to be removed or changed incompatibly and could break your application.
Please modify your code to eliminate dependency on any JDK internal APIs.
For the most recent update on JDK internal API replacements, please check:
https://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+Tool

JDK Internal API Suggested Replacement
---------------- ---------------------
sun.misc.Unsafe See http://openjdk.java.net/jeps/260

Would you look at that, 14 violations found in Google Guava 23.0; unfortunately the project requires Google Guice which brings Google Guava as a transitive dependency. What does this mean? Will Griffon projects run without problems on Java 9? There's a good chance they do but it certainly would better if a newer version of Google Guava were to be published that did not rely on unsupported APIs. We'll still have to see how libraries will cope with the compatibility split that Java 9 brings, will it be multiple artifacts with classifiers? Multi-Resource JARs (MRJARs for short)? The next months will certainly be interesting to watch.

The rest of the plugins in the list deliver capabilities that you may have seen at previous projects/builds as they are also accessible via Maven or Ant. Code coverage, code style checks, potential bugs, and centralized reports. It's worth mentioning that FindBugs and PMD define a comprehensive set of rules for statically checking a codebase. The sonarqube plugin can detect more than the aforementioned plugins but requires reporting capabilities. It may be a good idea to combine all of them to have different perspectives on the same code, as in different reviewers each one with their particular point of view. Here's the summary view of Griffon's code health as seen by Sonarqube

All these plugins can be configured to run on a continuous integration server; there's no excuse to skip generating code health reports at least once a day.

Liked it? Take a second to support aalmiray on Patreon!
Become a patron at Patreon!

Trackbacks/Pingbacks

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

ˆ Back To Top