《JavaScript专家编程》——9.4 度量JavaScript代码质量

9.4 度量JavaScript代码质量

为了让计算精度上升到最高,客观质量分析以程序化的方式对代码进行分析。这项任务可以使用编程工具完成,这些工具能够在多种情况下评估代码,根据各项指标得到最终的质量得分。本节介绍了静态代码分析,这种方法非常适合评估JavaScript的质量。

静态代码分析
静态代码分析就是不通过运行代码来分析代码的过程。静态分析看起来非常像一个文本编辑器的拼写检查器。拼写检查器扫描文档的正文来寻找错误和含糊之处,而并不需要了解文本的意义。同时,静态代码分析从功能上分析源代码的正确性,而不必知道它做什么。虽然JavaScript是一个非常动态的语言,但是它非常适合静态分析,因为它不会被编译成另一种形式。本节将评估JavaScript中静态分析的两种方法,其中包括语法验证器和使用复杂的工具进行分析。

1.语法验证
在JavaScript中,语法验证可以采用两种方式。第一种方法是使用linter如JSLint3或JSHint4,它们不仅会检查代码的功能正确性,而且还能在程序不能符合最佳实践时给一些提示。下面我们来看一看这段质量有疑问的代码:

我用的是JSHint,你可以npm模块的方式来安装(在你的系统上可能需要sudo,取决于你的用户权限):

安装好后,你可以通过在终端的命令行运行linter对来源文件进行验证:

JSHint将报告这些警告:

可以看到,linter只有在缺少分号和发生重复键的时候才会通知你。就个人而言,我认为event=event赋值的意义也值得一提,但它在技术上并没有什么不对。这种模糊性说明了linter的观点驱动方法,它验证的不仅是语法,也是你的做法。

对于那些对识别所谓的坏味道的代码不感兴趣的人来说,可以使用一个简单的独立的ECMAScript语法分析器,比如Esprima5,它只会识别出无效的代码。Esprima可以使用npm模块来安装:

与JSHint类似,可以通过终端的命令行来验证代码:

验证完成后,Esprima应该会在终端窗口中输出类似下面的内容:

Linter和解析器都是优秀的可用来建立代码质量基线的工具。许多这样的工具可以而且应该被整合到更大的开发工作流程中。它们在提高代码美感、努力和达到质量指标的能力方面来说都很关键。然而,在大多数情况下,对于确保代码的质量来说,简单的语法检查是不够的。下一节将探讨有助于减轻代码库的复杂性蠕变的工具。

2.复杂性
当Antoine de Saint-Exupery​说“完美的实现,不是说没有更多的功能需要增加,而是没有任何可以删除的代码”时,他这是在谈论代码质量。代码质量不仅从形式上来看是正确的,而且在概念上来说也是明确的,并且在向读者说明需求的问题是如何被解决时,它是有表现力的。不幸的是,有很多原因可以让简洁的代码陷入操作数和运算符的泥潭。团队可能会变,功能可能增加或减少,利益相关者的目标可能变动;而当程序员们的在承受很大压力的情况下保持工作的时候,所有这些事情都会发生。

任何编过程序的人都知道“代码是我们的敌人6”。开发中的一个简单事实就是,随着代码量的增加,质量会随之下降。代码是语法结构上的脂肪:添加往往比删除容易得多。所谓的代码膨胀,导致了程序的复杂性,因为对程序员来说需要阅读、理解和维护更多的源代码。聪明的程序员通过利用设计模式和应用程序框架来对抗的复杂性。他们拥抱开发方法论通过一致的编程方法来试图降低复杂性。

除了这些方法,复杂度也可以使用查找复杂代码的质量指标来编程式地度量。本节探讨复杂的JavaScript被识别、隔离和最终从程序中删除的方式。

3.通过代码度量评估代码复杂性
运行时引擎在JavaScript中是最复杂的。它可能是bug缠身、低效或不完整,但如它般复杂的程序是一个人类难题。因此,代码复杂度是对程序员要完全理解代码而必须承受的脑力劳动的度量。

