自由行

2009-12-06

软件度量-面向对象的软件

Filed under: SoftWare Development, Software Engineering — Tags: , , — thomas @ 13:00

新范围,老问题

在之前的软件度量的讨论中,我们了解了SLOC的有一些优点,也有很多问题。那么在采用面向对象的程序设计语言的项目中,我们应该如何来衡量软件的大小呢?SLOC是能作为面向对象软件的度量呢?下面就笔者的项目经历来讨论这个问题。
说 到度量,笔者想起来一个有趣的例子,就是建筑中来如何衡量建筑项目的大小。在钢筋混凝土结构出现之前,是砖结构的,瓦匠们经常会说,我盖的房子用了多少 砖。砖作为建筑物的基本单元,砖的数目反映建筑的大小是比较直观的,所以这个尺度也很普遍。要想在理论上探讨软件度量,我们有必要对软件的结构进行分析, 找出结构上的规律,包括结构与开发代价之间的关系。这样对于我们评估开发代价,掌握项目的发展变化,提供重要的参考。

软件结构分析

作为面向对象的软件,什么是基本单元呢?当然是类。类本身不能执行,在程序中运行的只能是类的实例,但是类确实源代码的组织形式和结构单元。那么我们是否能用类、类的实例的数量来衡量软件的大小呢?
当然是可以的。

类、成员变量、成员函数

首先作为基本的结构单元,类包含了成员变量和成员函数,成员变量的类型和数目决定了实例的在内存中大小;成员函数的数目能反映运算的规模。作为程序而言,无非就是在内存中数据和能够完成的特定运算的指令的集合。一般而言,程序功能越丰富,需要的类的数量,类的大小都增加。

全局变量、全局函数

尽管在在面向对象设计中,代码主要是类和对象,但是大多数面向对象的程序设计语言也支持全局变量、全局函数。从语用的角度,对于程序级别的数据存储使用全局变量是很方便的。
工 具函数,比如用来dump或者log的函数,使用工具函数有几种方式来处理。一是封装成工具类,工具函数作为静态函数;二是直接声明为全局函数,供其它模 块直接调用。从编译器处理的实质来看,是一样的。不过在工具类中可以实现丰富的访问控制。笔者个人不反对使用全局函数,因为这样比较简单。
在笔者经历过的项目和笔者自己开发的程序中,也使用了一些全局变量、全局函数。在度量软件大小时,我们也需要考虑全局变量和函数的数目。

实例分析

目 前的大多数IDE都能很好的支持对类的解析,这样我们能容易比较两个不同项目的类的数目。不过对于总的成员变量的数目和成员函数的数目,就不是那么直观 了。笔者个人发现Source Insight在Project Report方面,提供的统计比较全面。下面以一个将比较两个软件,他们都是某一Symbian手机上Camera软件。前者是笔者参与的项目,后者是笔 者为精益软件开发实践项目。其中选择这个项目也考虑到:软件功能相同,设计和实现不同,这样容易发现规律。
注意:成员变量、成员函数在不同的面向 对象设计的方法学,叫法不同。下面的数据由Source Insight v3.50产生,其中类、成员变量和成员函数分别对应表中的Classes、Structure Members和Methods。而Varibles指的是全局变量,Functions指的是全局函数。

项目名称 Camera XqCap4
NameSpaces 2 0
Classes
230
102
Structures 14 2
Type Definitions 8 2
Enumerations 92 16
Constants 348 89
Enum Constants 619 92
Variables 277
44
Functions
45
72
Methods
2383
1024
Macros 42 28
Function Prototypes 159 82
Method Prototypes 2508 1041
Structure Members
1248
386
Custom Tags 4 4

由于时间的关系,XqCap4并没有全部完成,有一些功能和特征没有实现,粗略评估是差30%左右,所以对于重要数据的比值,将按1.3纠正。
类数:230 / (102 * 1.3)= 1.74
成员变量数:1248 / (386 * 1.3) = 2.49
成员函数数:2383 / (1024 * 1.3) = 1.79
全局变量:277 / (44 * 1.3)= 4.84
全局函数:45 / (72 * 1.3)= 0.48
按相同权重,计算平均值 (1.74 + 2.49 + 1.79 + 4.84 + 0.48)/ 5 = 2.196
那么我们对于两个项目之间的大小就有了较直观的认识。前者要比后者大1倍左右。因为笔者对两个项目都比较了解,后面我们将对两者的主要特点对比分析,解释软件大小相关的因素。

模块

在这里,我们仍然对SLOC进行了统计。(注:以下数据来自于Practiline Source Code Line Counter)

