饭饭TXT > 学习管理 > 《人月神话》作者:[美]弗雷德里克·布鲁克斯【完结】 > 人月神话.TXT

第 5 页

作者:美-弗雷德里克·布鲁克斯 当前章节:15416 字 更新时间:2026-6-22 20:55

他们握了一下手。“Coster先生,我只想问一件事,”Berkeley认真的说,“所有你需要做的事,我都无权过问——你即将进行一个技术演示——但是看在上帝的份上,能否记录一下,从而让我了解一下。我将会把一个开关放在你的桌上,它会开启桌上的一个密封的录像机。”

“好的!”Coster正看着他,Harriman想,够年轻的。

“如果要做任何非技术的事情,不需要自己动手。只需按个按钮知会一声,它们就会被完成!”Berkeley扫了Harriman一眼。“老板说他想同你谈一谈实际的工作。我得先走,去忙去了。”他离开了。

Harriman坐了下来,Coster整了整衣服,说道,“喔!”

“感觉好一些了?”

“我喜欢Berkeley这小伙子的样子。”

“太好了!不用担心,他现在就是你的孪生兄弟。我以前用过他。你可以认为你正住

在一个头等的疗养院里。”2

这个故事几乎不需要任何的分析解释,这种安排同样能使工作非常有效。

我猜测最后一种安排对小型的团队是最好的选择,如同在第3章《外科手术队伍》一文中所述。对于真正大型项目中的一些开发队伍,我认为产品负责人作为管理者是更合适的安排。

巴比伦塔可能是第一个工程上的彻底失败,但它不是最后一个。交流和交流的结果——组织,是成功的关键。交流和组织的技能需要管理者仔细考虑,相关经验的积累和能力的提高同软件技术本身一样重要。

胸有成竹(Calling the Shot)

实践是最好的老师。

- PUBILIUS

实践是最好的老师,但是,如果不能从中学习,再多的实践也没有用。

- 《可怜的理查年鉴》

Practice is the best of all instructors.

- PUBILIUS

Experience is a dear teacher, but fools will learn at no other.

- POOR RICHARD’S ALMANAC

系统编程需要花费多长的时间?需要多少的工作量?如何进行估计?

先前,我推荐了用于计划进度、编码、构件测试和系统测试的比率。首先,需要指出的是,仅仅通过对编码部分的估计,然后应用上述比率,是无法得到对整个任务的估计的。编码大约只占了问题的六分之一左右,编码估计或者比率的错误可能会导致不合理的荒谬结果。

第二,必须声明的是,构建独立小型程序的数据不适用于编程系统产品。对规模平均为3200指令的程序,如Sackman、Erikson和Grant的报告中所述,大约单个的程序员所需要的编码和调试时间为178个小时,由此可以外推得到每年35,800语句的生产率。而规模只有一半的程序花费时间大约仅为前者的四分之一,相应推断出的生产率几乎是每年80,000代码行1。计划、编制文档、测试、系统集成和培训的时间必须被考虑在内。因此,上述小型项目数据的外推是没有意义的。就好像把100码短跑记录外推,得出人类可以在3分钟之内跑完1英里的结论一样。

在将上述观点抛开之前,尽管不是为了进行严格的比较,我们仍然可以留意到一些事

情。即使在不考虑相互交流沟通,开发人员仅仅回顾自己以前工作的情况下,这些数字仍然显示出工作量是规模的幂函数。

图8.1讲述了这个悲惨的故事。它阐述了Nanus和Farr2在System Development Corporation公司所做研究,结果表明该指数为1.5,即,

工作量 = (常数)×(指令的数量)1.5

Weinwurm3的SDC研究报告同样显示出指数接近于1.5。

现在已经有了一些关于编程人员生产率的研究,提出了很多估计的技术。 Morin对所发布的数据进行了一些调查研究4。这里仅仅给出了若干特别突出的条目。

月 机器指令:千

注:

  incomplete-未终结的

图8.1:编程工作量是程序规模的函数

Portman的数据

曼彻斯特Computer Equipment Organization(Northwest)的ICL软件部门的经理Charles Portman,提出了另一种有用的个人观点5。

他发现他的编程队伍落后进度大约1/2,每项工作花费的时间大约是估计的两倍。这些

