Home | About Us | Stelligent  

TestEarly Weblog

Code Metrics

Developer Testing and Continuous Integration and Code Metrics and Agile and /Duvall29 Aug 2008 11:40 am

One of the primary goals of every developer should be to prevent or drastically limit the number of bugs or defects from being introduced in their source code. It is also our responsibility to write good, extensible, testable, and maintainable code. This however seems like a herculean task to many.

John Smart, has very well said in his latest and greatest "Java Power Tools" book:

When used well, software metrics can provide valuable feedback on the quality of the code being written, and allow the development team to learn and progress. To be successful, software metrics should be considered a team sport.

So, lets automate the task of finding defects early by using open source tools which can look at your source code and in most cases find, if not all, at least some potential defects. There are numerous open source tools like:

1. CheckStyle - is a development tool to help programmers write Java code that adheres to a coding standard.

2. JDepend - traverses Java class file directories and generates design quality metrics for each Java package.

3. JavaNCSS - cyclomatic complexity tool.

4. Simian - identifies duplication in Java. Not open source.

5. Emma - Code coverage tool.

There are several other open source tools as well, like PMD, Cobertura, FindBugs and many more. All these tools are highly configurable as well. I mentioned the above five for a reason. I will get to it soon.

Imagine how much work it is to setup, configure, and run these metric tools as part of your continuous integration. It really is a huge task doing it for each and every project you have.

However, there is just one tool which you need to download: Panopticode. Panopticode includes all the above mentioned tools preconfigured. If you have read Neal Ford’s "The Productive Programmer", chapter 7: Static Analysis" page 113, the author talks about "Generating Metrics with Panopticode". That’s how I got to know about this amazing tool. There is no detailed instructions in the book on how to get this up and running, the web site does have.

So, I decided to give it a try and here are the steps I followed.

Rather than creating a new project, I re-used the PetStore project which I have been using for a long time for all the articles I write.

Follow these steps to get Panopticode up and running:

1. Download Panopticode from here.

2. Unzip and copy to your project folder.

The folder structure will look like this:

panopticode-in-project

3. Make changes to the build.xml file.

In the Panopticode web site, there are 4 steps listed which you can follow. However, rather than copying the entire build file, I modified my existing build file, and ran the new target metrics within the Hudson(Continuous Integration Server) Job .

Add the following lines from the panopticode/build-example.xml to your build file.

3.a

<import file="panopticode/panopticode-imports.xml"></import>

3.b

<target name="metrics" depends="clean">
		<panopticode projectdir="${basedir}" projectname="${ant.project.name}"
                           projectversion="${version}" srcdir="${srcdir}"></panopticode>
	                           </target>
             

In the above target, specify the path to your source directory.

3.c Modify your target which compiles and runs your unit tests to include the following lines:

<panopticode-junit unitTestClasspathId="unittest.path"
	                           outputDir="target">
	            <batchtest todir="target/rawmetrics/xml/junit">
	                <fileset dir="target/classes" includes="**/*Test.class" />
	            </batchtest>
	       

Make changes to the unitTestClasspathId to include the libraries required to run your tests. In my case, I included the JEE libraries required for my EJB application.

4. Run the metrics Ant target.

Run the metrics target either from the command line. You should see an output like this:

[junit] Testcase: validNumberOfLifecycleAnnotations took 0.008 sec
[report] processing input files …
[report] 2 file(s) read and merged in 4 ms
[report] writing [xml] report to [../CodeMetricsProject/target/rawmetrics/xml/emma.xml] …
[report] writing [html] report to [../CodeMetricsProject/target/rawmetrics/html/emma/emma-coverage.html] …
[emmaPanopticode] Loading panopticode structure: panopticode.xml
[emmaPanopticode] Loading supplement: org.panopticode.supplement.emma.EmmaSupplement
[emmaPanopticode] Writing back to panopticode structure: panopticode.xml
[mkdir] Created dir: ../CodeMetricsProject/target/reports/svg
[echo] Building Static Reports
[echo] Building Interactive Reports
BUILD SUCCESSFUL
Total time: 8 seconds

