借助Sonar 评估你的技术债务

16163916_4aXJ

技术债务是一个很出名的概念,它是在1992年由沃德•坎宁安(Ward Cunningham)(wiki创始人)提出的,他在最近的视频中谈到了这个话题。从那时以来,在博客以及文章上,这个话题被讨论和研究了无数次。在这里我不能描述它的很多细节,但我可以推荐你去阅读那些被认为是在这个主题之下的相关文章,比如:Martin Fowler。这里摘录了一篇文章,通过比喻给出了一个的观点:

在这个比喻中,我们通过临时应急的方式设置了一个技术债务,它类似于经济上的债务。就像经济上的债务,技术上的债务也是要付利息的,它存在于我们将来的开发上,因为选择了临时的应急措施,在某个时候,我们将会付出某种形式的额外代价。我们可以选择继续付利息,或者我们可以选择通过重构过去的临时处理方案,直接支付本金,获取更好的设计。虽然它当场支付掉了本金,却可以让我们在未来减少利息上的支出。

这个比喻看起来已经被许多开发者接受了,并且每天还有许多人在推特上讨论关于临时措施带来的技术债务。但是除了这个概念,是时候回到评估偿还上来了,没有哪篇文章介绍如何计算债务或者去计算债务的方法。这类似于借钱去买了一个房子,但是2年之后却没有办法知道剩余的债务,以及每个月要还多少利息:-)。

通过Martin Fowler的描述,开发者很明智,并且许多时候会做出深思熟虑的选择去借取——为了买时间。当开始一个新的开发,正如你所知道,正好是技术债务……为0的时候。但是,当扩展或者维护一个遗留的程序时,那就是另外一个故事了,没有人知道它确切地历史欠账。当一个开发者没有遵循最佳的实践方法的时候,你可能没有意识到,你就已经借了钱了。那就是为什么,评估大致的技术债务是非常有用的。

在介绍Sonar插件之前,这里有一些有趣的和相关的概念要介绍:

在维护一个应用时,每次你添加或者改动一行代码,却没有任何的单元测试就类似于借钱
跳过设计阶段就类似于借钱去获取一个非常“快速”和“可预期”的投资回报
重构就类似于偿还掉本金
当利息上涨时,开发效率降低
管理者不重视代码质量,就问问他们关于偿还的债务问题,让他们重视起来
破产是一个在技术债务逻辑上的扩展,指的是在技术债务上失去了控制……我们称之为系统重写
当讨论源代码质量的时候,我喜欢谈谈这里的七宗罪,每一个都代表质量分析上的主要问题:不均匀分布的复杂性,重复代码,缺乏注释,违背代码规范,潜在的bug,没有单元测试或者无效的代码和糟糕的设计。你已经知道,Sonar实际上覆盖了它们中的6种类型,除此之外的1/7(糟糕的设计)可能也开始摇晃了:-)它被覆盖那只是时间的问题。

从这个观察来看,为了得到在各方面都完美分数,我们决定建立新的量化指标反映到底有多少的工作量是需要的。换言之,就是在一个项目中每一笔债务偿还的成本。通过汇总结果,我们获得了一项全面的指标,在我们的报告中使用了$符号来保持它的趣味性!连同这个指标在内,每个指标都被重新分配,也就是说,每个指标有多少(份额)被分配进技术债务中。

当前插件的版本是0.2,并且可以使用下面的表达式去计算债务 :

Debt(in man days) = cost_to_fix_duplications + cost_to_fix_violations +
cost_to_comment_public_API + cost_to_fix_uncovered_complexity +
cost_to_bring_complexity_below_threshold

条件:

Duplications   = cost_to_fix_one_block * duplicated_blocks
Violations   = cost_to fix_one_violation * mandatory_violations
Comments   = cost_to_comment_one_API * public_undocumented_api
Coverage   = cost_to_cover_one_of_complexity * uncovered_complexity_by_tests (80% of coverage is the objective)
Complexity   = cost_to_split_a_method * (function_complexity_distribution >= 8) + cost_to_split_a_class * (class_complexity_distribution >= 60)

 

通过计算这种方式, 它可以接近实际中的情况,技术债务的量化(测定)是宝贵的:

在项目,模块(等等)上,它是一项综合的指标
它可以在时间上被跟踪(历史数据,趋势)
它可以让众多项目进行比较
他可以被深度探讨,甚至可以……
作为第一个版本,你可能要被提示选择一些选项,为了插件的配置可以更灵活地被调整,付出一些是值得的。

插件已经被安装在Nemo中,作为Sonar的公开实例,现在有超过80个开源项目被计算了债务。插件仅仅依赖于有效的Sonar扩展点上,并且是能通过Sonar计算的高水平量化案例。