过了数年之后,程序员们开发了度量复杂性的指标。这些指标可以找出源代码中的缺陷,而这些缺陷往往会导致复杂代码的产生。其中有些指标是经验观察的结果,而其他的则和程序员如何看待代码算法的解释有关。其他程序员已经开始把这些指标引入到工具中来定期扫描程序,以努力帮助开发人员了解,哪些代码需要重构或额外的测试。

本节将演示一些精选的非常适合JavaScript的复杂性度量指标,以及一些可以自动控制质量的工具集合。

(1)过多的注释
复杂代码的一个明显结果就是,对于读者来说,源代码不再能自解释。通常来说,注释会用于让未来​​的程序员了解以前的开发人员的做法。出于这个原因,注释可以说是一个引人注目的复杂度度量方式,因为注释意味着还有工作尚未完成,或者可以改进。

(2)代码行数
就像过多的注释指标一样,计算代码行数也具有直观意义。当一个函数开始扩展时,开发人员误解代码实现的一些细微差别的可能性也在增加。代码行数可以通过各种不同的方式度量,包括Lines of Code(LOC),Source Lines of Code(SLOC),或者Non-Commented Source Lines(NCSL)。

当使用LOC指标度量时,应确保所分析的粒度级别是正确的。例如,将一个函数重构为三个函数可能会增加LOC指标,但在现实中这将会减少源代码的整体复杂性。出于这样的原因,开发人员有时会认为LOC是一个非常傻的指标。当我评估JavaScript代码的时候,我发现一个LOC指标可以在函数级别度量得很好,因为长函数通常是不必要的复杂性的标志。

(3)耦合
如果一个对象很明显地需要另一个对象的实现才能工作,依赖对象就会被称为是紧密地耦合到了另外一个对象。这种耦合应该尽可能避免,因为它导致源代码整体变得脆弱。此外,它还意味着,信息隐藏失败了,并且具体实现逻辑已经被暴露到更大的代码库中了。

当静态分析JavaScript中的紧耦合时,可以计算用于访问一个对象链的属性时所用到的点的数量。如果可能的话,你应该把调用链保持在三个点或更少。举个例子:

(4)函数的变量
有太多局部变量的JavaScript函数可能​​表明函数有待改善,无论是通过关注点分离还是将变量集合起来作为一个共同的对象。看看下面的例子:

race函数处理的不仅仅是模拟比赛,因此在函数体中充斥了很多局部变量。你可以通过下面的关注点分离来将变量数目由7减少至2:

(5)函数参数
函数的参数过多可以导致函数太过复杂,但究竟多少个参数才合适,没有硬性的规定。然而,在传递一箩筐的参数到一个函数中时,就可能是函数意图混乱的迹象。在某些情况下,可以通过将相关参数有逻辑地组织到一起来减少读者需要记住的参数数量。也可以将它们组合成一个对象提供给函数:

(6)嵌套的深度
代码嵌套得越深就越复杂越难测试。函数的嵌套深度可以用不同的方式来测量。例如,下面的每个函数都有四个嵌套深度:

这可能看起来不太对,第二个函数对于isRGBA的实现和第一个函数的实现具有相同的嵌套深度;毕竟,第二个函数只有一个if语句。然而,使用逻辑运算符(&&)是用来嵌套条件逻辑的,所以对于读者来说,它们必须解开。一个含有四层或四层以上嵌套深度的函数应该引起重新思考。

(7)圈复杂度
圈复杂度有着一个奇妙复杂并冠冕堂皇的名子。每次我大声把它说出来的时候,我都觉得我更聪明了。你可以尝试一下,你应该会明白我的意思。幸运的是,度量背后的概念比它的名字更容易理解。圈复杂度是由Tomas McCabe(McCabe,1976)提出来的,它是判断一个函数内复杂度的一种手段。他断言,一个函数的复杂度增加的比例,来源于其内部发生的控制流决策的数量。