5. Force a Build.
Now that we have all the xml files generated for the metrics tool, we need to make sure run the above target metrics from the Hudson Job, and force a build. You should be able to see the following xml as well as HTML files generated:
reports

6. Configure the XML files.
Finally, configure all these xml files within the Post-Build actions of the Hudson Job, and you should be able to force a build and see the reports in your dashboard. See screen shots below for various metrics:

a. Hudson Dashboard:

Hudson_dashboard

b. Emma Coverage Trend:

emma-coverage-trend

c. Check Style

check-style

d. JavaNCSS

JavaNCSS

7. Troubleshooting.
A few problems I found getting this up and running:

If you see the build failed with the following exception, copy the JDepend library to your ANT_HOME/lib folder.

compile:
    [mkdir] Created dir: /Users/meerasubbarao/Development/ci-jobs/jobs/CodeMetricsProject/workspace/CodeMetricsProject/target/classes
    [javac] Compiling 22 source files to /Users/meerasubbarao/Development/ci-jobs/jobs/CodeMetricsProject/workspace/CodeMetricsProject/target/classes
    [javac] Note: Some input files use unchecked or unsafe operations.
    [javac] Note: Recompile with -Xlint:unchecked for details.
     [echo] Panopticode - Using JDepend for OO metrics
     [echo] If you get an error stating 'Could not create task or type of type: jdepend' then you need to copy the jdepend-2.9.1.jar file to your ANT_HOME/lib directory.

BUILD FAILED
/Users/meerasubbarao/Development/ci-jobs/jobs/CodeMetricsProject/workspace/CodeMetricsProject/build.xml:54: The following error occurred while executing this line:
/Users/meerasubbarao/Development/ci-jobs/jobs/CodeMetricsProject/workspace/CodeMetricsProject/panopticode/panopticode-imports.xml:125: The following error occurred while executing this line:
/Users/meerasubbarao/Development/ci-jobs/jobs/CodeMetricsProject/workspace/CodeMetricsProject/panopticode/supplements/jdepend/jdepend-imports.xml:38: Problem: failed to create task or type jdepend
Cause: the class org.apache.tools.ant.taskdefs.optional.jdepend.JDependTask was not found.
        This looks like one of Ant's optional components.
Action: Check that the appropriate optional JAR exists in
        -/usr/share/ant/lib
        -/Users/meerasubbarao/.ant/lib
        -a directory added on the command line with the -lib argument

Do not panic, this is a common problem.
The commonest cause is a missing JAR.

This is not a bug; it is a configuration problem

Total time: 5 seconds
Publishing Javadoc
Recording Emma reports CodeMetricsProject/reports/emma.xml
finished: FAILURE

In the Panopticode-imports.xml file, you see the following comments:

    <!--
        Panopticode supports multiple competing code coverage tools.  You can switch which tool you use at will and your
        build files will not change.  You must choose exactly one though.  If you do not want to collect coverage data
        then choose the 'nocoverage' import.  You choose your coverage tool by using exactly one of the following import
        statements:

            <import file="plugins/emma/emma-imports.xml" />
            <import file="plugins/cobertura/cobertura-imports.xml" />
            <import file="plugins/nocoverage-imports.xml" />

        The default is Emma.  Try them all to see which one you prefer.
    -->
	<import file="supplements/emma/emma-imports.xml" />

However, if you try to comment the import for emma and use cobertura import definition, you get an error as shown below:

Buildfile: ../CodeMetricsProject/build.xml

BUILD FAILED
../CodeMetricsProject/build.xml:3: The following error occurred while executing this line:
../CodeMetricsProject/panopticode/panopticode-imports.xml:42: Cannot find plugins/cobertura/cobertura-imports.xml imported from ../CodeMetricsProject/panopticode/panopticode-imports.xml

Total time: 223 milliseconds

Now, if I go back and change it to the directory where I found the cobertura-imports.xml file (supplements), I get an exception like this:

[cobertura-report] Report time: 263ms
     [move] Moving 1 file to /Users/meerasubbarao/Development/ci-jobs/jobs/CodeMetricsProject/workspace/CodeMetricsProject/target/rawmetrics/xml
   [delete] Deleting directory /Users/meerasubbarao/Development/ci-jobs/jobs/CodeMetricsProject/workspace/CodeMetricsProject/target/rawmetrics/xml/cobertura
   [delete] Deleting: /Users/meerasubbarao/Development/ci-jobs/jobs/CodeMetricsProject/workspace/CodeMetricsProject/cobertura.ser

