软件工艺

978-7-115-28068-8
作者: 【美】Pete McBreen
译者: 熊节
编辑: 傅道坤

图书目录:

详情

本书首先对软件开发的传统观点提出质疑,然后提出“采用软件工程来解决软件开发中的问题”的观点,并从不同角度展现了软件工艺理论所带来的主要变化,以及如何实践这个观念,然后对软件工艺和软件工程进行了对比,最后讨论了软件开发中的权宜之计和长期问题。

图书摘要

Software Craftsmanship:The New Imperative

软件工艺

[美]Pete McBreen 著

熊节 译

人民邮电出版社

北京

图书在版编目(CIP)数据

软件工艺/(美)麦克布林(McBreen,P.)著;熊节译.--北京:人民邮电出版社,2012.12

ISBN 978-7-115-28068-8

Ⅰ.①软… Ⅱ.①麦…②熊… Ⅲ.①软件工程 Ⅳ.TP311.5

中国版本图书馆CIP数据核字(2012)第080916号

版权声明

Authorized translation from the English language edition, entitled Software Craftsmanship: The New Imperative, 0201733862 by Pete McBreen, published by Pearson Education, Inc., publishing asAddison-Wesley,Copyright©2001PearsonEducation,Inc.

All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from Pearson Education Inc. CHINESE SIMPLIFIED language edition published by PEARSON EDUCATION ASIA LTD., and POSTS &TELECOMMUNICATIONSPRESSCopyright©2012.

本书封面贴有Pearson Education(培生教育出版集团)激光防伪标签。无标签者不得销售。

软件工艺

◆著 [美] Pete McBreen

译 熊节

责任编辑 傅道坤

◆人民邮电出版社出版发行  北京市崇文区夕照寺街14号

邮编 100061  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

三河市海波印务有限公司印刷

◆开本:880×1230 1/32

印张:8.5  2012年12月第1版

字数:164千字  2012年12月河北第1次印刷

著作权合同登记号 图字:01-2011-7814号

ISBN 978-7-115-28068-8

定价:29.00元

读者服务热线:(010)67132692 印装质量热线:(010)67129223

反盗版热线:(010)67171154

广告经营许可证:京崇工商广字第0021号

内容提要

本书针对软件开发,提出了一些相当棘手和敏感的问题,并给出了颇具争议性的结论:从一个数百年来一直兴旺发达的系统——工艺学中获得启示,寻找答案。

本书用5个部分共19章的篇幅,系统地阐述作者的观点,并试图回答一直困扰着软件行业的难题——我们应该如何重组软件构造的过程,使其能够如我们所愿地有效运转?第1部分共4章,对传统的观点提出质疑——软件工程真的是解决软件开发问题的灵丹妙药吗?第2部分共2章,这一部分提出了本书的观点,即以软件工艺的视角看待软件开发。第3部分以7章的篇幅,从不同的角度全面地展现了软件工艺理论所带来的主要变化,以及如何实践这个观念。第4部分共3章,对比了软件工艺与软件工程,并为各自适用的范畴重新划定了界限。第5部分共3章,分别讨论软件开发中的权宜之计和长期问题。

本书荣获2002年度Jolt图书大奖。阅读本书,有助于引发读者在软件开发问题上的独立思考。本书适合软件行业的所有从业人员阅读参考。

作者简介

Pete McBreen是一名独立顾问,对软件开发情有独钟。尽管将很多时间用于写作、教学和顾问工作,但他仍然坚持每年至少在一个真实项目中亲手从事编程工作。Pete特别善于为软件开发者面临的问题找到创造性的解决方案。在过去的很多年中,他参与了各种正式和非正式的过程改进活动,所以他能够以超然的态度看待软件业普遍存在的问题,并敏锐地意识到:“软件开发理应有其乐趣。否则,开发过程就是错的。”Pete住在加拿大亚伯达省的小镇考昆,没有再回到大城市居住的计划。

译者简介

熊节,普通程序员,喜编程,乐此而不疲。酷爱读书,好求新知。记性好忘性大,故凡有所得必记诸文字,有小得,无大成。胸有点墨,心无大志,惟愿宁静淡泊而已。夜阑人静,一杯清水,几本闲书,神交于各方名士,献曝于天下同好,吾愿足矣。

中译本序

看见“软件工艺”的思想在全世界得到日益广泛的认同,我欣喜若狂。这本《软件工艺》,是为软件开发的工艺学送上的赞歌。在过去的30年中,很多人试图把软件开发变成一种机械化的行为。尽管如此,优秀的开发者们仍然知道:真正起决定性作用的,还是编写软件的人,是他们的技能和经验。没错,现在有很多精良的工具和技术,但最关键的还是使用这些工具的人,是他们的才华。

从事软件开发的企业为什么会把这一切置之脑后呢?我不知道。不止一次,我看到早期的文献中强调“软件编写者的能力”的重要性。软件工艺的思想毫不新鲜,在我着手撰写本书之前,Jim Coplien和Steve McConnell(以及其他很多人)早已在各自的著作中提到过它。掌握软件开发中的工具和技术需要耗费很多时间,但在那之后,开发者还需要学会并习惯交付优秀的软件。

在过去的一段时间里,人们似乎太热衷于追寻一蹴而就的终南捷径,静听“掌握软件开发技艺”的传统似乎已经不再流行。但是,时间早已证明,只有精通自己的技艺,才是获得成功的不二法门。对于软件开发之外的很多行业,这个道理是众所周知的。即便是批量生产的标准件取代了手工作坊,人们在内心深处依然坚信:哪怕是司空见惯的日常用品,也只有工艺大师才能做出精品。