这种度量方法以下面两种方式产生一个复杂度指数:

  • 它可以计算一个函数中的所有决策点,每个加一。
  • 它可以将函数作为一个控制流图(G)7,从边的数目(e)中减去所有顶点数(n)以及加上连接部件的平方(p);例如:

基本示例

为了更好地理解这一度量方式,让我们来看个实际的例子。在下面的例子中,我写了一个假想的路由器页面,代码还有待重构。在努力使代码变得更加清晰的过程中,我在函数的每个决策点上都增加了复杂度分数。另外,分数初始值为1,而不是最后加1。

这个函数的复杂度分数为8,McCabe认为这已经是非常复杂了。理想情况下,McCabe认为函数的复杂度分数应该是4或小于4。8的高分表明,这个函数做了太多事情。一个圈复杂度的分数可以告诉你更重要的是这个函数需要重构了;McCabe认为对于每个循环点都应该有一个测试。这样做才能确保所有可能的决策路径都会被覆盖到。由于分数越低越好,所以任何分数为10或更高的函数都增加了bug潜伏在某处的可能性。

局限性

在圈度量中有一个盲点,就是它只关注控制流,并将其作为函数复杂性的唯一来源。任何花时间阅读过代码的程序员都知道,复杂性不仅仅来自控制流。例如,下面这两个表达式有相同的圈复杂度分数,尽管很明显其中一个更难理解:

另外,使用McCabe的推理,一个单片机程序,无论多长,都没有单个if语句的程序复杂。这对于开发人员来说似乎与现实不太一样。这并不是说这个指标没有价值:它的工作原理非常好,就如一个在代码煤矿中的金丝雀,可以作为函数内部对可能潜在问题的预警。考虑一种除控制流外的指标来度量复杂性是非常值得的。对于这一点,你需要研究一下NPATH。

(8)NPATH复杂度
Brain Nejmeh创造了NPATH复杂度,它在函数或单元级别分析代码质量。Nejmeh觉得在软件质量中得到的最大收获来自单元级别,因为它们可以和其余源代码相互隔离,因此提供了一种客观度量复杂度的有效手段。根据Nejmeh的说法:

NPATH,通过一个函数计算非循环的执行路径,是一种客观的软件复杂度度量方式,辅助软件进行全面测试(Nejmeh,1988)。

计算非循环执行路径是说这个指标汇总了一个函数可以执行的所有方式。NPATH使用这种计算路径个数的方法为函数得出一个最终的复杂度得分。这种方法类似于McCabe的圈复杂度度量的工作方式。两者之间的区别是圈复杂度计算的是控制流决策的个数,而NPATH计算所有可能的路径。Nejmeh认为NPATH的非循环计数方式是对McCabe方法的改进。具体而言,Nejmeh认为McCabe的指标不能度量一个函数的全部复杂度,原因如下。

  • 圈复杂度计数方式不能通过一个线性函数正确地计算非循环路径的不同数量,这是与指数函数截然不同的。
  • 圈复杂度计算方式以同样的方式对待所有的控制流机制。Nejmeh则认为,一些结构在本质上是很难理解和正确使用的。
  • McCabe的方法并没有考虑为一个函数内嵌套的层数。比如,三个连续的if语句与三个嵌套的if语句会得到相同的得分。而Nejmeh认为,对于一个程序员来说,后者更难理解,所以应该更复杂。

基本示例

为了更好地理解NPATH如何计算一个JavaScript函数的复杂度指数,来看下面的例子。如前所述,NPATH使用不同的分值来计算各种控制流机制。为帮助理解,我在每个流程控制语句上以注释的形式加上了得分。


 所有的NPATH表达式计算了NP[(expr)]并得到了0分。NPATH通过计算逻辑运算符(&&,| |)的数量来决定表达式的分数。这是因为,逻辑运算可以对可能的控制流路数产生复杂的分支影响。
局限性

