Home   Contact Us

Productivity and Software Development Tools  

Free Downloads
dbFramework
Priorganizer
 
Support
Development Blog

dbFramework
    Bug Reports
    Blog

Priorganizer
    Bug Reports
    Blog

 

 

Welcome

     

CCMetrics Complexity Analyzer
Download here!
 

A utility for determining the cyclomatic complexity of any .Net binary


PLEASE NOTE: 'CCMetrics Complexity Analyzer' is not yet a finished product, and the current download is a beta test version. You should expect bugs and deficiencies in the utility, and full support for the utility may not be available.

How do we measure how complex source code is?
 
Of course, to get a perfectly accurate measure is next to impossible. And even if you can measure the complexity of source code, maybe the complexity is justified because the requirements are complex - and quantifying the complexity of the requirements is a project unto itself.
 
But, however imperfect they may be, there are some useful metrics out there that we can deduce from analyzing source code. And again, I think it would be quite useful to have this somehow reported during our nightly build, so I wrote a command line tool that would provide me with this information.
 
The complexity metric that I'm going to use is called the Cyclomatic Complexity index, and it basically measures the complexity of a single method based on the number of independent code paths (decisions) that occur in that method. This includes 'if' statements (and each logical condition within the if statement), 'while' and 'for' loops, 'switch' statements, and basically any code form that results in a decision being made.
 
For example, the following method would have a CC of 3 (all methods start out with a CC of 1, there is 1 branch for the if true, and 1 branch for the else):
 
bool ValidateAge(int age)
{
    if (age<21)
        return false;
    else
        return true;
}
 
I've then combined this with the Weighted Methods Per Class index to come up with a complexity index that also takes into account the number of methods per class. This index sums the complexity index for each method in a class, and then averages this out across all classes. The resultant figure should be in the range of 1 - 200, anything above 200 is considered to be questionable and anything about 400 is considered to be in need of a serious refactoring.

Another important metric to follow is the amount of re-use in your application. Re-use is considered to be code that is invoked by two or more other methods, and it's a very important facet of good design in an application. As development progresses on a project, I want to make sure that the amount of code re-use increases as the developers increase their understanding of the application and commonality between components, and so I want a utility that can tell me how much re-use is present in a software project so I track it on a day to day basis.

Note that there's a difference between re-use and re-usability (or the potential for a method to be re-used), and I'll be covering that in a future posting. Right now we're just focusing on how much code re-use is present in a particular application, and not whether that code is capable of being re-used.

One way to calculate a re-use index is to see which methods are called by other methods (a call graph) and somehow process data. This is useful, but it doesn't give me the whole picture. What I'm also interested in is how this helps the overral complexity of the application, not just whether a method has been re-used: I want to determine how much of the complexity of the application is being re-used. In essence, I think it is more acceptable for a highly-reused method to be complex, than an orphaned method that is used only once. Therefore we should be easier on complexity that is re-used in multiple places. Surprisingly I've found little research into measuring the amount of re-use in code, so I'm winging this a bit.

I've modified the complexity analyzer to take re-use into account, providing me with both the average cyclomatic complexity, and a new figure that reduces the cyclomatic complexity based on the method's re-use. The two figures are then aggregated into a figure that tells you what percentage of the complexity of your application is re-used - and the higher this figure is, the better.

In addition to this I'm providing the amount of code re-use. This is determined by increasing the logical size of a method depending on how many times it's called, summing all method sizes together and comparing this to the original application size to create a ratio. The ratio tells us how much general code is re-used in the application.

Also, if you're looking for some insight into the meaning of cyclomatic complexity metrics, you can read this (http://www.aivosto.com/project/help/pm-complexity.html) - to summarize though, the general rule is that the complexity index shouldnt increase beyond 10 per method, or 120 per class (based on the assumption that you shouldn't have more than 12 complex methods in your class) . Anything beyond that and you should look at simplifying the code a bit.