自出版以来,本书已经先后被翻译为日文和韩文,现在又有了中文译本。本书中的思想与西方的工艺学传统、学徒传统有着紧密的联系,看着这些思想被如此贴切地翻译到另一种文化中,是一件颇有兴味的事情。曾经有很多人错误地认为软件开发是一项机械性的行为,希望本书能帮助你避免重蹈覆辙—这就是我给本书读者的祝愿。

Pete McBreen

2003年8月

译者序

时隔一年之后,当我再次到AMAZON寻找这本《软件工艺》时,它的评价不知何时已经悄悄地变成了四星半,销售排行也已经到了5000多名 熟悉AMAZON的读者应该知道,在AMAZON能得到四星半评价的已经是精品好书,四位数的销售排行就更能证明它的品质。可是,一年前看到的批评仍然历历在目:“过时的例子”、“混乱的逻辑”、“东拉西扯不知所云”……当这些尖锐的言辞与“所有软件管理者的必读书目”一类溢美之词并列时,我不得不再次认真地思索:这究竟是一本怎样的书?

Pete McBreen说,这本《软件工艺》是一本“极具煽动性”的著作。而在我看来,用“煽动性”来评价它只嫌太客气,或许“颠覆性”会是一个更贴切的词。自1968年NATO会议以后,软件工程的话语就始终把持着软件业(以及软件学科)的言路。一切的软件问题都不由自主地被归咎于“软件危机”,同样自然地,一切的解决方案都不由自主地被划入“软件工程”的范畴。从记事以来……呃,我是说,从上大学以来,我们的一切讨论都围绕着软件工程展开:这样做是否符合软件工程?如何对软件工程加以改进?企业应该如何开展软件工程?凡此种种。在言词的不断重复与变调之间,“软件工程”逐渐被捧上了神坛,成为一种信仰,并因此失去了它旧有的价值与意义。君不见,即便是软件工程的反对者,也只能说出“我们不要软件工程”这样的话——仍然未脱软件工程的话语霸权。

Pete McBreen是一个极其敏锐的人,并且对语词背后的意蕴有着深刻的体会和认识,这或许与他年少时在英国所受的教育有关吧。他一针见血地指出:软件并不是工程,“软件工程”仅仅是一个多少有些不够贴切的隐喻而已。是的,一个隐喻,正如我们常说的“桌子腿”、“针眼”一样,这是一个深入人心、渗透极广的隐喻。但是,尽管每个人都知道绣花针并没有长眼睛,我们却常常忘记了软件工程作为隐喻的本来身份,真心诚意地把软件作为一种工程来对待了。软件工程的困境与读到这本《软件工艺》时本能的拒斥,殆出于此。

钱钟书曾说,反其道以行也是一种模仿。而对于目前软件工程的反对者们,另一个更恰当的比喻是“反转的胶片”——胶片的颜色与照片完全相反,但两者记载的信息却是毫无二致。作为一个真正意义上的颠覆者,Pete McBreen为软件开发找到了另一个隐喻(以及随之而来的另一套语词),那就是本书的标题——软件工艺(software craftsmanship)。

对于这套工艺学的语词,我一直有着淡淡的隐忧。在西方,工艺学传统多半与文艺复兴的人本主义联系在一起,而在对现代性的反动中,文艺复兴一直是吸引大众的旗帜。因此,可以想象,“软件工艺”这样一个隐喻对于欧美程序员有着不可抵挡的诱惑。而在中国,“学而优则仕”的传统价值观固有地鄙薄工艺学的实践者,“五四”以后,现代性的话语又早已根深蒂固,所以我实在不敢乐观地期望这个译本的读者能够让“软件工艺”的思想畅行无阻。好在Pete McBreen并不是一个太喜欢夸夸其谈的作者,书中的论述虽然大胆,却是有理有据。既然Fred Brooks的“没有银弹”已经深入人心,相信以逻辑思维见长的软件开发者们能够抛开对软件工程的迷信,随作者一道认识软件工程的局限,并由此生发对软件工艺的思索。倘如此,这本书也就算不辱使命了。

在你开始正式阅读本书之前,请允许我给你打一针预防针:这本书可能颠覆你浸淫其中数年甚至十年的软件观,所以书中的很多观点可能让你感到出离惊奇,甚至出离愤怒。请你不要马上把它扔到墙角去,阅读的过程也就是习惯一种话语方式的过程。当你逐渐习惯软件工艺的话语方式之后,或许能从中找到一些自己需要的东西。

为这个译本,我要感谢UMLChina的站长潘加宇,是他把这本书硬塞到我的手上,让我没有与这本精彩的著作失之交臂。我还要感谢我的女友马姗姗给予的帮助,她优雅的文笔弥补了我言辞的生涩,她的支持与鼓励让我能够在工作之余顺利完成此书的翻译。谢谢你,亲爱的姗姗。

最后,希望你能从这本《软件工艺》中找到别样的触动和欣喜——就像我曾经的阅读体验。

熊节

2003年8月9日星期六 凌晨

杭州

致谢

或许你不会相信,本书的灵感来自软件工程研究所(Software Engineering Institute,SEI)。在20世纪90年代早期,我四处寻找提高小型团队生产率的办法,能力成熟度模型(Capability Maturity Model,CMM)看上去是一个可行的起点。但是,我最终认识到:对于绝大多数项目,人的天赋比使用的过程更重要。

很快,我又发现,那并不真的是天赋。优秀的开发者之所以优秀,是因为他们知道如何创建优秀的软件,并且不断学习开发优秀软件的新方法。随后我意识到自己的思想得益于很多优秀的软件开发者和技术作家:Gerald Weinberg、Luke Hohmann、Capers Jones、Jim Coplien……他们的著作占据着我的书架每次读他们的书,总会让我不时掩卷沉思“如何开发优秀软件”这个问题,他们是我心目中的明星。