正如我在前面所讨论的,复杂度的量化对程序员而不是对运行引擎有利。因此,这些指标其实是基于创造者自己对于复杂度的定义。在NPATH的方法中,Nejmeh认为一些控制流语句本身就比其他的语句更容易理解。例如,当你使用一个switch语句和两个case的时候,你会得到一个比使用两个连续if语句更低的分数。虽然两个if语句可能需要更多的代码行,但我不认为它们从本质来上更难理解。这就是不要盲目套用复杂度度量指标,而应该花时间去了解整个代码功能的非常重要的原因。我们再来看看另外一个关于复杂度的观点,Halstead指标。

(9)Halstead指标
20世纪70年代末,计算机程序以单个文件的形式进行编写,随着时间的推移,这些程序由于其整体结构而变得越来越难以维护和增强。为了努力改善这些程序的质量,Maurice Halstead制定了一系列的量化措施来判断一个程序源代码的复杂性(Halstead,1977)。随着Halstead指标渐渐被人们所熟知,它被认为是“最早的软件度量指标,[并且]是复杂度的一个重要指标”8。

Halstead间接加强了关于度量质量和复杂度只能由精通程序和语言两个领域的专家才能做的普遍说法。然而,Halstead的说法是“软件应该在不同语言中反映算法的实现或表达,但应该独立于所执行的特定平台上,所以这些指标是从代码中静态地计算出来的”9。为了度量复杂度,Halstead指标追踪那些在给定算法的服务中运算符和操作数的使用情况。

自Halstead指标出现40年来,开发人员已经用许多不同的语言实现了这个指标,其中就包括JavaScript。虽然这些度量方式以及与人类认知相关的基本假设并非没有批评者,但是单独考虑每个指标以及它们如何为JavaScript代码计算分数的过程还是很有益的。通过了解这些指标的工作原理,你在评估代码方面能够扩展自己的思维框架,而且至少能够对使用这些指标如何来对JavaScript的一个单元计算得分以及为什么会有这样的得分有一个较好的把握。

输入

Halstead指标计算函数中使用到的运算符和操作数,并将其作为多种度量的输入。然而,在收集这些输入之前,你需要考虑一下Halstead指标中提到的操作数和运算符在JavaScript中指的是什么。

在JavaScript中操作数是一个语句中会被执行的包含对象或表达式的部分。JavaScript有多种在操作数上进行操作的多种形式的运算符10。下面是一个简单的例子:

为了能清楚而详细地看到运算符和操作数,你可以使用Esprima JavaScript分析器将语句提取转换成语法树11:

有了这个语法树,你可以计算唯一的操作数(3)和运算符(2)的数量。就本章而言,我用这个简单的语句作为在Halstead指标中计算的基础。现在有了JavaScript中操作数和运算符的工作定义,你可以得出Halstead指标的输入,正如下面这样:

  • n1 = 唯一运算符的数量;
  • n2 = 唯一操作数的数量;
  • N1 = 总运算符的数量;
  • N2 = 总操作数的数量。

从语法树中计算运算符和操作数的数量,能得到下面的值:

在得到这些输入值后,你可以把它们放到不同的指标中来计算分数。Halstead指标之所以非常灵活的原因在于,它们的定量性质意味着它们可以很好地应用到整个源文件或者单一的函数中。事实上,在同一段程序上使用不同分辨率的Halstead指标可以得到有趣的结果,这值得思考。就本节而言,如果你打算将其应用在函数级别上,我将会解释这些指标。

程序长度(N)

程序长度即将操作数和运算符的总数合在一起(N1 + N2)。这个数值较大表示该函数可以受益于分解为更小的组件。你可以用下面这种方式来表示程序长度:

词汇量(n)

词汇量的大小通过将唯一的运算符和操作数加在一起(n1 + n2)来计算。正如程序长度的指标一样,较大的数字表示这个函数可能做了太多的事情。你可以用下面的表达式来表示词汇量的大小:

程序体积(V)

如果你的大脑是一个玻璃罐子,一个程序的体积描述了这个容器占用了多大的空间。它描述了读者为了完全了解函数而必须从心理上解析的代码量。程序体积考虑的是总数或者一个函数内在操作数上执行的操作的数量。所以,不管函数有没有压缩,它都将得到相同的分数。这对于其他与源代码行数(source lines of code,SLOC)相关的复杂性度量指标来说并不成立。程序的体积通过将程序的长度(N)与以2为基数的词汇量的大小(n)的对数来计算。在JavaScript中你可以写成这样:

体积(Volume)在这个度量方法中是一个令人回味的名字,因为它可以有多种含义。之前,我谈到过体积可以视为取代其他智力资源的无形物质,但你也可以把它作为一个声音指标的信号。就像在真实世界中,当音量被设定在一个特定的范围内的时候,信息才能最佳地传输。想象一下,假如你正在听收音机;当音量旋钮设置过低时,你必须竭尽全力才能听到。然而,当转动旋钮至11,输出音量太大的时候,你对它理解也将受到影响。

程序级别(L)

程序级别定义了一个方法的相对复杂性。它通过一个潜在的体积(V1)除以实际体积(V)来得到感知能力的水平。一个函数的潜在体积被定义为,如果它以最为理想的实现方式来书写时所占用的体积。程序级别可以表示如下:

因此,如果这个值越接近1,表示实现方法越接近理想。


 潜在体积在每种语言中都不相同。高级语言的得分比低级语言的得分要好得多,这是因为高级语言从程序源代码中对复杂的东西抽象过。
难度级别(D)

难度级别用来度量读者误解源代码的可能性。难度级别是由唯一运算符数目的一半乘以操作数总数与唯一操作数的数目的商来计算的。在JavaScript中是这样写的:

如果你认为随着程序体积的增大,需要理解的难度也会增大,那么你就可以很直观地理解这个指标的计算。当操作数和运算符被重用的时候,它们增加了在许多控制流途径中引入错误的可能性。

编程花费的精力(E)

这一指标估计的是一个合格的程序员,基于一个函数体积和困难的分数,对理解、使用和改进这个函数所花费的精力。因此,编程花费的精力可表示如下:

毫不奇怪,正如体积和难度一样,我们希望花费的精力较低。

代码实现的所需时间(T)

这项指标估计的是一个合格的程序员实现一个给定的函数所需的时间。Halstead通过编程花费的精力除以一个Stroud数来计算这个指标12。Stroud数是一个人一秒钟能做的基本(二进制)决定的数量。Stroud数量并不从程序源代码中计算而来,它可以通过比较期望的结果和实际结果来不断地进行校准。代码实现的所需时间可以这样表示:


 有效的Stroud数的范围是从5到25,其中25是一个人可以在每计量单位内做出的最大简单决定的数量。Halstead确定18能很好地替代一个合格程序员的性能。
Bug的数量(B)

这项指标估算的是给定的程序中已经存在的软件缺陷的数量。正如你所期望的,bug的数量和程序的复杂性(量)强烈相关,但是能够通过程序员自己的技术水平(E1)得到缓解。Halstead在自己的研究中发现,在3000至3200的范围内可以找到足够的E1值。可以使用下面的表达式来估计bug的数量:

局限性

虽然Halstead指标提供了非常丰富的信息,但是仍有人质疑它们的可靠程度以及表面上看起来的有用程度。有些人如Lou Marco则批评了这个评分系统的模糊性以及它如何应用的不确定性。Marco指出,Halstead没有在这个问题上提供明确的方向:

Halstead认为,程序的级别越低,程序就越复杂。但不幸的是,他并没有更进一步的阐述。程序级别为.100的程序算是复杂的吗?级别为.005的呢?所有你能做的就是比较同一程序的不同版​​本,比较它们的程序级别。回想一下,McCabe指标给出了复杂度为10的上限。

Halstead指标对于冒泡排序的计算表明,冒泡排序的实现是非常复杂的。问题是,对于潜在体积的计算需要输入和输出参数的数量。对于冒泡排序,只有待排序的数组是必要的。潜在体积的小数值倾斜了程序和语言的级别。大多数程序员都会同意,这个算法并不复杂(Marco,1997)。