估计通常是非常仔细的,由很多富有经验的团队完成。他们对PERT图上数百个子任务估算过(用人小时作单位)。当偏移出现时,他要求他们仔细地保存所使用时间的日志。日志显示事实上他的团队仅用了百分之五十的工作周,来进行实际的编程和调试,估算上的失误完全可以由该情况来解释。其余的时间包括机器的当机时间、高优先级的无关琐碎工作、会议、文字工作、公司业务、疾病、事假等等。简言之,项目估算对每个人年的技术工作时间数量做出了不现实的假设。我个人的经验也在相当程度上证实了他的结论6。

Aron的数据

Joel Aron,IBM在马里兰州盖兹堡的系统技术主管,在他所工作过的9个大型项目(简要地说,大型意味着程序员的数目超过25人,将近30,000行的指令)7的基础上,对程序员的生产率进行了研究。他根据程序员(和系统部分)之间的交互划分这些系统,得到了如下的生产率:

非常少的交互

10,000指令每人年

少量的交互

5,000

较多的交互

1,500

该人年数据未包括支持和系统测试活动,仅仅是设计和编程。当这些数据采用除以2,以包括系统测试的活动时,它们与Harr的数据非常的接近。

Harr的数据

John Harr,Bell电话实验室电子交换系统领域的编程经理,在1969年春季联合计算机会议8的论文中,汇报了他和其他人的经验。这些数据如图8.2、8.3和8.4所示。

这些图中,图8.2是最数据详细和最有用的。头两个任务是基本的控制程序,后两个是基本的语言翻译。生产率以经调试的指令/人年来表达。它包括了编程、构件测试和系统测试。没有包括计划、硬件机器支持、文书工作等类似活动的工作量。

生产率同样地被划分为两个类别,控制程序的生产率大约是600指令每人年,语言翻译大约是2200指令每人年。注意所有的四个程序都具有类似的规模——差异在于工作组的大小、时间的长短和模块的个数。那么,哪一个是原因,哪一个是结果呢?是否因为控制程

序更加复杂,所以需要更多的人员?或者因为它们被分派了过多的人员,所以要求有更多的模块?是因为复杂程度非常高,还是分配较多的人员,导致花费了更长的时间?没有人可以确定。控制程序确实更加复杂。除开这些不确定性,数据反映了实际的生产率——描述了在现在的编程技术下,大型系统开发的状况。因此,Harr数据的确是真正的贡献。

图8.3和8.4显示了一些有趣的数据,将实际的编程速度、调试速度与预期做了对比。

程序单元

程序员人数

人年

程序字数

字/人年

操作性

50

83

4

101

52,000

515

维护

36

60

4

81

51,000

630

编译器

13

9

21/4

17

38,000

2230

语言解释器(汇编)

15

13

21/2

11

25,000

2270

图8.2:4个NO.1的ESS编程工作总结

注:

  Monthly estimate of program size-程序规模月估计

  Actual Programmize rate-实际编程速度

  Prediction of programming rate-预计编程速度

机器指令:千字

图8.3:ESS预计和实际的编程速度

注:

  Monthly estimate of program size-程序规模月估计

  Actual Programmize rate-实际调试速度

  Prediction of programming rate-预计调试速度

机器指令:千字

图8.4:ESS预计和实际的调试速度

OS/360的数据

IBM OS/360的经验,尽管没有Harr那么详细的数据,但还是证实了那些结论。就控制程序组的经验而言,生产率的范围大约是600~800(经过调试的指令)/人年。语言翻译小组所达到的生产率是2000~3000(经过调试的指令)/人年。这包括了小组的计划、代码构件测试、系统测试和一些支持性活动。就我的观点来说,它们同Harr的数据是可比的。

Aron、Harr和OS/360的数据都证实,生产率会根据任务本身复杂度和困难程度表现出显著差异。在复杂程度估计这片“沼泽”上的指导原则是:编译器的复杂度是批处理程序的三倍,操作系统复杂度是编译器的三倍8。

Corbato的数据

Harr和OS/360的数据都是关于汇编语言编程的,好像使用高级语言系统编程的数据公布得很少。Corbato的MIT项目MAC报告表示在MULTICS系统上,平均生产率是1200行经调试的PL/I语句(大约在1和2百万指令之间)/人年。

该数字非常令人兴奋。如同其他的项目,MULTICS包括了控制程序和语言翻译程序。和