这本书的写作历时经年。是Alistair Cockburn最早让我明白:软件开发者能够、也应该写书。Alistair 还鼓励我成为Addison-Wesley的一名审稿人,这也最终间接促成了本书的问世。

另一个间接的影响来自Catapulse Inc.的Rebecca Bence,她鼓励我在Catapulse网站上撰写了“软件工程 vs. 软件工艺”的文章。在这篇文章中,我对“工程”和“工艺”这两个隐喻做了对比。本书第3章的很多思想就来自这篇文章。

非常感谢Addison-Wesley的编辑团队——Mike Hendrickson、Heather Olszyk、Ross Venables和Marcy Barnes。本书的审稿人包括Ken Auer、Jim Bird、Bruce Brennan、Martin Fowler、Alastair Handley、Andy Hunt、Kim Kelln、Greg Klafki、Michael Le Feuvre、Miroslav Novak、Dave Thomas、Bruce Wampler和Frank Westphal,他们给了我无数的好建议,也对他们表示感谢。

最后,我要感谢我的妻子Lesley,是她让我明白:应该停止抱怨软件工程的现状,潜心针对这个问题写一些东西。感谢你的爱和支持。

Pete McBreen

序言

本书提出了一些相当棘手的问题。

对于工作量少于100人年(developer-year)的项目,软件工程仍然适用吗?软件工程与生俱来的专业化趋势真的是一个好主意吗?甚至,软件的开发真的可以用工程学的术语来描述吗?

本书也提出了一些相当敏感的问题:那些缺乏经验的开发者,是否享受了过高的薪资待遇?那些资深的开发者,是否应该比企业中绝大多数人都拿得更多?那些出现至今还不足十年的工具,是否应该在长期的项目中使用?

在这一切的最核心处,本书提出了一个最大的问题:我们应该如何重组软件构造的过程,使其能够如我们所愿地有效运转?

对于这些问题,本书也提出了一些颇具争议性的答案:本书认为,我们一直对一个简单的事实视而不见——编写软件的,不是硕大无朋的方法学,也不是一丝不苟的组织结构,而是。在当今软件开发的领域中,我们正在面临一个日益严重的危机。为了扭转这种不利的局面,我们需要培养出优秀的软件开发者。而为了达到这个目的,Pete[1]回顾了一个数百年来一直兴旺发达的系统,并期望从中获得启示——那就是工艺学。

“工艺”这个词是一种象征,象征着高质量的产品。但它的含义却还不仅限于此。从完整的意义上来说,工艺学是一个自给的系统。在这个系统中,师傅负责安排学徒的工作和培训,而学徒也有可能取代师傅,每个人地位的高下完全取决于他生产出的产品的优劣。学徒、工人和技师,所有人都在同一个团队中一起工作,并彼此学习。顾客则根据团队的声望来做出选择,而团队也只接受那些他们认为有可能提高他们声望的工作。

在我们的产业中,这个完整的工艺学系统能起作用吗?说实话,我也不知道。许多根深蒂固的习惯都必然会反对这种工艺学的观点。不过,我的确知道,作为学徒接受师傅的言传身教而最终成为高手,这样的成长途径是行之有效的,因为我就经历了这样的成长过程。

应该说我很幸运,进入了一所优秀的大学,在那里我学到了很多的理论(不过,在我上大学的时候,需要学的理论比现在可少多了)。但是,真正让我的大学生活显得与众不同的,还是那段学徒经历。那时,一位研究生带着我一起工作。他并没有明确地要教给我什么,但他用实际行动让我看到了一个优秀程序员的思维方式。月复一月,我在他的身边工作,从他那里吸收了大量实用的知识。不论是设计、编码还是调试,我从他那里学到的知识比在任何一门课上学到的都多。

后来,我又在伦敦加入了一个刚刚开工的项目。在那个项目中,我扮演了另外一种学徒的角色。我的新老板用他的所作所为告诉我:软件开发不仅仅是一项技术工作,同时也是一项人文工作。他帮助我理解了软件开发中与商业相关的这一部分,并教给我如何在拥有一定技术实力的基础上建立起良好的企业人际关系。

从这两次截然不同的学徒经历“毕业”之后,作为一个开发者,我已经比开始时强了太多太多。由于拥有这样一段经验,所以我完全相信:如果要学习一门手艺,与高水平的师傅一起工作是最佳的途径。

正如我刚才说的,本书在“如何训练下一代开发者”方面提出了很有价值的观念。不仅如此,本书还涉及到了软件的哲学。工艺学所针对的是个人的能力:对你的工作,对你个人的发展,对于你的职业,工艺学能给你更多的帮助。它并不干涉你开发软件的工作方式。你可能在通过了CMM 5级的企业中朝九晚五循规蹈矩地工作;也可能为了实现又一个惊天动地的新点子而一周工作100小时,靠咖啡因来驱散倦意。你可以使用RUP、XP或者SCRUM——或者根本不使用任何标准的过程。不管工作如何组织,只有当技艺高超的开发者编写出高质量的、合乎需要的代码时,只有当他们满足客户的需要时,整个软件开发过程才是真正有价值的。方法学无法造就技艺高超的开发者;只有给予工艺学以足够的认可并按照工艺学的指导去实践(当然,还需要留意本书中的其他观点),技艺高超的开发者才可能出现。如果你能花一些时间来阅读本书,来思考Pete McBreen提出的难题,必定会对你自己和你的职业生涯大有裨益。

David Thomas

The Pragmatic Programmers

[1].译注:本书作者Pete McBreen。

前言