BUILD FAILED
../CodeMetricsProject/build.xml:54: The following error occurred while executing this line:
../CodeMetricsProject/panopticode/panopticode-imports.xml:145: emmaFile emma.xml does not exist

Total time: 7 seconds

Next, I changed the report file to cobertura.xml, and the build complained about:

[cobertura-report] Report time: 264ms
     [move] Moving 1 file to ../CodeMetricsProject/target/rawmetrics/xml
   [delete] Deleting directory ../CodeMetricsProject/target/rawmetrics/xml/cobertura
   [delete] Deleting: ../CodeMetricsProject/cobertura.ser
[emmaPanopticode] Loading panopticode structure: panopticode.xml
[emmaPanopticode] Loading supplement: org.panopticode.supplement.emma.EmmaSupplement

BUILD FAILED
../CodeMetricsProject/panopticode/panopticode-imports.xml:145: null

Total time: 8 seconds

Finally, I downloaded the source code to see the classname for this taskdef, couldn’t find one and just gave up at this point.
You should be able to generate coverage report for Emma with no problems at all.

As you can see from this article, it is just a few minutes to setup and start using Panopticode. As I mentioned earlier also, there are many open source tools available, that can improve the quality of your code and also keep track of the same if they are automated and are part of your continuous integration. I am sure once you have these open source tools integrated, you will keep wondering how you developed code without them.

Developer Testing and Code Metrics22 May 2008 09:46 am

GSparklineTest_test1.png
Everyone loves sparklines, and if you want to build them using Groovy, here’s some code that I took from a fabulous example in JRuby, and modified:

package com.stelligent.gsparkyimport org.jfree.chart.JFreeChart
import org.jfree.chart.axis.NumberAxis
import org.jfree.chart.plot.XYPlot
import org.jfree.chart.renderer.xy.StandardXYItemRenderer
import org.jfree.data.general.Dataset
import org.jfree.data.xy.XYSeries
import org.jfree.data.xy.XYSeriesCollection
import org.jfree.chart.ChartUtilities

class GSparky {

    def DEFAULT_HEIGHT = 30
    def DEFAULT_WIDTH  = 150

    boolean build( def data, def imgPath, def height = DEFAULT_HEIGHT, def width = DEFAULT_WIDTH ) {

        def chart = buildChartFromData(data)
        return buildImageFromChart( chart: chart, height: height, width: width, path: imgPath)
    }

    private JFreeChart buildChartFromData( data ) {

        def dataset = generateDataset(data)

        def plot = new XYPlot()
        plot.dataset = dataset

        plot.domainAxis =  minimalAxis()
        plot.rangeAxis = minimalAxis()

        plot.domainGridlinesVisible = false
        plot.domainCrosshairVisible = false
        plot.rangeGridlinesVisible = false
        plot.rangeCrosshairVisible = false
        plot.outlinePaint = null
        plot.renderer = new StandardXYItemRenderer(StandardXYItemRenderer.LINES)
        plot.insets = new RectangleInsets(-1, -1, 0, 0)

        def chart = new JFreeChart(null, JFreeChart.DEFAULT_TITLE_FONT, plot, false)
        chart.borderVisible = false

        return chart
    }

    private boolean buildImageFromChart( args ) {

        ChartUtilities.saveChartAsPNG( new File(args.path), args.chart, args.width, args.height )

        return true
    }

    private Object minimalAxis() {

      def a = new NumberAxis()
      a.tickLabelsVisible = false
      a.tickMarksVisible = false
      a.axisLineVisible = false
      a.negativeArrowVisible = false
      a.positiveArrowVisible = false
      a.visible = false;

      return a
    }

    private Dataset generateDataset(def data) {

        def series = new XYSeries("Sparkline")

        def i = 0
        data.each { y -> series.add(i++, y)  }

        def dataset = new XYSeriesCollection()
        dataset.addSeries(series)

        return dataset

    }
}