其他项目一样,它产出的是经过测试和文档化的系统编程产品。在所包括的工作类型方面,数据看上去是可以比较的。该数字是其他项目中控制程序和翻译器程序生产率的良好平均值。

但Corbato的数字是行/人年,不是指令!系统中的每个语句对应于手写代码的3至5个指令!这意味着两个重要的结论。

  对常用编程语句而言。生产率似乎是固定的。这个固定的生产率包括了编程中需要注释,并可能存在错误的情况.

  使用适当的高级语言,编程的生产率可以提高5倍。

削足适履(Ten Pounds in a Five-Pound Sack)

他应该瞪大眼睛盯着诺亚, 好好学习,看他们是怎样把那么多东西装到一个小小的方舟上的。

- 西德尼·史密斯,爱丁堡评论

the author should gaze at Noah, and ... learn, as they did in the Ark, to crowd

a great deal of matter into a very small compass.

- SYDENY SMITH. EDINBURGH REVIEW

作为成本的程序空间

程序有多大?除了运行时间以外,它所占据的空间也是主要开销。这同样适用于专用开发的程序,用户支付给开发者一笔费用,作为必要分担的开发成本。考虑一下IBM APL交互式软件系统,它的租金为每月400美金,在使用时,它至少占用160K字节的内存。在Model 165上,内存租金大约是12美金/每月每千字节。如果程序在全部时间内都可用,他需要支付400美元的软件使用费和1920美金的内存租用费。如果某个人每天使用APL系统4小时,他每月需要支出400美元的软件租金和320美元的内存租用费。

常常听到的一个“可怕的”谈论是在2M内存的机器上,操作系统就需要占用400K内存。这种言论就好像批评波音747飞机,仅仅因为它耗资两千七百万美元一样无知。我们首先必须问的是“它能干什么?”。对于所耗费的资金,获得的易用性和性能是什么?投资在内存上的每月4800美元的租金能否比用在其他硬件、编程人员、应用程序上更加有效?

当系统设计者认为对用户而言,常驻程序内存的形式比加法器、磁盘等更加有用时,他会将硬件实现中的一部分移到内存上。相反的,其他的做法是非常不负责任的。所以,应

该从整体上来进行评价。没有人可以在自始至终提倡更紧密的软硬件设计集成的同时,又仅仅就规模本身对软件系统提出批评。

由于规模是软件系统产品用户成本中如此大的一个组成部分,开发人员必须设置规模的目标,控制规模,考虑减小规模的方法,就像硬件开发人员会设立元器件数量目标,控制元器件的数量,想出一些减少零件的方法。同任何开销一样,规模本身不是坏事,但不必要的规模是不可取的。

规模控制

对项目经理而言,规模控制既是技术工作的一部分,也是管理工作的一部分。他必须研究用户和他们的应用,以设置将开发系统的规模。接着,把这些系统划分成若干部分,并设定每个部分的规模目标。由于规模-速度权衡方案的结果在很大的范围内变化,规模目标的设置是一件颇具技巧的事情,需要对每个可用方案有深刻的了解。聪明的项目经理还会给自己预留一些空间,在工作推行时分配。

在OS/360项目中,即使所有的工作都完成得相当仔细,我们依然能从中得到一些痛苦的教训。

首先,仅对核心程序设定规模目标是不够的,必须把所有的方面都编入预算。在先前的大多数操作系统中,系统驻留在磁带上,长时间的磁带搜索意味着它无法自如地运用在程序片段上。OS/360和它的前任产品Stretch操作系统和1410-7010磁盘操作系统一样,是驻留在磁盘上的。它的开发者对自由、廉价的磁盘访问感到欣喜。而如果使用磁带,会给性能带来灾难性的后果。

在为每个单元设立核心规模的同时,我们没有同时设置访问的目标。正如大家能想到的一样,当程序员发现自己的单元核心未能达到要求时,他会把它分解成链接库。这个过程本身增加了程序整体的规模,并降低了运行速度。最重要的是,我们的管理控制系统既没有度量,也没有捕获这些问题。每个人都汇报了核心的大小,都在目标范围之内,所以没有人发现规模上的问题。

幸运的是,OS/360性能仿真程序投入使用的时间较早。第一次运行的结果反映出很大的麻烦。Fortran H,在带磁鼓的Modal 65上,每分钟模拟编译5条语句!嵌入的例程显示