用“工艺学”来比喻软件开发,这可以看成是对软件开发的一次追根溯源:优秀的软件开发者们一直都知道,编程的确就是一门工艺技巧。不论软件开发者拥有多少纷繁芜杂、晦涩难懂的知识,但最终左右着应用程序开发的仍是那种不可言说的感觉和经验。举个最简单的例子:也许有人能够了解Java语言所有深奥幽暗的技术细节,但除非这个人能培养起自己对于软件的审美感觉,否则他永远无法真正精通应用程序的开发。而与此相反,一旦某个人获得了那种软件开发的感觉,特定的技术细节就变得几乎无关紧要了。优秀的开发者总是在不断地学习、使用最新的技术和技巧,对于他来说,学习一门新的技术只是软件开发者生涯中的家常便饭而已。

“软件工程”这个词是由NATO属下的一个研究组在1967年提出的,这个研究组还提议召开一次会议,专门讨论“软件所面临的问题”。1968年,由NATO科学委员会主办的这次会议在德国Garmish[1]召开,会议提交的报告就被命名为《软件工程》[2]。在这份报告中,Peter Naur和Brian Randell这样写道:“我们之所以选择了‘软件工程’这个颇具争议性的词,是为了暗示这样一种意见:软件的生产有必要建立在某些理论基础和实践指导之上——在工程学的某些成效卓著的分支领域中,这些理论基础和实践指导早已成为了一种传统教义。”

和他们一样,本书之所以选择了这样一个颇具争议性的书名(并提出了很多颇具争议性的观点),是为了暗示这样一种意见:软件开发的实践者们有必要开始关注软件开发的工艺。软件工艺是如此重要,因为它让我们摆脱“制造业”的隐喻(这个隐喻正是软件工程所带来的),并让我们开始关注从事软件开发工作的。软件工艺带来了另一种隐喻:拥有技术的软件开发者抱定决心要掌握自己所从事的工艺,对自己的劳动成果负责并以之为荣。

软件工艺并非与软件工程或者计算机科学针锋相对,格格不入。与科学和工程学相比,软件工艺是另一种完全不同的教义,但又能与这两者很好地共存,并从中获益。现代的铁匠能够因为更好的工具、原料和知识而获益;同样,软件工艺也能够因为更好的计算机、可复用的组件和更先进的编程语言而获益。铁匠们在自己的工作中融入了技巧和艺术,从而超越了科学和工程学的范畴;同样,软件工艺能够指导开发者生产出优秀的应用程序及系统,因此也可以超越计算机科学和软件工程学的范畴。对于这一论点,最好的佐证大概就是UNIX和现在的GNU Linux了——这两个系统之所以能够获得如此巨大的成功,完全是因为它们的创建者拥有精巧的手艺、高超的技术和无私的奉献精神。

很长的时间里,人们一直试图强迫商用软件的开发适应软件工程的要求。这种削足适履的做法引发了不少的问题,而软件工艺则给这些问题带来了答案。软件工程的发展,很大程度上是为了满足NATO成员国开发超大型国防系统的需要。而商用软件的开发与军用系统、政府系统的开发却有着天壤之别:商用软件的规模通常比较小,并且开发时间通常不能超过18个月。只有极少数商用软件是由超过20人的团队所开发的,大多数开发团队都不会超过10人。对于拥有200人以上的大型团队,软件工程能够很好地解决他们所遇到的问题;但对于“团队中的个人应该如何锻炼自己的技艺”这个问题,软件工程却几乎没有任何论述。

软件工程鼓励在软件开发中使用人海战术[3]。软件工程不但没有解决“如何培养拥有高超技艺的开发者”这个问题,反而试图降低对软件开发工作的技术要求——软件工程认为:只要投入更多的人手,所有的问题都可以得到解决。这实际上就是在暗示:如果可以拥有大量技术水平较低的开发者,那么我们就不需要那些技术超群的“高手”。

尽管人海战术有时能够成功,但最终得到的软件多半也是垃圾:它们臃肿迟钝,总是无法令人满意。用户被炫目的图片和动画搞得晕头转向,但就是无法真正掌握软件的用法。由于无力学会使用整个软件,他们会有强烈的挫折感,并只使用很小一部分功能来满足自己的需要,而更多的功能则根本无人问津。

软件不一定非得要像这样的

我时常看到这样的软件开发团队:他们开发出真正有价值的应用程序,为用户的业务提供了实实在在的帮助,却因为没有遵循软件工程的最佳实践而懊恼不已。其实,他们大可不必这样想。在我看来,唯一能够检验团队能力的标准,就是看他们能否按时发布用户需要的软件,并在随后的时间里不断地补足、扩展这个软件。按时发布第一个版本固然重要,但始终及时地发布后续版本,并保证每个新版本都在原来的基础上有所提升,这可能是更加重要的。

常常有人问我“如何雇佣好的开发者”。面对这个问题,我的回答总是:去找那些成功地开发过几个应用程序,并在交付后仍然留在项目组中直到下一个升级或维护版本发布的开发者。能够交付最初的产品,就说明这个人有能力开发出可用的产品;参与第二个版本的开发则使他有机会反思自己最初的开发方式带来的效果。如果某个开发者把这样的过程重复了3遍,我敢打赌他在软件开发工艺方面已经拥有了足够的技能和经验,这将使他能够继续获得成功。

我把软件工艺称为“新的渴求”。之所以这样说,是因为我发现软件开发社群中的很多人开始盲目地追逐新技术,而忘记了真正重要的东西。软件开发的终极目标是要创建出高质量的、坚固的软件程序,并使之为用户创造价值。现在,我们的当务之急就是要培养出新一代的合格开发者,让他们拥有实现这一目标的能力。

“为用户创建应用程序”的过程曾经是妙趣横生、激动人心的,但软件工程几乎完全抹杀了这种令人愉悦的体验。现在,软件工艺将把软件开发过程中的乐趣和激动重新还给软件开发者。

