如何有效衡量可维护性?


23

上下文:我是全MS商店中的企业开发人员。

谁能推荐一种客观地衡量一段代码或应用程序可维护性的好方法?

为什么要进行可维护性:我对小组中的“质量”度量标准感到厌倦,该度量标准仅围绕bug的数量和代码覆盖率而变化。这两个指标都很容易使用,尤其是当您不评估可维护性时。目光短浅和截止日期导致大量技术债务,这些债务从未真正得到解决。

为什么具有客观衡量的能力:我在一个大型企业集团中工作。如果您不能客观地衡量它,就不能让人们对此负责,也不能使他们变得更好。主观测量要么不会发生,要么不会持续发生。

我正在查看VS2010代码指标,但我想知道是否还有其他建议。


@Anon-我同意,但至少它将为我提供一个起点。现在什么都没有了。它甚至不必玩。
nlawalker

1
我真的看不到没有同行代码审查怎么办。有人需要真正了解整个系统的设计(并且必须存在)才能看一看代码单元,然后通过改进的设计来改进它,或者这是代码重写或老牌,您的工具已经过时了...类似地,您可以维护总体指导原则,例如“嘿,将索引硬编码到Gridview中不是一个好主意,使用itemtemplates并按名称选择列”。归根结底,开发人员必须变得出色且具有团队合作精神。达芬奇无法教人敬畏。
P.Brian.Mackey

8
如果您拥有开发人员游戏指标,而不是已经编写好的代码,那么添加更多指标也将导致他们也使用这些指标,但不会解决问题。解决方案是完全取消指标,并使用其他方式(例如,公共代码审查)来确保代码质量。
Anon。

3
“所有可以计数的东西都不一定要计数;所有必须计数的东西都不一定要计数。”
杰森·贝克

@nlawalker除了回答者已经提出的问题之外,您的问题还带有一个可疑的假设,即如果存在这样的衡量标准,人们可以对此做些什么。可维护性低是软件本身外部各种因素的结果:程序试图解决的问题,员工经验,人员流动,上市时间,范围变更等问题的难易程度或定义得当……您简直无法悬赏对此,期望问题是善意的问题。
亚瑟·哈维利切克

Answers:


7

衡量可维护性的警告是您试图预测未来。代码覆盖率,错误计数,LOC,循环复杂性都可以解决当前问题

现实情况是,除非您有具体的证据证明该代码无法按原样进行维护,即..修复错误,由于代码无法维护,导致N个小时的不必要时间;那么要站起来就很难了。在这个例子中,这可能是由于当一个简单得多的东西就足够时,使用了一种过于复杂的方法。踏足尝试测量方法论,范式和最佳实践的领域变得越来越困难,几乎没有长期收益。

不幸的是,走这条路是无路可走的。着重于发现具有实质性优点且与个人看法无关的根本问题,例如在整个代码库中缺乏命名约定,并找到一种方法来衡量围绕该根本问题的成败。然后,这将使您可以开始构建一组构建块,然后可以从中开始制定解决方案。


7

好吧,我使用或喜欢认为自己使用的度量是:

对于每个独立,单行,单行,保留或保留的功能需求,在实现代码库之前对其进行快照。然后实施它,包括查找并修复过程中引入的所有错误。然后diff在代码库之前和之后运行a 。该diff会告诉你所有的插入,删除和修改实施的变化的列表。(就像插入10行连续的代码是一次更改。)在那里进行了多少次更改?该数字越小,通常代码越可维护。

我称之为冗余源代码,因为它就像纠错代码的冗余一样。该信息包含在1个大块中,但被编码为N个大块,所有这些必须一起完成才能保持一致。

我认为这是DRY背后的想法,但是有点普遍。减少计数的好处是,如果需要N次更改来实现典型的要求,并且作为一个容易犯错的程序员,您一开始只能正确完成N-1或N-2个操作, 1或2个错误。除了O(N)编程工作之外,还必须发现,定位和修复这些错误。这就是为什么小氮好。

对于尚未了解代码工作方式的程序员来说,可维护性不一定意味着可读性。优化N可能需要做一些事情,为程序员创造学习曲线。 这是一个例子。 有助于解决问题的一件事是,如果程序员试图预见未来的变化,并在程序注释中留下指导说明。

我认为,当N减少得足够远(最佳值为1)时,源代码读取的内容就更像域特定语言(DSL)。该程序并没有“解决”问题,而只是“陈述”了问题,因为理想情况下,每个需求只是作为单个代码重新表达。

不幸的是,我没有看到人们学习如何做到这一点。相反,他们似乎认为心智名词应成为类,动词应成为方法,而他们要做的就是转动曲柄。根据我的经验,结果是N等于或大于30。


这是否不是一个非常宏大的假设-所有功能需求的大小都大致相同?而且这种度量标准是否会阻止责任分离?我需要实现水平功能;因此,最“可维护”的代码是对程序的几乎完全重写,该程序完全包含在一个整体方法中。
亚罗诺(Aaronaught)2011年