控制程序模块进行了很多次磁盘访问。甚至使用频繁的监控模块也犯了很多同样的错误,结果很类似于页面的切换。

第一个道理很清楚:和制订驻留空间预算一样,应该制订总体规模的预算;和制订规模预算一样,应该制订后台存储访问的预算。

下一个教训十分类似。在每个模块分配功能之前,已编制了空间的预算。其结果是,任何在规模上碰到问题的程序员,会检查自己的代码,看是否能将其中一部分扔给其他人。因此,控制程序所管理的缓冲区成为了用户空间的一部分。更严重的是,所有的控制模块都有相同的问题,彻底影响了系统的稳定和安全性。

所以,第二个道理也很清晰:在指明模块有多大的同时,确切定义模块的功能。

第三个更深刻的教训体现在以上的经验中。项目规模本身很大,缺乏管理和沟通,以至于每个团队成员认为自己是争取小红花的学生,而不是构建系统软件产品的人员。为了满足目标,每个人都在局部优化自己的程序,很少会有人停下来,考虑一下对客户的整体影响。对大型项目而言,这种导向和缺乏沟通是最大的危险。在整个实现的过程期间,系统结构师必须保持持续的警觉,确保连贯的系统完整性。在这种监督机制之外,是实现人员自身的态度问题。培养开发人员从系统整体出发、面向用户的态度是软件编程管理人员最重要的职能。

空间技能

空间预算的多少和控制并不能使程序规模减小,为实现这一目标,它还需要一些创造性和技能。

显然,在速度保持不变的情况下,更多的功能意味着需要更多的空间。所以,其中的一个技巧是用功能交换尺寸。这是一个较早的、影响较深远的策略问题:为用户保留多少选择?程序可以有很多的选择功能,每个功能仅占用少量的空间。也可以设计成拥有若干选项分组,根据选项组来剪裁程序。任何一系列特殊选项被合并在一起进行分组时,程序需要的空间较少。这很像小汽车。如果把照明灯、点烟器和时钟作为整个配件来标明价格,则成本会比单独提供这些选择所需要的成本低。所以,设计人员必须决定用户可选项目的粗细程度。

在内存大小一定的情况下进行系统设计时,会出现另外一个基本问题。内存受限的后果是即使最小的功能模块,它的适用范围也难以得到推广。在最小规模的系统中,大多数模

块被覆盖(overlaid),系统的主干占用的空间,会被用作其他部分的交换页面。它的尺寸决定了所有模块的尺寸。而且将功能分解到很小的模块会耗费空间和降低性能。所以,当可以提供20倍临时性空间的大型系统使用这些模块时,节省的也仅仅是访问次数,仍然会因为模块的规模引起空间和速度上的损失。这样后果其实是——很难用小型系统的模块构造出非常高效的系统。

第二个技能是考虑空间-时间的折衷。对于给定的功能,空间越多,速度越快。这一点在很大的范围内都适用。也正是这一点使空间预算成为可能。

项目经理可以做两件事来帮助他的团队取得良好的空间-时间折衷。一是确保他们在编程技能上得到培训,而不仅仅是依赖他们自己掌握的知识和先前的经验。特别是使用新语言或者新机器时,培训显得尤其重要。熟练使用往往需要快速的学习和经验的广泛共享,也许它应该伴随特别的新技术奖励或者表扬。

另外一种方法是认识到编程需要技术积累,需要开发很多公共单元构件。每个项目要有能用于队列、搜索和排序的例程或者宏库。对于每项功能,库至少应该有两个程序实现:运行速度较快和短小精炼的。上述的公共库开发是一件重要的实现工作,它可以与系统设计工作并行进行。

数据的表现形式是编程的根本

创造出自精湛的技艺,精炼、充分和快速的程序也是如此。技艺改进的结果往往是战略上的突破,而不仅仅是技巧上的提高。这种战略上突破有时是一种新的算法,如快速傅立叶变换,或者是将比较算法的复杂度从n2降低到n log n。

更普遍的是,战略上突破常来自数据或表的重新表达——这是程序的核心所在。如果提供了程序流程图,而没有表数据,我仍然会很迷惑。而给我看表数据,往往就不再需要流程图,程序结构是非常清晰的。