[1].译注:Garmish,位于阿尔卑斯山区,德国度假胜地。

[2].Peter Naur、Brian Randell编辑,《软件工程》(Software Engineering: A Report on a Conference Sponsored by the NATO Science Committee),NATO,1969。

[3].Steven Levy,《黑客》(Hackers),Penguin Books,1994,p. 88。

第一部分 置疑软件工程

引言

在开发软件时,软件工程是最好的方法吗?

是,也不是。

对于某些项目,软件工程的方法确实很合适;但对于绝大多数项目,它并不合适。人们发明软件工程,是为了用它来解决那些超大型NATO系统项目中的问题。在20世纪60年代末和70年代初,正是这些项目推动着计算机硬件以及以这些新硬件为基础的软件开发技术的发展。

在1968年的一次NATO会议上,软件专家们提出了“软件危机”的概念,并指出:对于大型的、要求高质量的软件应用程序来说,软件工程是使其脱离危机的最佳途径。此后相当长的一段时间里,美国国防部的软件需求一直主宰着软件工程的主流论调。

所以,是的,如果你所从事的是一个真正的大型项目,如果你们自己创造了全新的硬件,并需要为这些硬件开发软件,那么你就应该使用软件工程的方法。来自NATO的经验也应该适用于你的项目。

当然,美国国防部并不是唯一的软件消费者。如今,商用软件、开源(open source)软件、应用程序包、打包软件、交互式电脑游戏⋯⋯这些“新生代”软件早已把软件开发推离了经典的软件工程大道。形形色色软件的涌现提醒我们:现在已经到了该重新审视一下我们的软件开发方式的时候了。

一旦开始重新评估我们的软件开发方式,我们就会很清楚地发现:软件开发并不是一项简单机械的活动,将其看作一种工程学实践是不恰当的。因此,我们需要给软件开发一个更好的隐喻:软件工艺。

第1章 理解软件工程

为了看清软件工程适用(以及不适用)的范畴,我们首先需要对软件工程有一个深入的理解。为了理解软件工程,我们首先需要了解在早期的软件工程文献中提到的那些项目。稍做研究,你就会发现一个令人惊讶的事实:这些文献中几乎没有对商用软件的报告。在所有的案例中,绝大多数都是大型国防项目或者小型科研项目。在这两类项目中,开发者通常都需要面对极其严峻的硬件/软件条件;而在现代的商用项目中,环境通常会宽松得多。

一个非常典型的例子就是美国国防部于1969年至1975年间开发的SAFEGUARD弹道导弹防御系统[1]。“SAFEGUARD系统的开发和部署堪称有史以来最大、最复杂的软件系统。”在项目开始的第一年(1969年),工作量为188人年;到1972年,年工作量已经达到1 261人年;整个项目的工作量共计5 407人年,平均生产率为每人年418条指令。

SAFEGUARD是一个极其庞大的软件工程项目,它也代表了当时软件工程的最高水平。它所使用的计算机硬件是专为此项目而开发的。尽管程序设计工作都是用低级语言完成的,但编码和单元测试阶段在全部工作量中所占的比重还不到20%。系统工程(需求分析)和设计各自占据了20%的工作量,其他的工作量(超过40%)则用于集成测试。

软件工程的悖论

在试图理解软件工程时,我们需要在脑海中牢记下列两点:

像SAFEGUARD这样规模的项目属于凤毛麟角。

但软件工程正是在这些超大型项目(超过1 000人年)的基础上定义的。

同样,Fred Brooks的《人月神话》[2]也是建立在IBM开发OS/360操作系统的经验基础上的。所以,尽管Brooks在书中也提到了“由于人员的分工,大型编程项目碰到的管理问题和小项目区别很大”这一事实,但他的书仍然被用来支持软件工程背后的观点。

这些大型项目是真正的“系统工程”项目。这些项目通常同时包含硬件和软件的开发,其中的硬件是专为与软件协作而开发的。这一类项目有一个共通的特点:在项目的前期,软件开发者需要等待硬件的开发;而在项目的后期,则是硬件开发者在等待软件的开发。软件工程正是在这样一对矛盾中发展起来的。

等待硬件开发时,软件开发者在干什么?

在典型的软件工程项目的前期,软件开发者会有很多的时间。这时,硬件的发明或者设计尚未完成,所以软件开发者有大把的时间来做需求调研,并编写出详尽的软件设计规格书。他们根本不可能提前开始编码,因为用于执行代码的硬件环境根本还不存在(在很多较早的范例中,在这一阶段甚至连编译器和代码加载器都还不存在)。有时,连编程语言都必须到项目的后期才能选定。所以,就算设计规格书已经巨细靡遗,提前开始编码也是毫无意义的。

在这种情况下,“定义一个严格的需求获取过程,并通过这个过程生成详尽的、可复审的、一步到位的需求说明书”的做法就是有意义的。需求文档一旦完成,就可以交给设计团队;而设计团队则可以根据需求文档编写出极其详尽的设计规格书。我们都知道,硬件开发是相当费时的。就连为软件开发团队设计出一个可用的工程原型,也需要相当长的时间。所以,细致入微的设计复审也是软件开发过程中的一部分,因为软件设计团队有足够的时间来检查他们的设计。

得到可用的硬件之后,软件开发者如何加快交付的速度?

对于这个问题,最简单的答案就是:“投入大量的人手。”这也就是Steven Levy所说的“人海战术”,从SAFEGUARD项目的人力资源统计图中也可以很明显地看出这一点。一旦硬件能够投入使用,软件开发者就应该立刻动手将详细设计规格转换成代码。为了获得最高的开发效率,还需要对代码进行复审,以保证其完全与详细设计规格相符,因为任何的偏差都可能导致下游的集成阶段出现问题。