And.. a test to demonstrate how it works:

package com.stelligent.gsparky

class GSparklineTest extends GroovyTestCase {

    public void testBuildSparklineImage() {

        def gs = new GSparky()

        def data = [20]

        def r = new Random( new Date().getTime() )

        (0..99).each { x ->
           def y = data.get(x) + (x/2 - r.nextInt(x + 1))
           data << y
        }

        assert gs.build( data, "out/GSparklineTest_test1.png")

    }

}

*Update* - added a line to remove the grey border from around the graph.

Developer Testing and Continuous Integration and Code Metrics18 Apr 2008 09:53 am

Calling all blokes and sheilas– this year’s Asia-Pacific CITCON will be in Melbourne, Australia on June 27th & 28th– registration is now open so claim your spot before space runs out (space is limited to the first 150 tall poppies, surfies, and all around dags)!

If you dream about CI, yabber about TDD, live for BDD, or constantly think about automated deployments, then the Continuous Integration and Testing Conference is a ripper of a time, mates! The conference is free and is run as an OpenSpaces event, so there’s no reason not come. Remember, space is limited so sign up now!

Developer Testing and Continuous Integration and Code Metrics and Agile29 Jan 2008 03:24 pm

This year’s North American CITCON will be in Denver on April 4th and 5th– registration is now open so claim your spot, this instant, before they run out (space is limited to the first 150 people)! If you dream about CI, talk in TDD, live for BDD, or constantly think about automated deployments, then the Continuous Integration and Testing Conference is for you!

I, for one, can’t wait to go, as the last time I went, I met great people and learned a load of new things too– it was the best two days I’ve ever spent in Texas! Plus, the conference is free and is run as an OpenSpaces event, so there’s no reason not come. Remember, space is limited so why are you still reading this and why aren’t you you signing up this instant?

Developer Testing and News and Continuous Integration and Code Metrics and Agile22 Jan 2008 11:12 am

We’re hiring! Come work for the fastest growing Agile consultancy in the mid-Atlantic region. We’re seeking Senior Consultants with Java experience for immediate Agile consulting work.
Stelligent

As a Senior Consultant for Stelligent, you will help transform customer teams through Agile methodologies, build expertise in the latest tools and technologies, and work closely with established Agile experts.

We are currently seeking candidates with:

  • At least three years of Java development experience
  • Experience in all phases of the software lifecycle
  • Ability to work and communicate in diverse client environments
  • Knowledge of Agile methodologies (Scrum and XP)
  • Experience with test driven development (TDD), developer testing frameworks and continuous integration (CI)

Stelligent values team players that are interested in other people and new knowledge, open about exchanging ideas and practical in applying skills towards solving problems.

If this sounds like you, contact us today and tell us why you want to be a part of our team!

Developer Testing and Code Metrics and Podcast29 Oct 2007 04:55 pm

There are myriad code metrics available to measure attributes of code, such as complexity, coupling, and length, but few are arguably useful. In fact, as I’ve stated before, Cyclomatic complexity is the most applicable metric out there for accurately determining risk.

Recently, a few smart individuals married Cyclomatic complexity with code coverage yielding an impressively helpful metric. They’ve dubbed the metric C.R.A.P and while you may shudder at its name, its accuracy will bring goose-bumps.

If you want to learn more, have a listen to JavaWorld’s podcast entitled “Alberto Savoia talks shop about C.R.A.P.“– plus, the guy asking Mr. Savoia all the questions (and chortling a lot) is me!

Developer Testing and News and Continuous Integration and Code Metrics13 Oct 2007 09:27 pm

Do you live for Test Driven Development? Do you dream about implementing Continuous Integration? Do you like helping other people adopt these principles?

Stelligent

If you answered yes to these questions, you should consider working for Stelligent! We’re growing and are looking to build our team with superstars having solid software development experience (Java, .NET, C++, etc) and who live and breathe Agile techniques (like TDD and CI).

See our Employment page for more information and apply today!

Developer Testing and Code Metrics26 Sep 2007 02:09 pm

There are some excellent articles and posts around the internet recently related to a question asked on LinkedIn about metrics and code quality. Specifically, the question asked was:

What are the useful Metrics for Code Quality?

The user goes on to state that

The quality of any software application will depend mostly on its code base and it’s important to know what might be the key metrics that help us to evaluate the stability and quality of the code base.

Many of the answers bring up excellent points, including different ways of viewing the question, such as taking the time to understand what attributes of code are related back to quality. For example, Michael Bolton aptly suggests you ask if the code is:

  • testable
  • supportable
  • maintainable
  • portable
  • localizable
  • What’s more, further answers suggest coverage, code size, and other metrics as discrete measurements that can help gauge quality. These are all excellent answers; however, the answer turns out to be quite simple.

    We have found time and time again that there is one metric that most appropriately relates to code quality: Cyclomatic complexity. If your code base has highly localized pockets (i.e. methods) of Cyclomatic complexity (or CC) your code will have issues (undoubtedly affecting quality how ever you define it) eventually.

    In fact, CC affects arguably every attribute listed above (testable through localizable). Think about it for a minute: a method that has 27 different paths is next to impossible to adequately test, which means you’re going to have a doozy of time supporting it because it isn’t easy to maintain. Code that is littered with high CC is a blast to port as well (hopefully you’ve got deep pockets and customers that absolutely love you). Good luck localizing it too.

    It turns out that the other metrics mentioned (such as code size) tend to correlate to each other– in fact, it seems that all complexity-like metrics point back to CC. Classes that have a lot of dependencies are usually big and big classes usually have big methods and big methods usually have lots of conditionals. Lots of conditionals mean a high CC value (CC measures paths through a method, such as from an if/else chain).

    Code coverage is an excellent metric for ascertaining what code isn’t touched by tests and it happens to relate directly to CC because in order to reach 100% branch coverage you’d have to have a one to one relationship with CC (i.e. if a method has 27 different paths, you’d need 27 tests to reach full coverage). Plus, coverage can be unfortunately misleading and can provide a false sense of security.

    The beauty of CC is that it’s one metric. One number is all you need to understand risk. You can then apply it in many ways. For example, we provide development teams with ratios related to CC (because CC precisely delineates complex methods it’s often helpful to relate it to other normalized metrics) that enable them to gauge quickly the overall health of a code base. When the ratios grow, things are getting worse and when they decrease, happiness ensues.

    The definition of quality (and its associated attributes) as it relates to software has traditionally been quite hard to nail down (regardless if you are a customer or a developer); however, one thing is factual– complex code is a house of cards that will eventually collapse (via attrition, bankruptcy, ossification, etc). Finding complexity and proactively reducing it will lead to software that is more testable, maintainable, and supportable. And by the way, that happens to be the kind of software customers like.

Developer Testing and Build Management and Code Metrics and Podcast12 Jul 2007 02:46 pm

For his latest Automation for the people installment, “Asserting architectural soundness”, Stelligent CTO, Paul Duvall, demonstrates how using tests such as JUnit, JDepend, and Ant can play a role in enforcing architectural reliability.

Asserting architectural soundness describes a technique to build checks into your build scripts to proactively detect violations while coding. Locating potential deviations as soon as they’re introduced, instead of waiting to flag problems after the fact, ultimately leads to better quality software delivered faster.

In addition, Scott Laningham, host/editor of IBM developerWorks podcasts, interviewed Paul about the software development need that he addressed in the article. Paul kicked off the interview by indicating that,

Over time software architectures tend to become brittle. The architecture that you think you have versus the architecture that you actually have, as its manifested in the code, is often different.

Whether you read the article or listen to the podcast (hopefully both!), you’ll undoubtedly carry away the need to take charge of your architecture by using a proactive build process.

Developer Testing and Code Complexity and Code Metrics and Tutorial and Agile11 Jun 2007 04:05 pm

Who cares about software metrics? As a Java developer, I do. Measuring certain aspects of my code lets me quantify my schedule, work effort, product size, project status, and code quality. Oh, and then my project manager cares too. If I don’t measure my current status (number of classes, dependencies to other modules, complexity, code coverage, defects as well as code smells - yes, we all know when we have code smells) and use the data to improve my code and my future work estimates, those estimates will just be guesses. And my project manager expects a little better than guesses.

