Home | About Us | Stelligent  

TestEarly Weblog

December 2006


Code Complexity and Code Metrics and /Glover31 Dec 2006 02:25 pm

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.

Developer Testing and /Glover23 Dec 2006 10:40 am

If you are familiar:

you’ll be happy to know about pyUnitPerf, which adds performance testing in a transparent manner to pyUnit tests. Check it out!

Code Complexity and Code Metrics and /Glover19 Dec 2006 12:33 am

There are few metrics that serve as accurate of a touchstone for complexity than Cyclomatic complexity; yet, this metric alone can paint a somewhat misleading picture of true complexity because it doesn’t account for conditional depth.

For example, the following C++ code snippet yields a Cyclomatic complexity value of 5:

if(HighAmountAcct != NULL)
{
  iMgrMemory->FreeUp(HighAmountAcct->GetHighPriorityMssgsResult);
}
if(AQuedAcct != NULL)
{
  iMgrMemory->FreeUp(AQuedAcct->GetQueuedMessagesResult);
}
if(NotifyAcct != NULL)
{
  AtlCleanupValueEx(&NotifyAcct->NotifyAcct, iMgrMemory);
}
if(ReplyAcct != NULL)
{
  iMgrMemory->FreeUp(ReplyAcct->ReplyQueuedMessagesResult);
}
if(RegisterAcct != NULL)
{
  AtlCleanupValueEx(&RegisterAcct->RegisterAcct, iMgrMemory);
}

Regardless of the domain or the language involved here, it’s hard to argue that this snippet of code is terribly complex. Each condition is logically separated– no one condition depends on another. Yet, compare the code above with the code below, which also yields a Cyclomatic complexity of 5:

if(ACCT_FAIL(iSettings->EnumValues(&iEnumValues)))
{
 iSettings->Remove();
}
else
{
 CHAR iActHldr[MAX_AMOUNT];
 if(ACCT_SUCCEED(iEnumValues->Get(iActHldr)))
 {
  if(ccint(iActHldr, iName, len(iName)) == 0)
  {
   sr = iSettings->Delete(iName);
   if (!ACCT_FAIL(sr))
   {
    sr = ACCT_FAIL(iSettingsMgr->Put(iSettings));
   }
  }
 }
}

Again, ignoring the domain tackled here or the perceived complexity of the language, which code snippet do you find more complex? It’s clear that the second example snippet involves conditional depth, which means one must comprehend previous state in order to ascertain the context of an individual line of code– as you get deeper into a series of conditions, the management overhead increases as well.

While Cyclomatic complexity acts as an excellent barometer of complexity, as a stand alone metric, it’s one-dimensional– it only gives a partial picture. The addition of depth gives complexity a second dimension, which yields a far more explicit view. Keep in mind though, both method snippets are testing challenges– it’s just that the second snippet is arguably harder to test.

/Cox and Business Perspectives18 Dec 2006 10:38 am

The only thing more reliable than death, taxes and – perhaps – the Energizer Bunny, is the relentless churn of new feature requests for software products.

The moment you complete the (ridiculously ambitious) feature-set you are working on today, your executive, marketing and sales teams will be dropping a new set of requests in your lap tomorrow.
Energizer Bunny
Another tight schedule. Another Herculean effort. Another amazing delivery.

Then, again (it keeps going, and going, and going), a new set of features.

The problem at most organizations is that the features you add today actually make it harder to add new features in the future.

For a project manager, or VP of Engineering, you can quickly get caught in an ugly cycle:

  1. For the new features, you need to increase the size of your team
  2. As your team grows, your budget pressure grows
  3. With new budget pressure, you have to cut corners on testing and other important infrastructure
  4. If you succeed, the cycle starts over (with an even larger team)

Occasionally, I will talk with someone who suggests that a growing team means growing responsibility and more importance within the organization.