项目名称 Camera XqCap4
File Count 337 167
Max Line Count 1984 1547
Total Lines 87631 23428
Nominal Lines 87631 23428
Source Code Lines 51719
17988
Source Code Lines (%) 59.02% 76.78%
Comment Lines
19559
1363
Comment Lines (%) 22.32% 5.82%
Blank Lines 14444
3810
Blank Lines (%) 16.48% 16.26%
Mixed Lines 1909 267
Mixed Lines (%) 2.18% 1.14%

在Source Code Lines上比值为:51719 / (17988 * 1.3) = 2.21,前者也差不多是后者的两倍。对于注释代码比率,前者达到了22.32%,前者的注释应该说是很丰富的,相比之下后者就少的可怜了。不过在后者中 使用了自文档化的编码方式,代码可读性非常好,而前者注释虽多,在类继承体系、类之间的关联方面,很难看懂。当然这也是笔者个人判断,需要研究者自己来评 判。对可读性的讨论,超出本片的范围。在空行率方面两者相差无几,可以推断:代码中小函数或者复合语句比较多,通常为了在视觉上容易分辨代码,往往在符合 语句,函数之间加空格加以间隔。

比较方法

在软件开发实践中,我们会发现对于不同的功能,代码的数目差异是巨大的。因为不同的功 能,涉及到算法、交互等方面的复杂可能相差好几个数量级。比如:编码与解码,通常编码比解码多很多倍。所以,功能点如果相同更容易发现软件大小的影响因 素。比如,不同的架构设计,使用不同的库和框架等等。
在这两个项目中,架构设计的都一些特点。

  • 都采取与配置/设置为中心的方式。前者用叫setting,后者叫config,同为CCoeStatic子类。但是后者只是中转类,即本身并不读取设置和更改设置,只做存储设置,设置的读取和更改放在专门的类;
  • 都采取了setting/configuration observer模式,但是前者只是用了几个observer。而具体的设置项的改变则有某一个控制器类派发,这样导致派发途径上经过的类都有相关的处理,是非繁琐。
  • 对于拍摄/录制,前者类继承体系复杂,后者拍摄和视频由独立的类负责,拍照和视频本身UI/实体类完全分离,功能相对封闭。在针对不同类型的拍摄,比如:Normal、Touch等拍摄模式时,使用了设计模式中的状态模式来解耦,效果很好。
上述这些不同,决定了类的数量,以及实现时代码的数量。这样说明:一个好的设计可以减少软件的尺寸,降低软件的复杂行,从而降低了软件的维护成本。

重构

对 代码的重构,主要是针对代码的结构的变化,对可维护性、可扩张性方面有直观的改善。不过笔者的经验表明,重构通常也能很好的减少软件的大小。比如通常我们 会为了提高函数的复用性而使用Extract method,因为复用度提高意味着冗余代码的减少,软件尺寸自然也就减少了。另外,把相似的派生类的方法提升到基类中,也是基于复用的原因而减少尺寸。 当然,并非所有的重构都会显著改善软件的大小。比如用状态模式取代类继承体系,它可能是把与状态有关的函数的实现代码,转移到状态类中,甚至方法数目会略 有增加。笔者建议读者不要计较软件大小方面的得失,坚定不移的重构已有代码,改善软件设计。

增量式开发

开 发者通常改动代码是因为增加新的功能,笔者个人的体会,增加功能前后软件大小的变化值得关注。如果功能很简单,但是软件尺寸变化很大,开发者有必要检查自 己的设计,肯定是什么地方很糟糕。当然更多的是,有一些地方是改变,同时也有一些成员变量、成员函数是新增加的。在规模比较大的软件中,常常会需要增加同 类型功能。比如增加一个设置,增加了一个类,50行代码;而再增加一个设置,增加了好几个类,数百行代码。这就提示设计上有差错了。

总而言之

影响的因素软件大小的变化是多方面的,软件大小一般不是约束条件,开发者不应该对此顾虑。开发者应该根据功能需要来编写代码,按照通过重构保持代码的灵活性,从而更容易修改、扩展。

2009-12-02

软件度量-SLOC

Filed under: SoftWare Development, Software Engineering — Tags: — thomas @ 21:39

软件度量-SLOC(源代码行数)

摘自:http://en.wikipedia.org/wiki/Source_lines_of_code
中英同步翻译,不足之处请各位指正。

