The Agile Executive

Making Agile Work

Posts Tagged ‘Cyclomatic Complexity

Delving into Technical Debt

leave a comment »

Many of the findings and the recommendations we make in Cutter technical debt engagements are broadly applicable in concept, if not in detail. There is commonality in the nature of the hot spots we typically find, the mal-practices we identify as the root causes and the ways we go about reducing the “heat.”  Granted, your technical debt reduction strategy might dictate investing in automated unit testing prior to reducing complexity, while your competitor might be able to address complexity without additional investment in unit testing. However, the considerations you and your competitor will go through in devising your technical debt reduction strategies are fairly similar.

It is this similarity that we try to capture in this Executive Update. Some of specifics we recount here might not be applicable to your environment. However, we trust the overall characterization we provide will give you, your colleagues and your superiors a fairly good “3D” picture of how the technical debt initiative will look like in the context of your own business imperatives and predicaments.

The good folks at Cutter have released the Executive Update from which the excerpt cited above is taken. It is co-authored by colleague Chris Sterling and me. For a free donwnload, click here and use the promotion code DELVING.


Written by israelgat

October 31, 2011 at 7:28 pm

SPaMCAST 112 – Israel Gat, Technical Debt

leave a comment »

Click here for my just published interview on Technical Debt. Major themes discussed in the interview are as follows:

  • The nature of technical debt
  • Tactical and strategic effects of technical debt
  • How the technical debt metric enables you to communicate across levels and functions
  • What Toxic Code is and how it is related to Net Present Value
  • The atrocious nature of code with a high Error Feedback Ratio
  • Cyclomatic complexity as a predictor of error-proneness
  • Use of heat maps in reducing technical debt
  • Use of density of technical debt as a risk indicator
  • How and when to use technical debt to ‘stop-the-line’
  • Use of technical debt in governing software

To illuminate various subtle aspects of technical debt, I use the following metaphors in the interview:

  • The rusty automobiles metaphor
  • The universal source of truth metaphor
  • The Russian dolls metaphor
  • The mine field metaphor
  • The weight reduction metaphor
  • The teeth flossing metaphor

Between the themes and the metaphors, the interview combines theory with pragmatic advice for both the technical and the non-technical listener.

Round Two: Can Technical Debt Constitute a Breach of Implied Warranties?

with 2 comments

In a previous post I discussed whether technical debt could under some conditions constitute a breach of implied warranties. Examining the subject with respect to intent, I made the following observation:

It is a little tricky (though not impossible – see Using Credit limits to Constrain Development on Margin) to define the precise point where technical debt becomes “unmanaged.” One needs to walk a fine line between technical/methodical incompetence and resource availability to determine technical fraud. For example, if your code has 35% coverage, is it or is not unmanaged? Does the answer to this question change if your cyclomatic complexity per class exceeds 30? I would think the courts might be divided for a very long time on the question when does hidden technical debt represent a fraudulent misrepresentation.

One component  of technical debt deserves special attention in the context of this post. I am referring to the conscious decision not to do unit testing at all… Such a conscious decision IMHO indicates no intention to pay back this category of technical debt – unit test coverage. It is therefore quite incompatible with the nature of an implied warranty:

Responses to my post were mixed. Various readers who are much more knowledgeable in the law than I am pointed out various legal defenses a software vendor could use. Click here for a deeper understanding of these subtle legal points.

Imagine my delight reading yesterday’s uTest interview with Cem Kaner. Cem makes the following statement in his interview:

ALI [American Law Institute] … started writing the Principles of the Law of Software Contracts. One of its most important rules is one that I advocated: a seller of software who knows about a defect of the software but does not disclose the defect to the customer will be held liable for damages caused to that customer by that defect. Note that this does not apply to free software (not sold). And if the seller discloses the defect, it becomes part of the product’s specification (it’s a feature). And if the seller doesn’t know about the defect there is no liability (once customers tell you about a defect, you have knowledge, so you cannot avoid knowledge for long by not testing). ALI adopted it unanimously last year. This is not law, but until the legislatures pass statutes, the Principles will be an important guide for judges. Even though I am a minor contributor to this work, I think the defect-disclosure requirement might be my career’s most important contribution to software quality. [Highlights by IG].

While not (yet?) a law, the Principles could indeed lead us where IMHO we as an industry should be. Technical debt manifests itself as bugs. By making the specific bugs part of the spec the software evolves from a quality standpoint. Moreover, the defect-disclosure requirement practically force software vendors to address their bugs within a “reasonable” amount of time. Customer bugs become an antidote to the relentless pressure to add functions and features without paying due attention to software quality.

I guess I missed the opportunity to include technical debt in the 2010 revision of the Principles. As we always do in software, I will target the next rev…

Technical Debt Meets Continuous Deployment

with 11 comments

As you would expect in a conference entitled velocity, and in a follow-on devops day, speeding up things was an overarching theme. In the context of devops, the theme primarily manifested itself in lively discussions about the number of deploys per day. Comments such as the following reply to my post Ops Driven Dev were typical:

Conceptually, I move the whole business application configuration into the source code…

The theme that was missing for me in many of the presentations and discussions on the subject was the striking of a balance between velocity and quality. The classical trade-off in process control is between production rate and product quality (and safety, but that aspect [safety] is beyond the scope of this post). IMHO this trade-off applies to software just as it applies to mechanical or chemical processes.

The heart of the “deploy early and often” strategy hailed by advocates of continuous deployment is known deployment state to known deployment state. You don’t let the deployment evolve from one state to another before it has stabilized to a robust state. The power of this incremental deployment is in dealing with single-piece (or as small number of pieces as possible) flow rather than dealing with the effects of multiple-piece flow. When the deployment increments are small enough, rollback, root cause analysis and recovery are relatively straightforward if a deployment turns sour. It is a similar concept to Agile development, extending continuous integration to continuous deployment.

While I am wholeheartedly behind this devops strategy, I believe it needs to be reinforced through rigorous quality criteria the code must satisfy prior to deployment. The most straightforward way for so doing is through embedding technical debt criteria in the release/deploy process. For example:

  • The code will not be deployed unless the overall technical debt per line of code is lower than $2.
  • To qualify for deployment, code duplication levels must be kept under 8%.
  • Code whose Cyclomatic complexity per Java class is higher than 15 will not be accepted for deployment.
  • 50% unit test coverage is the minimal level required for deployment.
  • Many others…

I have no doubt whatsoever that code which does not satisfy these criteria might be successfully deployed in a short-term manner. The problem, however, is the accumulative effect over the long haul of successive deployments of code increments of inadequate quality. As Figure 1 demonstrates, a Java file with Cyclomatic complexity of 38 has a probability of 50% to be error-prone. If you do not stop it prior to deployment through technical debt criteria, it is likely to affect your customers and play havoc with your deployment quite a few times in the future. The fact that it did not do so during the first hour of deployment does not guarantee that such a  file will be “well-behaved” in the future.