很容易就能找到重新表达所带来好处的例子。我记得有一个年轻人承担了为IBM650开发精细的控制台解释器的任务。他发现用户交互得很慢,并且空间很昂贵。于是,他编写了一个解释器的解释器,使得最后程序所占的空间减少到不可思议的程度。Digitek小而优雅的Fortran编译器使用了非常密集的、专业化的代码来表达自己,以至于不再需要外部存储。

对这种表达方式解码会损失一些时间,但由于避免了输入-输出,反而得到了十倍的补偿。(Brooks和Iverson第六章结尾的练习以及Knuth的练习2--自动数据处理1包含了许多类似的例子。)

由于缺乏空间而绞尽脑汁的编程人员,常常能通过从自己的代码中挣脱出来,回顾、分析实际情况,仔细思考程序的数据,最终获得非常好的结果。实际上,数据的表现形式是编程的根本。

提纲挈领(The Documentary Hypothesis)

前提:

在一片文件的汪洋中,少数文档形成了关键的枢纽,每件项目管理的工作都围绕着它们运转。它们是经理们的主要个人工具。

The hypothesis:

Amid a wash of paper, a small number of documents become the critical pivots around which every project's management revolves. These are the manager's chief personal tools.

技术、周边组织机构、行业传统等若干因素凑在一起,定义了项目必须准备的一些文书工作。对于一个刚从技术人员中任命的项目经理来说,这简直是一件彻头彻尾令人生厌的事情,而且是毫无必要和令人分心的,充满了被吞没的威胁。但是,在实际工作中,大多数情况都是这样的。

慢慢的,他逐渐认识到这些文档的某些部分包含和表达了一些管理方面的工作。每份文档的准备工作是集中考虑,并使各种讨论意见明朗化的主要时刻。如果不这样,项目往往会处于无休止的混乱状态。文档的跟踪维护是项目监督和预警的机制。文档本身可以作为检查列表、状态控制,也可以作为汇报的数据基础。

为了阐明软件项目如何开展这项工作,我们首先借鉴一下其他行业一些有用的文档资料,看是否能进行归纳,得出结论。

计算机产品的文档

如果要制造一台机器,哪些是关键的文档呢?

目标:定义待满足的目标和需要,定义迫切需要的资源、约束和优先级。

技术说明:计算机手册和性能规格说明。它是在计划新产品时第一个产生,并且最后

完成的文档。

进度、时间表

预算:预算不仅仅是约束。对管理人员来说,它还是最有用的文档之一。预算的存在会迫使技术决策的制订,否则,技术决策很容易被忽略。更重要的是,它促使和澄清了策略上的一些决定。

组织机构图

工作空间的分配

报价、预测、价格:这三个因素互相牵制,决定了项目的成败。

预测

报价

价格

为了进行市场预测,首先需要制订产品性能说明和确定假设的价格。从市场预测得出的数值,连同从设计得出的组件单元的数量,决定了生产的估计成本,进而可以得到每个单元的开发工作量和固定的成本。固定成本又决定了价格。

如果价格低于假设值,令人欣慰的循环开始了。预测值较高,单元成本较低,因此价格能够继续降低。

如果价格高于预测值,灾难性的循环开始了,所有的人必须努力奋斗来打破这个循环。新应用程序必须提高性能和支持更高的市场预测。成本必须降低,以产出更低的报价。这个循环的压力常常是激励市场人员和工程师工作的最佳动力。

同时,它也会带来可笑的踌躇和摇摆。我记得曾经有一个项目,在三年的开发周期中,机器指令计数器的设计每六个月变化一次。在某个阶段,需要好一点的性能时,指令计数器采用触发器来实现;下一个阶段,成本降低是主要的焦点,指令计数器采用内存来实现。在另一个项目中,我所见过的最好的一个项目经理常常充当一个大型调速轮的角色,他的惯性降低了来自市场和管理人员的起伏波动。

大学科系的文档

除了目的和活动上的巨大差异,数量类似、内容相近的各类文档形成了大学系主任的主要资料集合。校长、教师会议或系主任的每一个决定几乎都是一个技术说明,或者是对这些文档的变更。

目标

课程描述

学位要求

研究报告(申请基金时,还要求计划)

课程表和课程的安排

预算

教室分配