Utility 功效
Advantages 优点
1. Scope for Automation of Counting: Since Line of Code is a physical entity; manual counting effort can be easily eliminated by automating the counting process. Small utilities may be developed for counting the LOC in a program. However, a code counting utility developed for a specific language cannot be used for other languages due to the syntactical and structural differences among languages. 1.自动统计行数的范围:因为代码行是一个物理实体;手工计算的代价能由自动统计处理来消除。可以在程序中开发一个一些小工具来统计LOC。然而,针对特定语言开发的代码统计工具并不能用于其它语言,因为语法和结构不同。
2. An Intuitive Metric: Line of Code serves as an intuitive metric for measuring the size of software due to the fact that it can be seen and the effect of it can be visualized. Function points are said to be more of an objective metric which cannot be imagined as being a physical entity, it exists only in the logical space. This way, LOC comes in handy to express the size of software among programmers with low levels of experience. 2.一个直观的度量:代码的函数作为一个直观的度量来衡量软件的大小,那是缘于这样的事实:LOC可以很明确并且它的效果能被可视化。因此,在经验水平低的程序员之间,LOC很顺手地表示软件的尺寸。
Disadvantages 缺点
1. Lack of Accountability: Lines of code measure suffers from some fundamental problems. Some think it isn’t useful to measure the productivity of a project using only results from the coding phase, which usually accounts for only 30% to 35% of the overall effort. 1.缺乏可说明性:LOC测量遭遇到一些基本的问题。一些观点认为它在测量项目的生产率上没有用处,就算是在编码阶段,该阶段只占总成本的30%~35%。
2. Lack of Cohesion with Functionality: Though experiments have repeatedly confirmed that effort is highly correlated with LOC, functionality is less well correlated with LOC. That is, skilled developers may be able to develop the same functionality with far less code, so one program with less LOC may exhibit more functionality than another similar program. In particular, LOC is a poor productivity measure of individuals, because a developer who develops only a few lines may still be more productive than a developer creating more lines of code. 2.缺乏对功能的内聚度:实验已经反复证明了代价与LOC高度相关,功能却不那么相关。那就是说,熟练的开发者可以用少很多的代码来实现统一的功能,所以 一个LOC更少的程序可以展示更多功能比其它的类似的程序。在特定情况下,对于个体来说,LOC是低劣的生产率测量,因为一个开发者只用仅仅少数行就可以 比写更多函数的开发者更有生产效率。
3. Adverse Impact on Estimation: Because of the fact presented under point (a), estimates based on lines of code can adversely go wrong, in all possibility. 3.对评估的负面影响:因为上述的揭示出的事实,基于LOC的评估可能反而走向错误,在所有的可能情形。
4. Developer¡¯s Experience: Implementation of a specific logic differs based on the level of experience of the developer. Hence, number of lines of code differs from person to person. An experienced developer may implement certain functionality in fewer lines of code than another developer of relatively less experience does, though they use the same language. 4.开发者的经验:特定逻辑的实现会因为开发者经验水平的不同而不同。因此,LOC的数目也因人而异。一个有经验的开发者可以用更少的LOC来实现一定的功能,而经验少的开发者用的LOC更多,尽管他们使用同样的语言。
5. Difference in Languages: Consider two applications that provide the same functionality (screens, reports, databases). One of the applications is written in C++ and the other application written in a language like COBOL. The number of function points would be exactly the same, but aspects of the application would be different. The lines of code needed to develop the application would certainly not be the same. As a consequence, the amount of effort required to develop the application would be different (hours per function point). Unlike Lines of Code, the number of Function Points will remain constant. 语言之间的差异:考虑两个应用程序提供同样的功能(屏幕,报告,数据库)。一个应用程序用C++来写而另一个用像COBOL一样的语言来写。它们的功能点 完全相同,但是应用程序的某些方面则不同。开发应用程序所需要LOC一定是不同的。作为结论,开发应用程序需要的代价的大小可以是不同(每个功能点的小时 数)。与LOC不同,功能点的数量是不变的。
6. Advent of GUI Tools: With the advent of GUI-based programming languages and tools such as Visual Basic, programmers can write relatively little code and achieve high levels of functionality. For example, instead of writing a program to create a window and draw a button, a user with a GUI tool can use drag-and-drop and other mouse operations to place components on a workspace. Code that is automatically generated by a GUI tool is not usually taken into consideration when using LOC methods of measurement. This results in variation between languages; the same task that can be done in a single line of code (or no code at all) in one language may require several lines of code in another. 6.GUI工具的出现:有了基于GUI的程序设计语言和像Visual Base这样的工具,程序员能写相对少量的代码就能达到高水平的功能。例如,不用写程序来创建窗口和绘制,GUI工具能用drag-and-drop的方 式和其它鼠标操作来把组件放到工作区中。由GUI工具自动生成的代码通常不在LOC测量方法的考虑之列。这一点在不同语言之间也不同,同样的任务,在一种 语言可以由一行代码(或者跟不用)来做,而在另一种语言中可能要几行。
7. Problems with Multiple Languages: In today¡¯s software scenario, software is often developed in more than one language. Very often, a number of languages are employed depending on the complexity and requirements. Tracking and reporting of productivity and defect rates poses a serious problem in this case since defects cannot be attributed to a particular language subsequent to integration of the system. Function Point stands out to be the best measure of size in this case. 7.多语言问题:在先进的软件情景中,软件通常由好几种语言开发。很多,使用哪些语言取决于复杂性和需求。在这种情况下,生产率和缺陷率的跟踪和报告提出 一个严肃的问题,因为缺陷不能归咎于系统集成后的特定的语言序列。在这种情况下,功能点显然是最好的软件尺寸的度量。
8. Lack of Counting Standards: There is no standard definition of what a line of code is. Do comments count? Are data declarations included? What happens if a statement extends over several lines? ¨C These are the questions that often arise. Though organizations like SEI and IEEE have published some guidelines in an attempt to standardize counting, it is difficult to put these into practice especially in the face of newer and newer languages being introduced every year. 8.缺乏统计的标准:在什么是一行代码的问题上并没有一个标准定义。把注释也统计吗?数据声明呢?如果一个语句太长了有好几行怎么办?这些问题经常出现。 尽管一些组织,如:SEI和IEEE颁布了几个指导书来试着统一LOC计数标准,在面对每年都有新之又新的语言出现的情况下,很难实际操作。
9. Psychology: A programmer whose productivity is being measured in lines of code will have an incentive to write unnecessarily verbose code. The more management is focusing on lines of code, the more incentive the programmer has to expand his code with unneeded complexity. This is undesirable since increased complexity can lead to increased cost of maintenance and increased effort required for bug fixing. 9.心理:如果程序员的生产率由LOC来衡量,将刺激他们写不需要的冗余代码。越是专注于LOC来管理,越是会刺激程序员用不必要的复杂性扩充代码。这是不期望的,因为增长的复杂性将导致维护成本增加并且bug修复的代价也会增加。
In the PBS documentary Triumph of the Nerds, Microsoft executive Steve Ballmer criticized the use of counting lines of code: 在PBS纪录片中“Triumph of the Nerds”,微软首席执行官Steve Ballmer批评了对LOC计数的使用:
In IBM there’s a religion in software that says you have to count K-LOCs, and a K-LOC is a thousand line of code. How big a project is it? Oh, it’s sort of a 10K-LOC project. This is a 20K-LOCer. And this is 50K-LOCs. And IBM wanted to sort of make it the religion about how we got paid. How much money we made off OS/2, how much they did. How many K-LOCs did you do? And we kept trying to convince them – hey, if we have – a developer’s got a good idea and he can get something done in 4K-LOCs instead of 20K-LOCs, should we make less money? Because he’s made something smaller and faster, less K-LOC. K-LOCs, K-LOCs, that’s the methodology. Ugh! Anyway, that always makes my back just crinkle up at the thought of the whole thing. 在IBM,有一个软件方面的教条,说你们必须统计K-LOC。一个项目多大?噢,它是一种10K-LOC的项目,这是一个20K-LOC的,而这是一个 50K-LOC的。并且IBM想按照这个标准来安排对我们的支付我们。多少钱我们在OS/2做的,多少钱是他们做的。多少K-LOC是你们做的?还有,我 们坚持试图说服他们-嘿,如果我们有一个开发人员想出了一个好主意并且它能用4K-LOC而不是20K-LOC来完成什么事,我们是不是应该得到更少的钱 呢?因为它使某件事更小更快,更少的K-LOC,K-LOC,K-LOC,那就是他们的方法学。哈!无论如何,总是在考虑整件事时,搞得我背都皱起来。
Related terms 相关术语
* KLOC: 1,000 lines of code
* KDLOC: 1,000 delivered lines of code
* KSLOC: 1,000 source lines of code
* MLOC: 1,000,000 lines of code
* GLOC: 1,000,000,000 lines of code
* KLOC: 1,000 代码行
* KDLOC: 1,000 已提交的代码行
* KSLOC: 1,000 源代码行
* MLOC: 1,000,000 代码行
* GLOC: 1,000,000,000 代码行

有不少软件开发组织,比如笔者所在的组织,在如何度量软件的大小时,就曾经用过SLOC,甚至打算通过LOC和KLOC的bug数来进行奖惩,后来被“自然”抵制了。再后来,随着功能的稳定,代码行数的稳定,这个问题就淡出了人们的视线。

如何度量软件大小,如何评估代价和开发者的生产力,靠SLOC是不够的。作为软件项目的管理者、实践者,应该认真的研究这个问题,根据实际的项目类型,程 序设计语言…等等来度量软件大小,评估代价和开发者的生产力,是项目管理在进度控制,成本和质量管理方面更准确。

那么我们应该如何来衡量软件大小呢?之后将专门设篇幅并结合实例对这个问题做一个探讨。

Powered by WordPress