4.工具
客观质量分析的主要目标是创建一系列程序化的措施,可以使用一个一致而又可重复的过程按需计算复杂度的得分。这些指标的程序性意味着它们是列入程序化工具的主要候选者。毫不奇怪,有一些专门做这个的项目。本节会比较为JavaScript提供的两个复杂度分析程序。

(1)复杂度报表
Phil Booth的复杂度报表(complex-report)是一个简单的命令行工具13,用于分析任意JavaScript文件,然后生成一个复杂度报表。复杂度由以下指标来确定:

  • 代码行数;
  • 每个函数的参数;
  • 圈复杂度;
  • Halstead指标;
  • 可维护性指数。
    由于它是一个命令行工具,因此部署工程师可以轻松地将其添加到他们的持续集成工作流中。你可以配置当源文件的的质量低于任意一个阈值时,拒绝代码部署。

基本示例

要了解这个库是如何工作的,你需要先安装它的npm模块:

为了测试复杂度报表的输出,你可以用它测试自己的某个源文件,我们亲切地称其为“吃你自己的狗食”。在命令行中,输入以下代码:


 你可能需要更改目录到你本地复杂度报表节点模块所在的路径。
一旦完成之后,你应该能够看到终端窗口上的打印结果。报表首先计算了整个文件的复杂度得分,然后分别计算了每个函数的复杂度。下面是整个报告的摘录:

这个复杂度报告是非常有用的,因为它不仅可以自动化手工计算源代码得分的苦差事,而且还能在文件和函数级别进行分析。这为开发者提供了一种机制去评估代码变化对最终得分的影响。虽然这个库提供的报告信息很丰富,但对于不懂技术的项目相关人员就不容易看懂了。幸运的是,有一些为这个目的而设计的其他工具。

(2)柏拉图
Jarrod Overson的柏拉图(Plato)是一个代码质量分析仪表盘14,它既好看又包含很多的信息。Plato使用JSHint和complexity-report来做实际的分析,然后将它们的原始报告转换成信息图表和图形的集合体。正如任何好的可视化套件一样,Plato知道当数据在不同的上下文中时,可以被理解为不同的意思。出于这个原因,Plato将原始分数改成各种信息空间,这就是我接下来要讨论的东西。就本节而言,我将使用一个在Grunt项目上的Plato报告截图15。

项目质量时间线

Plato的第一个报告截图是项目质量的时间线(如图9-1 所示)。它提供了一个项目在综合质量方面变化的柱点图。

不像其他那些仅仅给你一个在任意给定时间内的快照的质量报告,Plato的报告视图,绘制了项目质量随着时间发生的变化。这是非常重要的,因为它能让开发人员或经理看到质量变化的趋势。

项目度量视图

下面的程序报告中,Plato显示了一系列的柱状图的集合,如图9-2 所示。这些图展示了各种常见测试的度量指标的得分:“可维护性”,“代码行数”,“估计错误”,以及“lint错误”。使用此视图,用户在选择查看某一个详细内容之前,可以从整体上直观地评价文件。

文件质量概览图

最后综合图表列出了每个文件的各项指标分数,如图9-3 所示。指标视图中允许根据文件的相对性能来进行排序;文件质量图给你一个全面的理解,使你了解其中哪些文件是在所有指标中最有问题的。

Plato总结视图快速识别出代码库中有问题的全局区域。然后,你可以深入检查任意文件。文件视图使用数据源提供的相同的原始数据,并设置了在文件级别上有意义的作用域,我接下来会解释。

文件质量时间线

文件的质量时间线图展示了给定文件随着时间的推移在质量上的变化,如图9-4 所示。这个图和项目时间线图非常相似。Overson已经明智地决定,只在时间线中展示可维护性和LaOC指标。他描述了这样做的难度以及估计作为单值的错误指标。然而,对于时间序列的程序来说,这也将包含更多的信息。

函数质量

一旦Plato建立了全局的文件质量,文件级报告的其余部分就专门由函数级的分析来完成。Plato将一个文件的所有函数描述为一对圆环图(参见图9-5 )。环上每块颜色都代表每个函数的不同分数。选择圆环图是明智的,因为一个文件在其所有函数的数量上有很大差异。然而,从信息密度来看,这些图是这些图中最差的。