But the problem is that this inefficient cycle reveals itself as the solution ages. A few cycles down the road and we see:

  1. It gets more expensive to add new features
  2. New feature calendars get longer and longer
  3. The budget begins to spin out of control
  4. New features introduce serious defects in seemingly unrelated code

Once a product reaches this stage, the “hero” of the growing team is now answering some difficult questions. The CEO begins seriously considering “moving the product offshore” as if that is some magic elixir – the new team in some foreign country has no domain experience or familiarity with the code, but adding three times as many people will save the day.

Regardless, the fun work environment of addressing customer needs has shifted into a stressful environment of financial pressures and slipping schedules.

At Stelligent, we believe that the way you prevent this inefficient cycle is to invest in your “software assembly line”…find out what is really working and where you could improve. Start setting some targets for code growth, source complexity, code duplication and test coverage. Apply the business practices of “Measure, manage, execute” to your development efforts.

If you’re not sure how to get started, there are many articles here at testearly.com and on our company website that can help point you in the right direction. And, of course, you are always welcome to contact us directly.

Developer Testing and Code Coverage and Code Complexity and /Duvall14 Dec 2006 11:59 pm

Despite our best intentions, many of us don’t always get to work on the latest and greatest language or technology. In some cases, we may need to make our way around a code base that has been written by another team. Given that the average software system lives for 11 years, it’s probably safe to say that there are, in fact, many such cases where we need to quickly assess a new code base to find its flaws (i.e. risks) and determine which portions of the code may be difficult to maintain and extend and which should be easier. If you’re looking at a code base that was developed by another team or even code you just wrote yesterday, once it’s written, it’s now code that you must maintain.

If you need to analyze a code base and determine which portions of the code are more risky than others, what would you do? For me, I use tools that help me quickly assess the code quality. For instance, I’d like to know something I call the “big five” measures:

  • Code complexity
  • Amount of duplication
  • The resilience of the architecture
  • Whether coding standards are being applied
  • Amount of test code coverage

As I mentioned, I like to use tools to help me assess these measures. However, there are sometimes concerns when people consider using code metrics on their projects:

1) Don’t know which tools to use
2) Can be easily abused
3) Not sure what the data means

The table below links a measure to a tool (.NET and Java), the code smell associated with this measure, the refactoring for the smell and possible patterns that may be applied to refactor the code smell.

Measure Smell Tools Refactoring Pattern
Cyclomatic Complexity Conditional Complexity IDE, CCMetrics, Source Monitor, JavaNCSS, Eclipse Metrics Extract Method, Extract Class, Replace Conditional with Polymorphism Abstract Factory, Strategy
Number of Lines in Method Long Method IDE, PMD, Eclipse Metrics, CheckStyle, Source Monitor, FxCop Extract Method Strategy
Depth of Inheritance (DIT) IDE, PMD, Source Monitor Replace Inheritance with Delegation, Pull Up/Push Down Method Delegation

This is not a detailed list, but should give you some ideas. I plan to add to this list in the future. Do you have additional measures|tools|refactorings|patterns? Please share them with us.

Next time you need to target risky parts of your code base, use these tools to obtain metrics so that you can monitor and improve your code quality (through refactoring and patterns) throughout your development lifecycle.

Developer Testing and Continuous Integration and Business Perspectives12 Dec 2006 05:14 pm

Okay, okay…Team Foundation Build has no built-in support for continuous integration, but even Khushboo Sharan, Program Manager, Visual Studio Team System acknowledges the advantages of Continuous Integration and explains how he sees Continuous Integration Using Team Foundation Build working.

News and /Owens and Podcast08 Dec 2006 11:22 am

The third Stelligent Early Quality Podcast, which focuses on Visual Studio Team System, was recently published. Paul Duvall and Trevor Paradis discuss what VSTS is and how it can facilitate easier management through increased traceably throughout the software life-cycle.

If you are unfamiliar with VSTS or simply are curious what it is and how it may be useful to you, check it out this 5 minute podcast!

