Posts Tagged ‘Error-Proneness’
Below is the detailed outline for my August 8, 1:30-5:00PM Technical Debt Workshop in Agile 2011. I look forward to meeting you and interacting with you in the conference before, during and after this workshop!
Technical Debt: Assessment and Reduction
Part I: Technical Debt in the Overall Context of the Software Process
- A Holistic Model of the Software Process
- Two Aspects of Output
- Three Aspects of Technical Debt
- Six Aspects of Software
Part II: What Really is Technical Debt?
- What’s in a Metaphor?
- Code Analysis
- Time is Money
- Monetizing Technical Debt
- Typical Stakeholder Dialog Around Technical Debt
- Analysis of the Cassandra Code
- Project Dashboard
Part III : Case Study – NotMyCompany, Inc.
- NotMyCompany Highlights
- Modernizing Legacy Code
- Error Proneness
Part IV: The Tricky Nature of Technical Debt
- The Explicit Form of Technical Debt
- The Implicit Form of Technical Debt
- The Strategic Impact of Technical Debt
- No Good Strategy Following Prolonged Neglect
Part V: Unified Governance
- How We View Success
- Three Core Metrics
- Productivity, Affordability, Risk
- What is the Real ROI?
Part VI: Process Control Models
- A Typical Technical Debt Pattern
- Process Control View of Scrum
- Integration of Technical Debt in the Agile Process
- Using Statistical Process Control Methods
Part VII: Reducing Technical Debt
- A Framework for Thinking about and Acting on Technical Debt Issues
- Portfolio Governance
Part VIII: Takeaways
- Nine Simple Takeaway
- Connecting the dots
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: http://www.enerjy.com/blog/?p=198)
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.
“[The 100% loan-to-value subprime loan is] the most dangerous product in existence and there can be nothing more toxic…”
This quip by Angelo Mozilo, founder of Countrywide Financial, led me to coin the term “toxic code.” The code stops being an asset when it accumulates technical debt equal to the value it is expected to generate. As matter of fact, the code could become a liability when the cost to “pay back” the technical debt exceeds the revenues the code would generate. Such situations have been known to happen more often than we might realize. They occur, for example, when numerous customers develop elaborate business processes around poor quality enterprise software.
I will be exploring the topic in my May 27, 2010 presentation at The Path to Agility conference in Columbus, OH. Here is the abstract of my talk:
Technical debt had originally been conceived as an expediency measure – “a little debt speeds development so long as it is paid back promptly with a rewrite.” However, like financial debt, unrestrained borrowing can lead to a broad spectrum of difficulties, from collapsed roadmaps to inability to respond to customer problems in a timely manner, and anything in between.
Recent advances in source code analysis enable us to quantify technical debt and express it in $$ terms. By so doing, the software development process can be governed with unprecedented effectiveness. It is possible to constrain the “development on margin” mal-practice and avoid the toxic code phenomenon: technical-debt-to-value ratio of 100%. Moreover, even toxic code can ultimately be “marked-to-market” by reducing/eliminating technical debt.
The combination of Agile refactoring practices with technical debt analytics brings rigor to the software development process through:
- Providing quantifiable data about the overall state of the code and its value
- Highlighting error-prone modules in the code and offering guidance to fixing them in a biggest-bang for-the-buck manner
- Pinpointing technical issues all the way down to the individual line of code level
- Balancing the technical debt work stream vis-a-vis other work streams
In the course of managing software development in this manner, your team will improve its design, coding, testing and project management skills. Ultimately, these improvements are the best antidote against accrual of technical debt in the future.
Technical debt is usually perceived as a measure of expediency. You borrow a little (time) with the intent of paying it back as soon as possible. To quote Ward Cunnigham:
Shipping first time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite… I thought that rushing software out the door to get some experience with it was a good idea, but that of course, you would eventually go back and as you learned things about that software you would repay that loan by refactoring the program to reflect your experience as you acquired it.
As is often the case with financial debt, technical debt accrues with compound interest. Once it reaches a certain level (e.g. $1 per line of code) you stare at a difficult question:
Should I ship this code before reducing the accrued technical debt?!
The Figure below, taken from An Objective Measure of Code Quality by Mark Dixon, answers the question with respect to one important component of technical debt – cyclomatic complexity. Once complexity per source code file exceeds 74, the file is for most practical purposes guaranteed to contain errors. Some of the errors in such a file might be trivial. However, a 2007 study by Capers Jones indicates about a third of the errors found in released code are likely to be serious enough to stop an application from running or create erroneous outputs.
To answer the question cited above – Should You Ship This Software Before Reducing Technical Debt?! – examine both cost and risk for the number of error-prone files you are about to unleash:
- The economics of defect removal clearly favor early defect removal over late defect removal. The cost of removal grows exponentially as function of time.
- Brand risk should be first and foremost on your mind. If complexity figures higher than 74 per file are more of the norm than the exception, you are quite likely to tarnish your image due to poor quality.
If you decide to postpone the release date until the technical debt has been reduced, you can apply yourself to technical debt reduction in a biggest-bang-for-the-buck manner. The analysis of complexity can identify the hot spots in your code, giving you a de-facto roadmap you would be wise to follow.
Conversely, if you opt to ship the code without reducing technical debt, you might lose this degree of freedom to prioritize your “fix it” work. Customer situations and pressures might force you to attend to fixing modules that do not necessarily provide as much bang for the buck.
Postscript: Please note that the discussion in this post is strictly limited to intrinsic quality. It does not address at all extrinsic quality. In other words, reducing/eliminating technical debt does not guarantee that the customer will find the code valuable. I would suggest reading Beyond Scope, Schedule and Cost: Measuring Agile Performance in the Cutter Blog for a more detailed analysis of the distinction between the two.
Erratum: The figure above is actually taken from a blog post on the Mark Dixon paper cited in my post. See McCabe Cyclomatic Complexity: the proof is in the pudding. My apology for the error.