Code conditionals like if and else clauses trigger complexity metrics like Cyclomatic complexity. The more conditions in a method, the higher the Cyclomatic complexity value– and the higher the value, the greater chance there’s a defect lurking somewhere the code (either presently or about to be coded). Granted, there are degrees of complexity associated with conditions too– the deeper the depth a series of conditionals reaches, the more complex it becomes compared to a linear sequential series of if clauses.
There are also a host of false positives within code that’ll flag Cyclomatic complexity. Defensive coding constructs, for example, that check various input values to ensure they meet acceptable conditions will trip Cyclomatic complexity and depending on the number of checks, yield high values. For example, the following simple method, which is part of a class that implements an Ant task, yields a Cyclomatic complexity value of 4:
private void validate() throws BuildException{
if(this.report == null){
throw new BuildException("Report Element was null");
}
if(this.sourceDependencies == null){
throw new BuildException("no source dependencies configured");
}
if(this.targetDependencies == null){
throw new BuildException("no target dependencies configured");
}
}
While this example is relatively un-complicated, it’s by no means unique– the defensive coding constructs employed here can be found across many a code base– all doing essentially the same thing. In the Aspect Oriented Programming (AOP) world, this is known as a crosscutting concern. These constructs span horizontally across a code base, which usually, using OO methodologies, are captured vertically using hierarchies.
Just like the trite logging examples that permeate AOP articles, using AOP constructs, you can effectively remove repetitive defensive coding constructs and replace them with advices defined in aspects. For example, OVal is a validation framework that makes use of AOP to facilitate the use of simple constraints, which can be checked before or after a desired method is invoked.
Taking the code above, you can retro-fit class members (like report and sourceDependencies, for example) with @NotNull annotations and make use of OVal’s @PreValidateThis annotation to automatically validate their values– thus you can effectively remove the validate method.
For example, using OVal, the class itself must be annotated with the @Guarded annotation. Then, the three class members from above are annotated like so:
@Guarded
public class DependencyFinderTask extends Task {
@NotNull
private Report report;
@NotNull
private SourceDependencies sourceDependencies;
@NotNull
private TargetDependencies targetDependencies;
// class body below...
}
Next, the execute method (which previously called the validate method from above) needs to be augmented with @PreValidateThis annotation. This means that when execute is invoked, an advice will trigger OVal’s code to ensure that all three members are not null. Thus, the execute method is decorated as so:
@PreValidateThis
public void execute() throws BuildException {
//method body with validate() removed....
}
Thus, using AOP constructs (as implemented by OVal), I’ve eliminated three conditionals (indeed, an entire method) and placed the burden on OVal. With the addition of annotations to Java and improved AOP tools, making use of AOP isn’t that much of a hurtle. There are performance issues to consider; however, in controlled environments, you can easily turn the aspects off.