当用户选择圆环上的某一区块时,另外一个圆环中对应的片段也会被选中。在圆环上选择多个区块,能够得到复杂性和LOC之间的明确关系。然而,其实使用两个图表甚至没有必要。这两个指标都可以很轻松地在一个圆环中展示,可以用区块的大小来表示LOC的值,用颜色来表示复杂度。更成问题的选择是使图表变成单色。除非你知道,比如,一个大的复杂度的分数不是我们想要的,你将很难单独通过Plato的色彩选择上来得到这个结论。一个更好的方法是在概览图中重新引入红、橙、蓝三种颜色。这些颜色能清楚地界定哪些分数是可取的,哪些不是。更重要的是,Plato已经教会用户来了解这些颜色的意思,所以如果不使用它们就成了一种浪费。

源代码图

Plato的最后一个图算不上是一个图,而是程序源代码的注解图(参见图9-6 )。用户可以手动滚动到某块代码,也可以点击函数质量圆环图的任何区块。单击某个区块可以瞬间跳到函数在源代码中出现的位置。通过单击函数的名字,用户可以看到它得到的各种指标的分数。将分数直接显示在源文件中,给用户提供了一个在更大源码范围内思考当前分数的机会。

Plato是一个用于探索特定代码库的质量指标的神话般的工具。它做了所有好的可视化工具所做的,能够让用户对于数据有更深的了解。Plato通过允许用户在不同规模和许多上下文中思考同样的分数实现了这一点。这对于在代码库质量方并不擅长的非技术人员来说特别有用。对于这个人群,Plato提供了一种方式,使他们不需要去了解程序的具体实现,就能与程序员进行关于质量的谈话。

时间: 2024-10-31 03:57:46

《JavaScript专家编程》——9.4 度量JavaScript代码质量的相关文章

《JavaScript专家编程》——第9章 代码质量 9.1 定义代码质量

第9章 代码质量 质量不是一种行为,而是一种习惯. --Aristotle 写高质量的JavaScript是什么意思?质量能度量吗?还是说它是一个主观感受,类似于美和艺术的柏拉图式的理想?程序员往往会在质量的主观和客观理解之间摇摆不定.他们提出了诸如软件工艺的概念,这是一种用类似手工艺的方法来编写软件的方式.软件工匠常被这样描述:他们拥有超群的技术,总是能将工作提炼为基本的.本质的部件.这样一个工匠在电气上被称为摇滚明星程序员.这基于两个标准,一是这个人具有如同艺术家一样的独特天赋,二是他工作的

《JavaScript专家编程》——9.3 为什么要度量代码质量

9.3 为什么要度量代码质量 "我不能为代码质量而索价."这是我问我的朋友关于这个问题的想法时,他的原话.他的意思是,代码质量主要是对程序员有利,而对客户来说是一种无形的税收.我能理解他的观点:我有几次经验,其中一个潜在客户将目光投向了我引以为傲的有关测试的方法论上.我的朋友接着说,"客户支付的是结果,而不是过程.当我买票到西南部,我付的钱是为了到达我的目的地,而不是为了乘坐飞机."这句话听起来好像有点道理,但我会在这一节讨论度量代码质量并不会让你失去竞争优势, 而

《JavaScript专家编程》——9.5 小结

9.5 小结 本章介绍了JavaScript代码质量的必要性及其原因.一个程序的质量往往会影响程序员维护.改进甚至是否有能力完全了解源代码.质量差的代码通常被称为技术债,剥夺了项目的时间和资源,而这些时间和资源用在其他地方能更好地发挥作用.然而,编程往往是一门跨越了艺术和科学之间的学科,这使得对质量的定义变的更为复杂.而且,质量又是从主观和客观上的双重度量. 有这样一种观点认为,一个人所在时代的文化,以及他们的个人经历都会对质量产生影响.这种观点将质量描述为具有"内在卓越"的东西,只有