教师和研究生助手的分配

注意这些文档的组成与计算机项目非常相似:目标、产品说明、时间安排、资金分配、空间分派和人员的划分。只有价格文档是不需要的,学校的决策机构完成了这项任务。这种相似性不是偶然的——任何管理任务的关注焦点都是时间、地点、人物、做什么、资金。

软件项目的文档

在许多软件项目中,开发人员从商讨结构的会议开始,然后开始书写代码。不论项目的规模如何小,项目经理聪明的做法都是:立刻正式生成若干文档作为自己的数据基础,哪怕这些迷你文档非常简单。接着,他会和其他管理人员一样要求各种文档。

做什么:目标。定义了待完成的目标、迫切需要的资源、约束和优先级。

做什么:产品技术说明。以建议书开始,以用户手册和内部文档结束。速度和空间说明是关键的部分。

时间:进度表

资金:预算

地点:工作空间分配

人员:组织图。它与接口说明是相互依存的,如同Conway的规律所述:“设计系统的组织架构受到产品的约束限制,生产出的系统是这些组织机构沟通结构的映射。1”Conway接着指出,一开始反映系统设计的组织架构图,肯定不会是正确的。如果系统设计能自由地变化,则项目组织架构必须为变化做准备。

为什么要有正式的文档?

首先,书面记录决策是必要的。只有记录下来,分歧才会明朗,矛盾才会突出。书写这项活动需要上百次的细小决定,正是由于它们的存在,人们才能从令人迷惑的现象中得到清晰、确定的策略。

第二,文档能够作为同其他人的沟通渠道。项目经理常常会不断发现,许多理应被普遍认同的策略,完全不为团队的一些成员所知。正因为项目经理的基本职责是使每个人都向着相同的方向前进,所以他的主要工作是沟通,而不是做出决定。这些文档能极大地减轻他的负担。

最后,项目经理的文档可以作为数据基础和检查列表。通过周期性的回顾,他能清楚项目所处的状态,以及哪些需要重点进行更改和调整。

我并不是很同意销售人员所吹捧的“完备信息管理系统”——管理人员只需在计算机上输入查询,显示屏上就会显示出结果。有许多基本原因决定了上述系统是行不通的。一个原因是只有一小部分管理人员的时间——可能只有20%——用来从自己头脑外部获取信息。其他的工作是沟通:倾听、报告、讲授、规劝、讨论、鼓励。不过,对于基于数据的部分,少数关键的文档是至关重要的,它们可以满足绝大多数需要。

项目经理的任务是制订计划,并根据计划实现。但是只有书面计划是精确和可以沟通的。计划中包括了时间、地点、人物、做什么、资金。这些少量的关键文档封装了一些项目经理的工作。如果一开始就认识到它们的普遍性和重要性,那么就可以将文档作为工具友好地利用起来,而不会让它成为令人厌烦的繁重任务。通过遵循文档开展工作,项目经理能更清晰和快速地设定自己的方向。

未雨绸缪(Plan to Throw One Away)

不变只是愿望,变化才是永恒。

- SWIFT

普遍的做法是,选择一种方法,试试看;如果失败了,没关系,再试试别的。不管怎么样,重要的是先去尝试。

- 富兰克林 D. 罗斯福1

There is nothing in this world constant but inconstancy.

- SWIFT

It is common sense to take a method and try it. If it fails, admit it frankly and try another. But above all, try something.

- FRANKLIN D. ROOSEVELT1

试验性工厂和增大规模

化学工程师很早就认识到,在实验室可以进行的反应过程,并不能在工厂中一步实现。一个被称为“实验性工厂(pilot planet)”的中间步骤是非常必要的,它会为提高产量和在缺乏保护的环境下运作提供宝贵经验。例如,海水淡化的实验室过程会先在产量为10,000加仑/每天的试验场所测试,然后再用于2,000,000加仑/每天的净化系统。

软件系统的构建人员也面临类似的问题,但似乎并没有吸取教训。一个接一个的软件项目都是一开始设计算法,然后将算法应用到待发布的软件中,接着根据时间进度把第一次开发的产品发布给顾客。

对于大多数项目,第一个开发的系统并不合用。它可能太慢、太大,而且难以使用,或者三者兼而有之。要解决所有的问题,除了重新开始以外,没有其他的办法——即开发一