@Aaronaught:我不知道它有多伟大,但是在我们小组中,我们根据需求/功能列表进行工作,有些是相互依赖的,有些不是。每个人都有一个相对简短的描述。如果需要进行重大重写,请确保我已经看过/完成了这些,但是对我来说,这可能是组织代码的更好方法。这是我的典型例子。我并不是说这很容易学习,但是一旦学会,它可以节省大量的工作量,并且可以快速进行更改而不会出错。
Mike Dunlavey

5

可维护性并不是真正可测量的。这是基于个人的经验和偏好的主观看法。

为了给出一段代码,可以给出一个完美设计的想法。

然后,对于实际代码与该完美代码的任何偏差,将100的值减小一些。具体取决于选择的非完美方法的后果。

一个例子:

一段代码读取并导入了某种数据格式,如果出现错误,则可能会显示错误消息。

完美的解决方案(100)将错误消息保存在一个公共位置。如果您的解决方案直接在代码中将它们硬编码为字符串常量,那么您可以节省15%。因此您的可维护性指数变为85。


4

难以维护的代码的结果之一是,它需要花费更长的时间(“平均”)来修复错误。因此,乍看之下,一个度量标准似乎是修复从分配漏洞(即开始修复)到“准备测试”所需的时间。

现在,这只有在您修复了一定数量的错误以获得“平均”(意味着)时间之后,才能真正起作用。您不能将数字用于任何特定的错误,因为要追查的难度不仅取决于代码的“可维护性”。

当然,当您修复更多错误时,随着变得更好(或至少应该如此),代码变得“易于维护”,并且您对代码也越来越熟悉。与之相反的是,这些错误将变得更加晦涩难懂,因此更加难以发现。

这也遭受这样的问题,即如果人们倾向于匆忙地修正错误以获得较低的分数,从而导致新的错误或无法正确地修复现有的错误,从而导致更多的工作甚至是更糟糕的代码。


2

我发现Visual Studio代码度量标准非常适合提供快速的“可维护性”度量标准。捕获了5个主要指标:

  • 圈复杂度
  • 继承深度
  • 类酷儿
  • 代码行(每个方法,每个类,每个项目,取决于您的汇总级别)

可维护性指数是我觉得很方便的一项。它是一个综合索引,基于:

  1. 总大小(代码行)
  2. 类或文件的数量
  3. 方法数量
  4. 循环复杂度大于20(或10-可配置,我更喜欢10)
  5. 复制

有时,我会研究可维护性指数低的方法(低=对这一方法不利)。几乎没有失败,我的项目中具有最低可维护性指数的方法是最需要重写且最难读取(或维护)的方法。

计算的更多信息,白皮书


1

两个有意义的是循环复杂性和类耦合。您无法消除复杂性,您所能做的就是将其分成可管理的部分。这两种措施应该使您了解可以将难以维护的代码放置在何处,或者至少在看起来最困难的地方。

循环复杂度是代码中有多少条路径的度量。每个路径都应该测试(但可能不是)。复杂度超过20的东西应该分解成较小的模块。复杂度为20的模块(一个模块可以复制20个连续的if then else块),其测试上限为2 ^ 20。

类耦合是对类绑定的紧密程度的度量。我在前任雇主工作过的一些不良代码的示例包括一个“数据层”组件,该组件在构造函数中包含约30个项目。对该组件最“负责”的人一直在向构造函数/打开调用添加业务和UI层参数,直到这真是一个大难题。如果记忆正确地为我服务,则大约有15个不同的new / open调用(有些不再使用),所有参数都略有不同。我们建立代码审查的唯一目的是阻止他做更多这样的事情-为了避免使我们看起来像他那样单挑,我们审查了团队中每个人的代码,所以我们浪费了半天时间来4-6每天都有人,因为我们没有


2
老实说,让每个人都对代码进行审查并不是一件坏事。您可能会觉得自己在浪费时间,但是除非所有人都以此为借口,否则您应该从他们那里获得有价值的见解。
Anon。

1

最重要的是,可维护性实际上只能需要之后进行衡量,而不能在之前进行。也就是说,您只能告诉您一段代码是否可维护,何时必须维护它。

衡量将一段代码适应不断变化的需求有多么容易是相对显而易见的。提前进行测量,如何响应需求变化几乎是不可能的。这意味着您必须预测需求的变化。如果可以的话,您应该获得诺贝尔奖;)

您唯一可以做的就是根据一组具体规则(例如SOLID原则)与您的团队达成共识,大家都认为这通常会提高可维护性。
如果原则选择得当(我认为从SOLID入手将是一个不错的选择),您可以很清楚地证明它们遭到了侵犯,并要求作者对此负责。
您将很难过,试图提出一种绝对的可维护性度量标准,同时逐步说服您的团队坚持一套既定的既定原则,切实可行。


1

从未真正解决的大量技术债务

那“被事件超越”的技术债务又如何呢?

我编写糟糕的代码,然后将其投入生产。

您正确地观察到它是不可维护的。

但是,该代码是产品线的最后一轮功能,由于法律环境已更改且该产品线没有前途,因此将停用该功能。