这个阶段需要大量的人手,因为整个项目都在等待软件的编码和测试。所以,从设计到代码的转换过程越快越好。早期的软件工程项目倾向于用大量的程序员来编码,但后来人们将关注的焦点转移到“使用CASE工具自动从设计生成代码”上面。之所以出现这样的转变,是因为在完成编码之后,项目组仍然需要排除代码中存在的大量错误才能让整个系统正常运转。如果代码能够从设计规格自动生成,那么集成阶段的问题就会大大减少,项目也可以更快地完成。

传统开发过程的内蕴

软件工程项目需要大量的文档。在整个项目的过程中,需要3类不同的技术人员:

分析师,负责编写需求文档;

设计师,负责创建设计规格;

程序员,负责编写代码。

在每个阶段,每份文档的作者都必须在文档中加入额外的细节,因为他们无法知道随后将要阅读这份文档的人是谁。由于无法假设阅读者的知识背景,所以唯一安全的办法就是:将作者所知道的所有细节、所有交叉引用都写在文档中。然后,文档的复审者必须仔细浏览整个文档,以确定它是完善并且明白无误的。

完善的文档也带来了另一个难题:当在实现阶段需要对需求和设计作出修改时,团队成员必须修改所有相关的文档,以保证文档与真实系统之间的一致性。软件工程项目解决这个问题的办法是:确保从需求分析到代码实现的整个过程是完全可回溯的。不论在任何时候需要作出修改,这种可回溯性都将保证相关的文档和组件能够被发现并被更新。

这种文档驱动的开发方式也影响项目中人员的工作方式:设计师不愿意主动置疑分析师的文档,而程序员对设计方案的置疑或改进建议也是不受鼓励的——对于任何一份文档的修改都需要付出高昂的代价,因此所有的修改都必须受到严格的控制。

要想控制对文档的修改,一个很好的办法就是:定义一个分层的项目人员体系,将分析师放在最顶端,设计师次之,程序员位于最低的地位。而维持这一结构的办法则是:将优秀的程序员提拔为设计师;同时让优秀的设计师担任分析师的角色。

软件工程的当代解读

在过去的30年中,软件工程社群一直用“工程学”这个略显呆板的比喻来看待软件开发过程。现在,软件工程已经成为了计算机专业学生的一门必修课。在各个大学的计算机系中,软件工程也是一个活跃的研究领域。人们最关注的是软件工程项目中那种确定的、可重复的开发方式。按照IEEE的定义,这种方式就是:

软件工程是指采用一种有组织、有纪律、可计量的方式来开发、使用及维护软件,也即在软件领域中对工程学的采用。[3]

对于强调安全性的软件系统,这种有组织、有纪律、可计量的开发方式已经被证明是非常有效的。例如,为航天飞机编写软件的团队就使用这种开发方式,并成功地获得了缺陷率极低的软件系统:

在这个程序的最后3个版本(平均代码长度为420 000行)中,每个版本只有一个错误;在其最后11个版本中,总共只有17个错误。同等复杂度的商用程序将会有5 000个错误。[4]

但是,在这样的过程中,其他的约束条件则不得不被放松:

金钱不是关键的约束条件:项目组每年3 500万美元的预算对于NASA来说不过是九牛一毛。但是,这个预算额就意味着每行代码价值 1 美元。这使得该项目组成为了全美国最值钱的软件组织。[5]

从工程学的角度来说,这是一个恰当的利弊权衡。面对性命攸关的软件,人们毫无疑问会慷慨地用一切资源来确保系统不出错。但是,对于那些出错的代价相对较低的软件,又应该如何去开发呢?

“足够好的软件”——庶民的软件工程

对于某些软件来说,快速地开发出具有丰富功能的应用程序才是最重要的。这种观点的核心思想是:用户能够容忍程序中的错误,因为他们能够得到很多无法从其他地方获得的有用功能。正如Edward Yourdon所说:“我将在6个月之内交付一个系统,其中会有5 000个错误——但你一定会非.常.高兴!”[6]

实际上,“足够好的软件”只不过是软件工程思想的一个衍生物,它的出现完全合乎逻辑。它体现出了人们在资源、进度、功能和缺陷等各方面作出的工程学权衡。航天飞机的软件最重视安全性,因此必须尽可能地减少其中的缺陷,并同时接受项目组为了提高质量而提出的资源、进度方面的要求;另一方面,打包的商用软件(例如文字处理软件、Web浏览器等)则要求开发者快速实现大量的功能,因此开发者就会很自然地作出“节省排除已知缺陷的时间从而压缩进度”的工程学权衡。这种权衡的核心思想是:对于某些类型的已知缺陷,花时间去排除它们并不经济。

软件工程适合你的项目吗?

需要同时开发全新的软/硬件系统的系统工程类项目显然是适于使用软件工程方法的,很多国防项目和航天项目都可以归于这一类。如果我要乘坐一架数控驾驶的航天飞机飞向太空的话,我一定会希望飞行控制软件的开发和检验是以一种“有组织、有纪律、可计量的方式”进行的。起码,如果听说这个软件是“由出价最低的软件公司开发的”,我的心里一定不会太好受。

另一方面,如果你的企业需要开发大型的、打包销售的消费类软件,并且又善于作出恰当的工程学权衡,那么你很可能会使用“足够好的软件”这种方法。这类软件工程成功的秘诀就是以量取胜:消费类软件的市场充满了竞争,消费者决定是否购买某个软件的依据不是细致的比较,而是别人的评论和软件厂商的市场宣传,因此软件厂商只有以较低的价格卖出极其大量的产品才可能占据市场。

除了上述两种项目之外,对于其他类型的项目,你都需要寻找一种软件工程的替代品,因为软件工程并不适合于你的项目。