Figure 1: Error-proneness as a Function of Cyclomatic Complexity (Source:

To attain satisfactory long-term quality and stability, you need both the right process and the right code. Continuous deployment is the “right process” if you have developed the deployment infrastructure to support it. The “right code” in this context is code whose technical debt levels are quantified and governed prior to deployment.

Using 3σ Control Limits in Software Engineering

with 2 comments

Source: Wikipedia; Control Chart

The  July/August 2010 issue of IEEE Software features an article entitled “Monitoring Software Quality Evolution for Defects” by Hongyu Zhang and Sunghun Kim. The article is of interest to the software developer/tester/manager in quite a few ways. In particular, the authors report on their successful use of 3σ control limits in c-charts used to plot defects in software projects.

To put things in perspective, consider my recent assessment of the results accomplished by Quick Solutions (QSI) in two of their projects:

One to one-and-a-half standard deviation better than the mean might not seem like much to six-sigma black belts. However, in the context of typical results we see in the software industry the QSI results are outstanding.  I have not done the exact math whether those results are superior to 95%, 97% or 98% of software projects in Michael Mah‘s QSMA database as the very exact figure almost does not matter when you achieve this level of excellence.

A complementary perspective is provided by Capers Jones in Estimating Software Costs: Bringing Realism to Estimating:

Another way of looking at six-sigma in a software context would be to achieve a defect-removal efficiency level of about 99.9999 percent. Since the average defect-removal efficiency level in the United States is only about 85 percent, and less than one project in 1000 has ever topped 98 percent,  it can be seen that actual six-sigma results are beyond the current state of the art.

The setting of control limits is, of course, quite a different thing from the actual defect-removal efficiency numbers reported by Jones for the US and the very low number of defects reported by Mah for QSI. Having said that, driving a continuous improvement process through using 3σ control limits is the best recipe toward eventually reaching six-sigma results. For example, one could drive the development process by using Cyclomatic complexity per Java class as the quality characteristic in the figure at the top of this post. In this figure, a Cyclomatic complexity reading higher than 10.860 (the Upper Control Limit) will indicate a need to “stop the line” and attend to reducing complexity before resuming work on functions and features.

Coming on the heels of the impressive results reported by David Joyce on the use of statistical process control (SPC) techniques by the BBC, the article by Zhang and Kim is another encouraging report on the successful application of manufacturing techniques to software (and to knowledge work in general). I am not at liberty to quote from this just published IEEE article, but here is the abstract:

Quality control charts, especially c-charts, can help monitor software quality evolution for defects over time. c-charts of the Eclipse and Gnome systems showed that for systems experiencing active maintenance and updates, quality evolution is complicated and dynamic. The authors identify six quality evolution patterns and describe their implications. Quality assurance teams can use c-charts and patterns to monitor quality evolution and prioritize their efforts.

Can Technical Debt Constitute a Breach of Implied Warranties?

with 12 comments

POGO_film_diffs by Dancing Lemur.

Photo credit: Dancing Lemur (Flickr)

Cunningham’s quip “A little debt speeds development so long as it is paid back promptly with a rewrite” is intuitively very clear. We are talking about short-term debt which will be reduced, and hopefully eliminated in entirety, at the earliest possible time.

The question this post addresses is what happens when the expected short-term technical debt becomes a significant long-term debt? Specifically, can technical debt under some conditions constitute a breach of implied warranties?

In his InformIT article Don’t “Enron” Your Software Project, Aaron Erickson coined the term “Technical Fraud” and connected it to Lemmon Laws:

As a reaction to seeing this condition and its deleterious effects, I coined the term technical fraud to refer to the practice of incurring unmanaged and hidden technical debt. Many U.S. states have “lemon laws” that make it illegal to knowingly sell someone a car that has undisclosed maintenance problems. Selling a “lemon” is a fraudulent practice in the world of cars, and it should be considered as such in the world of software.

It is a little tricky (though not impossible – see Using Credit limits to Constrain Development on Margin) to define the precise point where technical debt becomes “unmanaged.” One needs to walk a fine line between technical/methodical incompetence and resource availability to determine technical fraud. For example, if your code has 35% coverage, is it or is not unmanaged? Does the answer to this question change if your cyclomatic complexity per class exceeds 30? I would think the courts might be divided for a very long time on the question when does hidden technical debt represent a fraudulent misrepresentation.

One component  of technical debt deserves special attention in the context of this post. I am referring to the conscious decision not to do unit testing at all.

Best I understand it, the rationale for not “bothering” with unit testing is a variant of the old ploy “we do not have time for testing here.” It is a resource allocation strategy that bets on the code being miraculously bug-free. Some amount of functional testing is done out of necessity – the code in customers hands needs to function as proclaimed.  But, the pieces of code  from which functionality is constructed are not subject to direct rigorous testing. The individual units of code will be indirectly exercised in some manner through functional testing, but not in a systemic manner to verify and validate correctness of the units of code per se.

Such a conscious decision IMHO indicates no intention to pay back this category of technical debt – unit test coverage. It is therefore quite incompatible with the nature of an implied warranty:

An implied warranty is as an unstated promise, assumed by the law in most sales transactions, that the product will be of at least average quality and will do what the average customer would expect it to do  [The Reader’s Digest Legal Questions & Answers Book]

To #1 defense open to a software vendor who gets sued over lack of unit testing is that a fair average quality of software can be attained without any unit testing. As a programmer, I would think such defense would fly at the teeth of the availability since 1987 of the IEEE Standard for Software Unit Testing.

It is fascinating to note the duality between contracts and programming.  For the programmer who follows the tenets of design by contract, “a unit test provides a strict, written contract that the piece of code must satisfy…”

Disclaimer: I am not an expert in the law. The opinion expressed in this post merely represents my layman’s understanding of  principles of contract law that might be applicable to technical debt situations.

How to Use Observations From Outside the Agile Process

with 2 comments

a9723 The Whorl of Architecture by tengtan.

Photo credit: tengtan (Flickr)

Most posts on technical debt in this blog emphasize the use of technical debt for strategic decision-making. In this post we will point out the use of technical debt in Agile teams at the tactical level. Specifically:

  • Every two weeks; and/or,
  • With every build.

Taking a close look at the various components of technical debt during the  bi-weekly iteration review meeting provides plenty of useful information to the process. For example, you might look for insights to explain the following:

  • Why is the unit test coverage figure going down?
  • Any particular reason the cyclomatic complexity figure has gone up?
  • Why is the figure of merit for design lower than the figure indicated in the previous iteration review meeting?
  • Many others…

The emphasis in this mode of operation is on guiding the retrospection. Plenty of good and valid reasons might exist for any of the trends mentioned above. However, observing the trends helps you ask the right questions, focusing on what happened during the iteration just completed. In conjunction with technical debt data from previous iteration review meetings, trends that characterize your software development project become visible. You may or may not need to change anything you are doing, but you become very conscious of any “let’s not change” decision.

An intriguing practice suggested by colleague and friend Erik Huddleston is to make technical debt a criterion for the build to pass. The build automatically fails if the technical debt figure has gone up. Or, if you are very focused on a specific aspect of technical debt such as complexity, you fail the build whenever the complexity figure of merit rises above  a certain pre-determined threshold. For example, you might fail a build in which the cyclomatic complexity per method has exceeded 4.

The power of failing a build whenever the technical debt arises is in utilizing the build as an exceptionally effective influence point. You instill the discipline of reducing technical debt one build at a time. If your team aggressively practices continuous integration, it will address technical debt issues multiple times a day. Instead of staring at a “mountain” of technical debt towards the release of a product, you chunk it to really small increments that get addressed “real-time.” For instance, a build that failed due to lack of comments can usually be fixed very quickly by the developer who “upset the apple cart” while the logic embedded in the code is fresh on his/her mind.

A good insight to the way the tactical use of technical debt techniques adds value is provided by the following observation: the technical debt data is observed from outside the Agile process. Hence, technical debt data  is nicely suited to guiding the process. If you think of the software engineering fabric as a virtual stack, the technical debt “layer” could be considered a layer above the Agile process.