《JavaScript专家编程》——导读

**前言**在我看来,好的技术书籍是磁带.藏宝图和现场札记内容的混合体.本书就是我灌注了很多心血而将这些不同形式融为一体的一本书. 老一辈的人还记得,磁带内容是由很多歌曲组成的.这些磁带经常被作为礼物送给朋友.恋人.人们会挑选一些个人喜欢的歌,或者围绕某个主题组织在一起的歌,录入这盘磁带中.通常,当听磁带的人听到这些歌时,这些歌就会勾起人们对录制者的记忆.这本书就是一盘我录给你们的JavaScript方面的磁带.这些章节包括JavaScript中我喜欢的一些方面,也包括不容易被理解的主题,因为这

《JavaScript专家编程》——9.2 如何度量质量

9.2 如何度量质量 你正在为质量寻找一个可用的定义,但因为它们涉及到编程,所以需要首先考虑它的各个方面.通常会将这些方面表示为软件度量: 软件度量是一个软件在某些属性或其规格上的度量.由于定量度量在所有科学中都是必不可少的,因此计算机科学从业者和理论家通过不断努力,将类似的方法引入软件开发中.我们的目标是获得客观的.可重复的和可量化的度量,这可能包含很多有价值的实践,包括进度规划.预算规划.成本估算.质量保证测试.软件调试.软件性能优化以及人员任务分配优化. 我已经努力总结出六个指标,来度量代

《JavaScript专家编程》——1.2 对象概述

1.2 对象概述 JavaScript是由Brendan Eich创建的一种面向对象编程(OOP)语言,当时他还在Netscape公司工作,花了几周的开发时间就发布了.虽然JavaScript的名字中有个"Java",但它实际上跟Java语言没什么关系.在InfoWorld的一篇对Eich的采访稿中,他解释了JavaScript命名的由来: InfoWorld:据我所知,JavaScript开始的时候叫Mocha,后来改名叫LiveScript,在 Netscape和Sun合并以后才叫

《JavaScript专家编程》——1.3 小结

1.3 小结 对象是持有零个或多个属性的包. 对象的属性要么是基本类型,要么是复杂类型.对象可以持有它们自己的基本类型的拷贝,但仅能持有复杂类型的引用.出于这个原因,JavaScript的属性要么传引用,要么传值. 对象的属性可以有标记符,可以在修改对象时,控制对象的行为和能力. 对象可以通过以下三种方式之一创建. 使用字面量语法'{}'. 联合使用new运算符和构造函数,例如'new Foo()'. 使用内置的Object.create()函数. JavaScript是一种基于原型的语言,对象

《JavaScript专家编程》——第1章 对象和原型 1.1鸟瞰JavaScript

第1章 对象和原型 练习不会造就完美,只有使用最佳的方法来练习才能造就完美. --Vince Lombardi 对专家来说,把JavaScript的核心概念讲上3章似乎有点多,毕竟这些是语言最基本的组成部分.我的主张是,有的人虽然不能读写,但可以说话.就像有的开发人员对JavaScript的基本功能很熟悉,但对里面那些复杂的东西可能就没那么了解了. 本书的目标是像明灯一样照亮语言中那些晦涩的角落.里面包含的很多概念你可能已经试着学习过了,甚至可以假设你已经理解了.这里可以想象一下:你正降落到你大

JavaScript最佳实践:帮你提升代码质量

每天学一些新东西可以让一个理性之人走上不凡之路.而作为开发人员,不断的学习新东西则是我们工作的一部分, 不论这些新东西是不是来源于积极的学习经验. 在本篇教程中,我将指出一些重要的 JavaScript 最佳实践,让你不必去用另外一种艰难的方式来了解它们.准备好去升级你的代码吧! 1. 避免对全局作用域的污染 声明变量是一件很有趣的事情.有时候即使你不想这样做,但也有可能会定义出全局变量.在如今的浏览器中,全局变量都被存储在 window 对象中.而因为有许多的东西都在那个里面,所以你有可能把一