第2章 软件工程的困境

软件工程存在的最大问题就是:它假设那种“有组织、有纪律、可计量的开发方式”是唯一可行的方式。软件工程实际上是把工程学的隐喻强加于软件开发之上,从而使我们一叶障目不见泰山,看不到其他开发方式的存在。有一个例子能够将这一问题彰显无遗,那就是软件工程中的“缺陷可能性”和“缺陷排除率”这两个概念:

缺陷可能性:软件项目中预期可能存在的全部错误和缺陷。

缺陷排除率:在将软件项目发布给消费者之前,被排除的缺陷占潜在缺陷总数的百分比。[7]

这种机械的观点忽略了一个事实:越好的程序员,所犯的错误就越少,并且发现错误也越快。教条主义的软件工程使我们忘记了软件的本质:真正决定项目成败的,是作为个体的程序员的技能、知识和经验

Bill Curtis等人对大型软件工程项目进行了一组意义深远的现场调研。从这些调研结果中,我们可以清楚地看到杰出的设计师作为个体对整个项目所做的贡献以及他们的重要性:

每个项目组中都会有这样的一两个人。他们通常是资深系统工程师,他们在系统的设计中承担主要责任。在我们研究过的所有项目中,大约有三分之一的项目存在这样的情况:某一个人对整个项目起主导作用,项目的发展方向由他决定,项目的成果依赖于他的工作成果。有时候,项目组的其他成员甚至会将他称为“救世主”。这些真.正.杰.出.的.设.计.师.拥有的应用领域知识比其他同事丰富得多,因此,在我们的研究结果中,他们显得格外出类拔萃。他们是项目的一种稀缺资源。[8]

随后,这份研究报告还写道:

软件开发的传统观点往往认为:软件项目的成败不应该依赖于某个关键人物的发挥。但是,很多成功的大型项目的经验却告诉我们:这种理论一旦被用于实践,可谓贻害无穷。优秀的设计师拥有的领域知识不论在深度上还是在广度上都胜人一筹,而这些知识很难通过一组设计过程获得。所以,优秀的设计师的确是不可或缺、不可替代的。[9]

在期盼通过工程学的超度而达到“有组织、有纪律、可计量的开发方式”时,我们逐渐地迷惑了自己的头脑。其实,我们应该讨论的不是“项目的缺陷可能性”,而是“开发者的缺陷可能性”。

道理很简单:优秀的设计师所犯的错误要比他的同事们少得多,因此优秀设计师的“缺陷可能性”就比较低;同时,优秀的设计师也能够更快地发现系统中的缺陷,因此他的“缺陷排除率”也比较高。对此,Fred Brooks早已作出了精辟的论断:

……系统应该由尽可能少的人员来开发。实际上,绝大多数大型编程系统的经验显示出,一拥而上的开发方法是高成本的、速度缓慢的、低效的,开发出的是缺乏概念完整性的产品。……得出的结论很简单:如果在一个200人的项目中,有25个最能干和最有开发经验的项目经理,那么开除剩下的175名程序员,让项目经理来编程开发。[10]

简而言之,软件工程的关键问题就在于:它使我们忘记了“是人来开发软件”这样一个简单的事实。软件工程含蓄地给了我们一个承诺:只要能定义出一个有组织、有纪律、可计量的开发过程,任何人都可以成功地完成软件开发。可惜,这只能是一个梦想。正如Curtis的调研报告所表明的:就算有了一个理想的过程,想要获得项目的成功,出类拔萃的开发者仍然是必不可少的。所以,我们有必要认真考虑这样一个问题:如何培养软件开发者,才能使他们也有可能出类拔萃?不过,在回答这个问题之前,我们需要先解决另一个问题:所谓“有组织的软件开发过程”,究竟意味着什么?

“有组织的、可计量的”软件开发过程现实吗?

对于软件开发来说,所谓“确定的、可重复的过程”真的能够达到吗?SCRUM软件开发过程[11]的创始人曾经这样说道:

如果某个过程能够完全确定下来(即能够了解过程所涉及的所有细节,从而将其设计为可以重复地多次运行,并且完全能够预测其结果),那么该过程就被称为“确定过程”。从理论上来说,一切确定的过程都可以被自动完成。另一方面,如果人们并未了解某个过程中的所有细节,只是大致地知道在某些初始条件下、通过某些调节和控制就能得到想要的结果,这样的过程就被称为“经验过程”。[12]

按照这个定义,软件开发不是一个确定过程。实际上,我们所能希望获得的最好结果也就只是一个经验过程而已。之所以这样说,是因为所有的软件需求都来自于人。需求的获取无法自动完成,开发者必须和用户彼此沟通才可能了解用户真正的需求。同样,用户也必须在与开发者的交流中了解项目中存在的技术局限性和克服这些局限所需要的开销,从而不断调整自己要求的功能,使软件项目的性价比达到最佳。

在软件开发者了解用户的需求之后,下一个问题就是:如何将这些需求记诸文档。在一个确定的开发过程中,我们应该从一开始就整理出完整而明确的需求。可是,在一般情况下,要想做到这一点难于登天。Gause和Weinberg曾经非常精辟地阐释过这个问题[13]:对于一个最简单的句子,“玛丽有一只小羊”,根据语句的重音不同,就可能有截然不同的含义。

玛丽有一只小羊。(是玛丽的羊,而不是约翰的。)

玛丽有一只小羊。(她的确有这只羊,不是骗人的。)[14]

玛丽有一只小羊。(她只有一只羊,没有更多的。)

玛丽有一只小羊。(这只羊真小,小得令人吃惊。)

玛丽有一只小羊。(她拥有的是一只羊,而不是火鸡。)