个更灵巧或者更好的系统。系统的丢弃和重新设计可以一步完成,也可以一块块地实现。所有大型系统的经验都显示,这是必须完成的步骤2。而且,新的系统概念或新技术会不断出现,所以开发的系统必须被抛弃,但即使是最优秀的项目经理,也不能无所不知地在最开始解决这些问题。

因此,管理上的问题不再是“是否构建一个试验性的系统,然后抛弃它?”你必须这样做。现在的问题是“是否预先计划抛弃原型的开发,或者是否将该原型发布给用户?”从这个角度看待问题,答案更加清晰。将原型发布给用户,可以获得时间,但是它的代价高昂——对于用户,使用极度痛苦;对于重新开发的人员,分散了精力;对于产品,影响了声誉,即使最好的再设计也难以挽回名声。

因此,为舍弃而计划,无论如何,你一定要这样做。

唯一不变的就是变化本身

一旦认识到试验性的系统必须被构建和丢弃,具有变更思想的重新设计不可避免,从而直面整个变化现象是非常有用的。第一步是接受这样的事实:变化是与生俱来的,不是不合时宜和令人生厌的异常情况。Cosgrove很有洞察力地指出,开发人员交付的是用户满意程度,而不仅仅是实际的产品。用户的实际需要和用户感觉会随着程序的构建、测试和使用而变化3。

当然对于硬件产品而言,同样需要满足要求,例如新型汽车或者计算机。但物体的客观存在容纳和阶段化(量子化)了用户对变更的要求。软件产品易于掌握的特性和不可见性,导致它的构建人员面临永恒的需求变更。

我从不建议顾客目标和需求的所有变更必须、能够、或者应该整合到设计中。项目开始时建立的基准,肯定会随着开发的进行越来越高,甚至开发不出任何产品。

然而,目标上的一些变化无可避免,事先为它们做准备总比假设它们不会出现要好得多。不但目标上的变化不可避免,而且设计策略和技术上的变化也不可避免。抛弃原型概念本身就是对事实的接受——随着学习的过程更改设计4。

为变更计划系统

如何为上述变化设计系统,是个非常著名的问题,在书本上被普遍讨论——可能讨论得比实践还要多得多。它们包括细致的模块化、可扩展的函数、精确完整的模块间接口设计、完备的文档。另外,还可能会采用包括调用队列和表驱动的一些技术。

最重要的措施是使用高级语言和自文档技术,以减少变更引起的错误。采用编译时的操作来整合标准声明,在很大程度上帮助了变化的调整。

变更的阶段化是一种必要的技术。每个产品都应该有数字版本号,每个版本都应该有自己的日程表和冻结日期,在此之后的变更属于下一个版本的范畴。

为变更计划组织架构

Cosgrove主张把所有计划、里程碑、日程安排都当作是尝试性的,以方便进行变化。这似乎有些走极端——现在软件编程小组失败的主要原因是管理控制得太少,而不是太多。

不过,他提出了一种卓越的见解。他观察到不愿意为设计书写文档的原因,不仅仅是由于惰性或者时间压力。相反,设计人员通常不愿意提交尝试性的设计决策,再为它们进行辩解。“通过设计文档化,设计人员将自己暴露在每个人的批评之下,他必须能够为他的每个结果进行辩护。如果团队架构因此受到任何形式的威胁,则没有任何东西会被文档化,除非架构是完全受到保护的。

为变更组建团队比为变更进行设计更加困难。每个人被分派的工作必须是多样的、富有拓展性的工作,从技术角度而言,整个团队可以灵活地安排。在大型的项目中,项目经理需要有两个和三个顶级程序员作为技术轻骑兵,当工作繁忙最密集的时候,他们能急驰飞奔,解决各种问题。

当系统发生变化时,管理结构也需要进行调整。这意味着,只要管理人员和技术人才的天赋允许,老板必须对他们的能力培养给予极大的关注,使管理人员和技术人才具有互换性。

这其中的障碍是社会性的,人们必须同顽固的戒心做斗争。首先,管理人员自己常常认为高级人员太“有价值”,而舍不得让他们从事实际的编程工作;其次,管理人员拥有更

高的威信。为了克服这个问题,如Bell Labs的一些实验室,废除了所有的职位头衔。每个专业人士都是“技术人员中的一员”。而IBM的另外一些实验室,保持了两条职位晋升线,如图11.1所示。相应的级别在概念上是相同的。