Build Management and Continuous Integration and /Gurses08 Dec 2006 11:10 am

Yes. That’s what a colleague was telling me a while ago and today was the day I had to experience it myself.

Despite a later port to .NET, CruiseControl.NET seems to have achieved more in that field than its original home turf, Java.

For example today I needed to tag a repository after a successful build. Well, as of ver. 2.5 CruiseControl does not provide that capability out of the box.

Its .NET brother though seems to have thought about the need to tag an archive after successful builds and therefore comes with this nice tag set:

<sourcecontrol type="svn">
 <trunkUrl>svn://svn.stelligent.com/project/trunk</trunkUrl>
 <workingDirectory>c:/dev/ccnet</workingDirectory>
</sourcecontrol>

The <sourcecontrol> tag supports the following attriubutes:

Node Description Type Default Required
trunkUrl The url for your repository (eg. svn://svnserver/) string N/A false
workingDirectory The directory containing the locally checked out workspace. string N/A false
executable The location of the svn executable string “svn.exe” false
username The username to use for authentication when connecting to the repository. string N/A false
password The password to use for authentication when connecting to the repository. string N/A false
autoGetSource Whether to retrieve the updates from Subversion for a particular build. bool false false
webUrlBuilder The root url for the WebSVN site string N/A false
tagOnSuccess Indicates that the repository should be tagged if the build succeeds. bool false false
tagBaseUrl The base url for tags in your repository. string false false
timeout Sets the timeout period for the source control operation. Timeout 10 minutes false

Of those attributes tagOnSuccess and tagBaseUrl are the two that are needed to tag a source repository after a successful build and unfortunately these along with the entire <sourcecontrol> tag are missing from CruiseControl for Java. Oh well, looks like someone will have to begin exploring command prompt SVN calls to tag the repository.

Developer Testing and Business Perspectives07 Dec 2006 12:10 pm

Well, Mercury is not about to be left in the dark or run over by Microsoft. And, even with their powerful market share, they can’t beat Microsoft. So, as the saying goes…if you can’t beat ‘em, join ‘em. Check out this press release by Mercury.

Developer Testing and Business Perspectives07 Dec 2006 10:01 am

Have you started playing around with VSTS yet?!?!? Maybe you should. If you are at all interested in process improvement and decreasing time to market, Microsoft’s Visual Studio Team System is worth exploring.

Look, I don’t have any particular leanings towards (or against) Microsoft, but with VSTS, they really do seem to get at many of the pain points of what a typical shop struggles with as they work through the SDLC.

Okay, so I’m a process guy. I admit it. But any tool that makes the process easier is going to grab my attention.

But, how does it make the process easier you ask?

Well, imagine this…

You get that new contract signed to start working on adding functionality to your website. What’s the first thing you do? Well, the first thing I do is worry about the infrastructure. So, I open excel and start making a list of tasks let’s see…

  1. Assign project setup to Infrastructure Architect
  2. Assign project setup to Solutions Architect
  3. Begin making a project plan with key milestones to help measure progress

And then, I hit a wall…I have to wait for the architect team to give me the go ahead from here. So, because I am a worrier, I check with them constantly until they are done. Then, I can start work on my project plan.

I’m already getting tired and this is just the beginning of the project and I’m destroying my relationship with the architecture team. Wouldn’t it be nice if I could just send out my project setup items to the architecture teams as tasks and monitor there progress in a project based system? Enter VSTS.

VSTS allows you to enter tasks in MS excel import them into your project plan which also has development tasks which are updated as developers check in code and testing tasks that are updated when testers run their tests. See, this is the value of VSTS, it allows me to manage the project without running from one group to the next.

I can see unit test coverage, code progress, test coverage, test results, build results all in one place. I can even see performance test results. Shoot, I can even run the unit tests, the functional tests and not only can I now understand the performance test results, but I can re-run the performance tests at my leisure.

Next Page »