从这个例子中,我们就可以清楚地看到:对于任何一种自然语言,实际上根本无法做到精确无误的地步。需求获取要求开发者与用户保持紧密的联系,即使在需求文档成型之后,开发者也需要不断与用户交流,因为谁都无法保证需求文档中所写的内容不会有多种不同的解释。由于自然语言与生俱来的不精确性,你不可能喜欢一个确定而僵死的需求获取过程。

我们当然可以将软件开发中的某些部分自动化,不是吗?

当然,我们可以。但只有确定的过程才能被自动化,而那些需要大量人际交流的部分则无法被自动化。现在的确有很多这样的工具存在,它们将软件开发中的一些小规模的、精确定义的行为自动化了,它们对于提高软件开发的效率大有裨益。例如,配置管理工具和构建工具能够自动地将高级编程语言的代码转换成相应的低级语言代码甚至机器代码。我们能够实现这样的自动化工具,是因为我们可以精确地定义这个转换的过程。

但是,我们必须记住:在软件开发中,绝大部分可以被自动化的工作都已经被自动化了。也就是说,我们已经拥有了软件开发所需要的绝大多数工具—唯一缺少的就是使用现有工具的技巧和能力。仍然以构建工具为例:自动化的构建过程可以在无人值守的情况下自动运行,并将构建过程中的失败信息通过电子邮件通知关键开发者,从而极大地减少构建的工作量。可是,我所观察过的大多数商用软件开发项目都没有这样的自动化构建过程,因此,拥有这一能力的项目组就占了很大的优势。而且,自动化构建还是项目的一张安全网:每当项目的核心源码被修改时,整个应用程序就会被重新构建,随后自动运行回归测试,以确保这次修改没有造成任何破坏。如果一个项目没有这样的安全网,我简直无法想象如何在其中工作。

当我们将软件开发中一个又一个的部分自动化以后,我们却发现:软件开发仍然是一团乱麻,其中的复杂性和困难性并没有消失,只是换了个形式而已。只有对那些能够完全了解的问题,我们才能用系统化的方式来解决,因此软件工程就将我们的注意力集中到了软件开发中机械的部分,进而忽视其他非机械的部分。所以,尽管我们有了高级语言的编译器和解释器,尽管我们有了各种各样的新技术,实际上仍然没有任何办法帮助我们设计用户真正需要的东西,而且能够帮助我们找出用户的真实需求的工具或技术更是少之又少。

“足够好”的软件开发方法的危害

在软件变得越来越重要的同时,它们是否也变得越来越臃肿、错误越来越多?我还记得,在过去的日子里,整个文字处理软件可以装进一张软盘;现在,我们已经看到不少的应用程序连一张光盘都装不下了。有很多打包的应用程序,它们每次发布新版本都会要求用户购买更多的内存或者更快的计算机,而且其中大多数的新特性根本不能很好地工作。

你的软件是否越来越好看,却越来越难用?有时,用户们甚至会想:开发者是不是花了太多的时间在应用程序的观感上,以至于忘记了考虑别人怎么使用这个程序。

项目是否用掉了比预先承诺更多的时间,而交付的成果却更少?“雾件”(vaporware)是软件工业给我们的词典加上的一个有趣的词汇。软件产品的前几个版本也许还能够快速发布,但每次发布改进版本所需要的时间越来越长,软件也变得越来越复杂。随着复杂度的上升,“将缺陷减少到可接受的程度”也会耗费越来越多的时间。

当你报告一个缺陷时,软件开发者是否显得对你的需要漠不关心?现实就是如此残酷:在“足够好”的开发方式中,这种冷漠是必要的利弊权衡。如果一个缺陷仅仅影响一小部分的用户,那么花费人力来修复这个问题就是不经济的。如果你够幸运的话,你将可以找到其他的办法来绕过这个错误,并继续等待下一个版本发布。

“足够好”的软件开发方式是有害的,因为它继承并发扬了“缺陷是不可避免的”这一荒诞不经的理论。事实正好相反:缺陷之所以存在,恰恰是因为我们采用了这种疯狂的开发方式。“足够好”的软件开发的特点就是:近乎疯狂地编码,在最短时间内得到一个“拥有全部特性”的应用程序,随后是一个若有若无的测试、排错阶段。开发者哪怕只是动一动“排除所有缺陷”的念头也会被认为是浪费力气,因为一大半的特性很可能就实现在现有的错误之上。由于“足够好”的开发方式将编码和测试分离成了两个截然不同的阶段,所以用这种方式开发出的应用程序中必定会包含大量的缺陷。

发.布.含.有.已.知.错.误.的.软.件.,.这.不.是.一.个.好.主.意.。即使所有已知的严重错误已经被修复了,“发布含有已知错误的软件”这种做法仍然会向用户传递错误的信息:开发者不知道如何修复软件中的错误,甚至开发者根本不关心软件的质量和可靠性。[15]在其他行业中,你不会看到这种情况。你可以随便找一家汽车代理商,他们会告诉你:如果有其他高可靠性的产品,销售低可靠性的产品会对自己的声誉造成多大的损害。

谁能取代软件工程?

软件工程的替代品其实还不止一个。在过去的几十年中,人们尝试用很多种不同的方式来开发软件。不过,在开始讨论这些问题之前,我们必须首先摆脱机械刻板的“软件工程”这个隐喻,去了解软件开发的真实本质。

相关图书

有限元基础与COMSOL案例分析
有限元基础与COMSOL案例分析
程序员的README
程序员的README
现代控制系统(第14版)
现代控制系统(第14版)
现代软件工程:如何高效构建软件
现代软件工程:如何高效构建软件
GitLab CI/CD 从入门到实战
GitLab CI/CD 从入门到实战
科学知识图谱:工具、方法与应用
科学知识图谱:工具、方法与应用

相关文章

相关课程