Metrics is an Eclipse plugin that helps me take a holistic view of various aspects of my code. I use it on a daily basis to see how my project grows and if there are any deviations from the reference architecture. The plugin lets me take a closer look at:

  • Number of Classes
  • Method Lines of Code
  • Number of Methods
  • Nested Block Depth - Is nice, I like!
  • Depth of Inheritance Tree - nobody wants to traverse a 16-node deep tree trying to find what they need. 1-5 maybe, but 16….too many levels…
  • Afferent Coupling, Efferent Coupling - yea, whatever… we saw this here…same story…
  • Cyclomatic Complexity - If my code is simpler than Paul’s does that make me look “simpler” too?
  • …and more…

Quick Tutorial

  1. Download and start Eclipse 3.2
  2. Navigate to Help | Software Updates | Find and Install
  3. Select Search for new features to install
  4. Add a new remote site Metrics and point it to http://metrics.sourceforge.net/update
  5. Finish the wizard and restart Eclipse
  6. Download the sample solarsystem project from http://www.testearly.com/resources/agile/solarsystem.zip. Open the project in Eclipse. Note that this sample requires Java SDK 6.0.
  7. Build the project
  8. In the Package Explorer, right-click the solarsystem project and open the Properties dialog. Locate Metrics and check Enable Metrics
  9. Rebuild solarsystem
  10. Navigate to Window | Show View | Metrics | Metrics View
  11. You are looking at a table of various metrics covering the solarsystem project
  12. metrics001
  13. Feel free to dig down on each metric as it goes from source folder to package to class down to the method
  14. Notice all metrics for this simple project are in blue and there are no exclamation marks in the source code indicating any problems. Let’s change that and make life difficult for ourselves.
  15. Open the preferences page for Metrics and check Enable out-of-range warnings. Drill one level down to Safe Ranges, locate Nested Block Depth and enter 5 as the Max value. Similarly, enter 10 as the Max value for McCabe Cyclomatic Complexity
  16. In a Java Perspective open PlanetUtil.java and add the following method:
    public void thisIsAComplexMethod() {
            if (true) {
                    if (false) {
                            if (true) {
                                    if (false) {
                                            if (true) {
                                                    System.out.println("This is a deeply nested if sequence.");
                                            }
                                    } else {
    
                                    }
                            }
                    }
            }
    
            if (true) {
                    if (false) {
                            if (true) {
                                    if (false) {
                                            if (true) {
                                                    System.out.println("This is a deeply nested if sequence.");
                                            }
                                    } else {
    
                                    }
                            }
                    }
            }
    }
    
  17. Rebuild solarsystem and return to the Metrics View. You now see two red lines in the results table and an exclamation mark in the code editor. Clearly the new code failed the cyclomatic complexity and nested statements rules of Metrics and therefore was marked red. The cyclomatic complexity of the method is 11, while the if statements nest for 6 levels. Both values are out of the acceptable ranges we defined earlier.
  18. metrics002
  19. Locate the Dependency Graph View icon in the Metrics View. It can be found on the upper right corner and it is denoted by four dots connected in a square. Click the icon to open the graphical dependency view of Metrics.
  20. metrics003
  21. The packages in the project are denoted by boxes in different colors. Blue means normal relationship; red means cycles and orange denotes the selected node. There is also a circle in the middle, the tangle center, which displays the number of packages in a particular tangle and the longest walk. In general, the longer the walk the more layers are involved and therefore there may be refactoring opportunities. Similarly, the existence of red nodes and tangles indicates cycles in the package dependencies and that’s also something that may be avoided with a little care. Finally, every node and the tangle center provide right-click menus to drill-down for more details.
  22. The reason for this tangle (cycle) is the JUnit test PlanetUtilTest, which is located in com.solarsystem.jupiter. Let’s do something about this.
  23. In the Package Explorer, locate PlanetUtilTest, right-click and select Refactor | Move. Move the test into a new package com.solarsystem.test.jupiter.
  24. Rebuild the project. Open the Metrics View. Click the graph icon. Everything should be blue. There should be no tangles. No tangle centers. Blue is better than red. Life is good…
  25. metrics004
  26. Enjoy.

Next Page »