Another feature of ccmetrics is to measure something called "coupling" of code. In a world of extreme programming and service orientation, the trend is to write loosely coupled components that can be easily re-used in future applications with minimal changes. Coupling is really the easiest way for us to determine the re-usability of a class, and the good design of an application.

As part of my build I want to see just how re-usable the code in my project actually is, and I want to see whether a specific change or new feature in the project has somehow affected the overall re-usability of the project.

So what constitutes coupling? Quite a lot of research has been done in this area, especially by Chidamber and Kamerer who devised an index known as "CBO" or "Coupling Between Objects".

The gist of the research is this: Whenever we reference another class in our component's implementation, we're tying ourselves to that class. A reference includes both property accesses and method calls. This means that if we want to use that component later on, we'd have to make sure those dependencies were also available and this complicates our ability to re-use that component.

This can't be said of method calls to interfaces though. Calling a method on an interface instance does not constitute coupling, because the implementation of that interface can easily be replaced, so you're no longer bound to the specific class and can implement the interface yourself making re-use a possibility.

You can read more about Chidamber and Kamerer's work here http://www.pitt.edu/~ckemerer/clnieee.pdf.

Based on my understanding of this metric, I've enhanced my CCMetrics command-line utility so that it now also reports on the coupling of methods and classes. In this case, the coupling index is calculated based on the number of unique classes referenced that are not interfaces. The unique references are counted at the method level as well as the class level. The most-coupled class is reported in the summary, and individual method couplings can be seen in the XML output.

Integrating into a Build

Here's some instructions on how to integrate ccmetrics into your nightly build.

1. Firstly I generate a list file of all the assemblies I want to include in my analysis. Personally I'm going to generate this manually but you could also generate this from a quick "dir *.dll /b > files.lst" command.

Then I want to run CCMetrics on the list. Running CCMetrics without any arguments provides you with a list of the possible arguments:

CCMetrics v0.2 beta, (c) 2004, 2005 J. Wood Software Services LLC
Experimental Software - Use At Your Own Risk!
 
Usage: CCMetrics filename.dll [/x] [/b] [/f path]
 
CCMetrics takes a .Net DLL (or .EXE) and determines the cyclometric
complexity of the projects contained therein.
 
filename.dll is the name of the assembly or executable to analyze.
A *.lst file can be supplied that contains a list of assemblies to
analyze.
 
/m specify the number of methods to display, the default is 6.
/x generates XML output.
/b suppresses the banner.
/f can be used to override the folder to the .Net Framework SDK.
 

The XML output (/x) generally gives you a lot more detail and might be useful when you want to delve into a particular problem, but for the nightly build just the summary will do for me.

My basic requirement is to create a file containing summary statistics of the files, and then mail this out to me every night. So I think I'll end up using a command like this:

CCMetrics files.lst /b /m 10 > analysis.txt

Note that I've upped the number of method stats from the default (6) to 10. This is just personal preference. I've also included /b to suppress outputting the banner, so I can concentrate on just the data.

2. Before I run this command, I want to back up yesterday's analysis.txt so I can compare the values each day. I'll use a simple rename to call the old file "analysis_old.txt".

3. I'll then concatenate these two files together (a dos command such as "type analysis_old.txt >> report.txt" would do this), and send the resultant report.txt file via email. To send it from the build I'll be using this tool.

And we're done. Hopefully I should get an email each day of both today and yesterday's code statistics so that I can compare the values, monitor trends in changes, and be alerted to project changes that add unusual complexity. All in all, I really hope this will help me keep on top of things.

I think it would be really cool if I could graph this data, keeping a history of the analysis taken each day, and then mail out the graph or put it up on a project web page. In the meantime, though, I think this simple text report will suffice.

For more information please visit the forum to discuss. Source code is not available at present - click here to download.

If you find this utility useful, please make a donation by clicking the button below (suggested donation is 10.0 USD)!

Change Log

CCMetrics Complexity Analyzer Change Date
0.1
Initial release
04/09/2005

 

 

 

 

(c) Copyright 2010, RiaForm Technology LLC, All Rights Reserved.