今天,我将停下我讲述技术债务的脚步,但还是想简单地提一下我们后续计划要添加的东西:利息,负债比率和项目风险概况。我确信你想要知道你自己项目中的技术债务……那么,我希望你现在就回到Sonar这个话题,去安装这个新插件

——————-

英文原文:

The technical debt is a well-known concept that was invented by Ward Cunningham in 1992 and that he’s recently talked about in this video. Since then, it has been discussed and developed numerous times in blogs and articles. I am not going to describe it in great details here, I rather recommend that you read what it is considered as the reference article on the subject, by Martin Fowler. Here is an extract of this article that gives a synthetic view of the metaphor :

In this metaphor, doing things the quick and dirty way sets us up with a technical debt, which is similar to a financial debt. Like a financial debt, the technical debt incurs interest payments, which come in the form of the extra effort that we have to do in future development because of the quick and dirty design choice. We can choose to continue paying the interest, or we can pay down the principal by refactoring the quick and dirty design into the better design. Although it costs to pay down the principal, we gain by reduced interest payments in the future.

This metaphor seems to be accepted by many developers already and every day someone tweets about the urgent need to pay back his technical debt. But beyond the concept, when time comes to evaluate the amount to be repaid, there is simply no literature on how to calculate the debt or at least approach it. It’s like borrowing money to buy a house but 2 years later having no way to know what is the remaining debt and how much interest are being paid each month :-).

As stated by Martin Fowler, developers are good and sometimes make deliberate choice to borrow in order to buy time. That’s true when starting a new development as you know exactly the amount of technical debt… that is to say 0. But when extending or maintaining a legacy application, that’s another story as nobody knows exactly how bad it is. Further more you might even not be aware that you are borrowing money, when a developer simply does not follow best practices. That is why, evaluating even roughly the technical debt is very useful.

Before introducing this Sonar plugin, here are few funny and relevant quotes on the concept :

Maintaining an application without any unit tests is like borrowing money each time you add or change a line of code
Skipping design phase is like borrowing money to get a very “quick” and “predictable” return of investment
Refactoring is like paying down the principal
Development productivity decreases when interests grow up
Managers don’t care about code quality, just ask them to pay the debt in order get their attention
Bankruptcy is logical extension of technical debt uncontrolled… we call it a system rewrite
When discussing source code quality, I like to say that there are seven deadly sins, each one representing a major axis of quality analysis : bad distribution of the complexity, duplications, lack of comments, coding rules violations, potential bugs, no unit tests or useless ones and bad design. As you know already, Sonar actually covers 6 of them but the seventh one (bad design) should probably start shaking 🙂 as it is a matter of time it gets covered as well.

From this observation, we decided to build new metrics that reflect how much effort is required in order to get a perfect score on the various axes. In other words, what is the cost of reimbursing each of the debts in the project. By combining the results, we obtain a global indicator that we report in $$ to keep it fun ! Along with this indicator comes the repartition of each axis, i.e. how much did each axis participated to the technical debt.

The current version of the plugin is 0.2 and uses the following formula to calculate the debt :

 

Debt(in man days) = cost_to_fix_duplications + cost_to_fix_violations +
cost_to_comment_public_API + cost_to_fix_uncovered_complexity +
cost_to_bring_complexity_below_threshold

Where :

Duplications   = cost_to_fix_one_block * duplicated_blocks
Violations   = cost_to fix_one_violation * mandatory_violations
Comments   = cost_to_comment_one_API * public_undocumented_api
Coverage   = cost_to_cover_one_of_complexity * uncovered_complexity_by_tests (80% of coverage is the objective)
Complexity   = cost_to_split_a_method * (function_complexity_distribution >= 8) + cost_to_split_a_class * (class_complexity_distribution >= 60)

Beyond the calculation that is a broad approximation of the reality, the technical debt measure is precious as :

it is a consolidated metric on projects, modules…
it can be followed in the TimeMachine (historical data, trend)
it enables to compare projects
it is possible to drill down on it even to… the class
As a first version, you probably noticed that we took some options, however most of the values for costs can be adjusted in the plugin configuration.

The plugin has been installed on Nemo, the public instance of Sonar, that now calculates the debt of more than 80 Open Source projects. The plugin relies only on the available Sonar extension points and is good example of advanced metrics that can be computed with Sonar.

I am going to stop here on the technical debt for today, but would like to simply mention what we plan to add to it next : interests, debt ratio and project risk profile. I let you now go back to Sonar to install this new plugin as I am sure you want to know what is the technical debt of your project…