Improving code complexity
Have you ever noticed that long methods are sometime hard to follow? Ever had trouble understanding the logic in an excessively deeply nested conditional? Your copasetic instincts for eschewing this type of code are correct. Long methods and methods with a high number of paths are hard to understand and, interestingly enough, tend to correlate to defects.
In fact, a number of studies in the early days of computing (before the Golden Age of Disco) did show a correlation between the number of paths through code and defects. One such metric that arose from these studies was Cyclomatic Complexity. This integer based metric precisely measures complexity by counting the distinct paths through a method; moreover, various studies over the years have determined that methods having a cyclomatic complexity (CC or sometimes referred to as CCN) value greater than 10 have a higher risk of defects.
JavaNCSS is an excellent tool which determines the lengths of methods and classes by examining Java source files. What’s more, this tool also gathers the cyclomatic complexity of every method in a code base. By configuring JavaNCSS either through its Ant task or via a Maven plug-in, an XML report is generated which lists:
- The total number of classes, methods, non commenting lines of code, and varying comment styles in each package
- The total number of non commenting lines of code, methods, inner classes, and JavaDoc comments in each class
- The total number of non commenting lines of code and the cyclomatic complexity per each method in the code base
The tool ships with a few hip style sheets which can then be used to generate an HTML report summarizing the data. For example, the HTML report generated by Maven has a section section labeled “Top 30 functions containing the most NCSSâ€, which details the largest methods in the code base, which incidentally almost always correlate to methods containing the highest cyclomatic complexity. For instance, this report lists the class DBInsertQueue’s updatePCensus method as having a length of 283 and a cyclomatic complexity (labeled as CCN) of 114.
The question now becomes “so what?â€
Because high cyclomatic complexity values tend to correlate to defects, the first course of action is to verify the existence of any corresponding tests. If there are any tests, how many are there? A neat-o rule of thumb when dealing with cyclomatic complexity is in order to obtain full coverage of a method, one would need an equal number of test cases to the cyclomatic complexity value (i.e. in the example above, to achieve full coverage of the updatePCensus method, 114 test cases would be required). All but the most rare code base would actually have 114 test cases for this method, however, having a few is a great start in reducing the risk of this method containing defects.
If there aren’t any associated test cases, there is an obvious need to test this method (if it turns out there is a desire to truly lower the risk of defects). Some may immediately think it’s time to refactor; however, that would break the first rule to refactoring: write a test case. Once test cases are in place, lower risk refactoring can occur. In the case of cyclomatic complexity, the most effective way to reduce it is to apply the extract method technique and push the complexity into smaller, more manageable and therefore. more testable methods. Of course, then those smaller methods should then be tested.
In a Continuous Integration environment, evaluating this method’s complexity over time becomes possible. For instance, having run the report for the first time, this method’s complexity value can be monitored for any associated growth. If this is the case, appropriate action can be taken.
If a method’s CCN value keeps growing, teams can do a number of things:
- Ensure a healthy amount of related tests are present to reduce risk
- Evaluate the possibility of refactoring the method to reduce any long term maintenance issues
Because JavaNCSS also reports on documentation trends, these values can be monitored for organizational documentation standards. Interestingly enough, the tool reports single line comments and multi-line comments in addition to JavaDocs. In some software circles, the mere presence of a high amount of inline code comments can be considered an indication of complexity.
JavaNCSS isn’t the only trippin’ tool available to the Java platform which can facilitate complexity reporting. PMD, another open source project, which analyzes Java source files, has a series of rules which report on complexity, including cyclomatic complexity, long classes and long methods. CheckStyle is another open source project with similar rules as well. Both PMD and CheckStyle also have Ant tasks and Maven plug-ins.
Complexity has been shown to correlate to defects; therefore, it makes sense to monitor a code base’s complexity values and take appropriate actions to lower defect risks via test cases and refactoring. Dig it?
| Related odds and ends | ||
|---|---|---|
Saturday 11 Mar 2006 | Code Metrics, Continuous Integration, Developer Testing