管理线

技术线

高级程序员

高级程序员

开发程序员

项目程序员

程序职员

顾问程序员

高级准程序员

图11.1:IBM的两条职位晋升线

很容易为上述层次建立相互一致的薪水级别。但要建立一致的威信,会困难一些。比如,办公室的大小和布局应该相同。秘书和其他支持也必须相同。从技术线向管理同级调动时,不能伴随着待遇的提升,而且应该以“调动”,而不是“晋升”的名义。相反的调整则应该伴随着待遇的提高,对于传统意识进行补偿是必要的。

管理人员需要参与技术课程,高级技术人才需要进行管理培训。项目目标、进展、管理问题必须在高级人员整体中得到共享。

只要能力允许,高层人员必须时刻做好技术和情感上的准备,以管理团队或者亲自参与开发工作。这是件工作量很大的任务,但显然很值得!

组建外科手术队伍式的软件开发团队,这整个观念是对上述问题的彻底冲击。其结果是当高级人才编程和开发时,不会感到自降身份。这种方法试图清除那些会剥夺创造性乐趣的社会障碍。

另外,上述组织架构的设计是为了最小化成员间的接口。同样的,它使系统在最大程度上易于修改。当组织构架必须变化时,为整个“外科手术队伍”重新安排不同的软件开发任务,会变得相对容易一些。这的确是一个长期有效的灵活组织构架解决方案。

前进两步,后退一步

在程序发布给顾客使用之后,它不会停止变化。发布后的变更被称为“程序维护”,但是软件的维护过程不同于硬件维护。

计算机系统的硬件维护包括了三项活动——替换损坏的器件、清洁和润滑、修改设计上的缺陷。(大多数情况下——但不是全部——变更修复的是实现上、而不是结构上的一些缺陷。对于用户而言,这常常是不可见的。)

软件维护不包括清洁、润滑和对损坏器件的修复。它主要包含对设计缺陷的修复。和硬件维护相比,这些软件变更包含了更多的新增功能,它通常是用户能察觉的。

对于一个广泛使用的程序,其维护总成本通常是开发成本的40%或更多。令人吃惊的是,该成本受用户数目的严重影响。用户越多,所发现的错误也越多。

麻省理工学院核科学实验室的Betty Campbell指出特定版本的软件发布生命期中一个有趣的循环。如图11.2所示。起初,上一个版本中被发现和修复的bug,在新的版本中仍会出现。新版本中的新功能会产生新的bug。解决了这些问题之后,程序会正常运行几个月。接着,错误率会重新攀升。Campbell认为这是因为用户的使用到达了新的熟练水平,他们开始运用新的功能。这种高强度的考验查出了新功能中很多不易察觉的问题。5

安装后的时间(月)

每月发现的bug数

图11.2:出现的bug数量是发布时间的函数

程序维护中的一个基本问题是——缺陷修复总会以(20-50)%的机率引入新的bug。所以整个过程是前进两步,后退一步。

为什么缺陷不能更彻底地被修复?首先,看上去很轻微的错误,似乎仅仅是局部操作上的失败,实际上却是系统级别的问题,通常这不是很明显。修复局部问题的工作量很清晰,并且往往不大。但是,更大范围的修复工作常常会被忽视,除非软件结构很简单,或者文档书写得非常详细。其次,维护人员常常不是编写代码的开发人员,而是一些初级程序员或者新手。

作为引入新bug的一个后果,程序每条语句的维护需要的系统测试比其他编程要多。理论上,在每次修复之后,必须重新运行先前所有的测试用例,从而确保系统不会以更隐蔽的方式被破坏。实际情况中,回归测试必须接近上述理想状况,所以它的成本非常高。

显然,使用能消除、至少是能指明副作用的程序设计方法,会在维护成本上有很大的回报。同样,设计实现的人员越少、接口越少,产生的错误也就越少。

目录
设置
设置
阅读主题
字体风格
雅黑 宋体 楷书 卡通
字体大小
适中 偏大 超大
保存设置
恢复默认
手机
手机阅读
扫码获取链接,使用浏览器打开
书架同步,随时随地,手机阅读
首 页 < 上一章 章节列表 下一章 > 尾 页