立法变更消除了“技术债务”,使之全部过时。

由于外界的考虑,“可维护性”度量标准从“差”变为“无关”。

如何测量?


“一百年后,我们所有人都会死,这都无关紧要。某种角度看待事情,不是吗?” 如果有什么不相关的地方,那么这个回答并不是问题的答案。
马丁·马特

0

对等代码审查的第二件事是在对单元或产品进行编码之前,创建一个可工作的体系结构。 红绿重构是解决该问题的一种非常简洁的方法。让一个高级人员汇集一个可行的界面并精简工作。每个人都可以抓住难题,以红色绿色赢得胜利。在此之后,对等代码审查和重构将是有序的。这在我以前开发的主要产品上效果很好。


0

问卷调查

为开发人员制作一个匿名问卷,每月大约填写一次呢?这些问题将类似于:

  • 上个月您有多少时间(大约)花在了X项目上[0%... 100%]
  • 您如何根据可维护性[非常差,差,中立,可以,很好,非常好]评估代码库的状态。
  • 与项目的复杂度相比,您对代码库的评估有多复杂(过于复杂,恰到好处,过于简化)。
  • 由于代码库过于复杂,您多久感到自己受阻于完成任务?[一点也不,偶尔,经常,不断地]。

(请随意添加您认为对评估注释中的可维护性有用的其他问题,我将添加它们。)


0

我可以考虑两种方法来检查可维护性(我相信还有更多希望其他人可以提出好的定义。

修改时不了解。

是否可以将错误修复程序引入代码中并解决问题,而无需了解整个系统的工作原理。

这可以通过提供全面的单元测试(回归测试)来实现。您应该能够检查对系统的任何更改是否都不会改变系统在任何特定良好输入下的行为。

在这种情况下,错误修复程序应该只需要很少的系统知识就能进入并修复(简单)错误。如果该修复程序有效,则所有回归测试都不会失败。如果任何回归测试失败,则需要进入第2阶段。

maintainabilty1 = K1 . (Code Coverage)/(Coupling of Code) * (Complexity of API)

修改后就可以理解了。

如果错误修复变得不那么重要,则您需要了解系统。那么系统的文档是什么样的。我们不是在谈论外部API的文档(它们相对没有用)。我们需要了解的是系统如何在实现等中使用的任何巧妙(阅读技巧)技巧下工作。

但是文档还不够,代码必须清晰易懂。为了衡量代码的可理解性,我们可以使用一些技巧。开发人员完成编码后,请给他/她一个月的时间从事其他工作。然后请他们回来,并在码头现在可以理解系统的范围内记录系统。如果代码相对容易理解,那么它应该很快。如果写得不好,他们将花费更长的时间来解决他们构建的内容并编写文档。

因此,也许我们可以提出一些措施:

maintainability2 = K2 . (Size of doc)/(Time to write doc)

0

我经常发现“最短等效”解决方案往往最易于维护。

在这里,最短意味着最少的操作(不是行)。等效意味着较短的解决方案不应比以前的解决方案具有更差的时间或空间复杂性。

这意味着所有逻辑上相似的重复模式都应提取为适当的抽象:相似的代码块?提取功能。似乎同时出现的变量?将它们提取到struct / class中。其成员仅因类型而异的类?您需要一个通用的。您似乎在许多地方重新计算了同一件事?首先计算,然后将值存储在变量中。这样做将导致代码更短。这基本上就是DRY原理。

我们也可以同意删除未使用的抽象:不再需要的类,函数是无效代码,因此应将其删除。版本控制会记住我们是否需要恢复它。

经常争论的是仅引用一次的抽象:非回调函数仅被调用一次,没有理由被多次调用。仅使用一种类型实例化的泛型,并且没有理由将其用另一种类型实例化。接口仅实现一次,没有任何理由可以由其他任何类实现,等等。我认为这些事情是不必要的,应该删除,这基本上是YAGNI原则。

因此,应该有一个可以发现代码重复的工具,但是我认为问题类似于找到最佳压缩,这是无法确定的Kolmogorov复杂性问题。但另一方面,根据引用的数量,很容易发现未使用和使用不足的抽象:可以自动进行检查。


0

这都是主观的,基于代码本身的任何度量最终都是无关紧要的。最后,这取决于您满足需求的能力。您是否仍可以提供所请求的功能?如果可以,由于某些事情还不太正确,这些更改将多久返回给您?这些问题有多严重?

我只是(重新)定义了可维护性,但是它仍然是主观的。另一方面,这可能没什么大不了的。我们只需要让客户满意并享受它,这就是我们的目标。

显然,您认为您必须向老板或同事证明,需要做一些事情来改善代码库的状态。我认为足以让您感到沮丧的是,对于每一个小事情,您都必须更改或添加,您必须修复或解决可以避免的其他10个问题。然后命名一个臭名昭著的地区,并提出理由将其上下颠倒。如果那没有在您的团队中获得任何支持,那么您在其他地方可能会更好。如果您周围的人不在乎,证明您的观点也不会改变他们的想法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.