定论——软件开发的方法论探讨

一、消除隐喻

1、隐喻

软件开发这件事情,出现得很晚。距今只有几十年的时间,关于它的定义,我们可以简单地说:“就是把软件做出来。” 这基本上等于什么都没有说。而软件开发究竟是怎么回事,大家也没有搞明白,于是隐喻就派上用场了。当你要向一个完全没有概念的朋友,解释什么是软件开发的时候,你无法向解释建筑工程那样把他带到现场去看——案件开发的现场,你的朋友会以为软件开发就是一群人坐在电脑前面打键盘——你只能打比方:它就像是造一幢楼,有基础,有结构,有可以使用的房间,在这之前必须要设计,最后一样要通过验收,最终用户就能够住进去——哦,不,是可以使用软件的各种功能。

这样,你用上了一个隐喻:软件开发就像建筑工程,或许极可以称之为软件工程。还有其它一些隐喻:比如手工作坊与软件工艺。我们不会说建筑工程就像什么什么,它们都有自己鲜明的特点,不需要通过像什么什么来解释。但是软件开发,还是太年轻,也缺乏鲜明的特征,只能借助隐喻,我们才能向人们解释它。在这条路上,很多人都已经走得太远,隐喻不但被用来向外行解释什么是软件开发,居然被用来说服自己人,软件开发就应该像那个比喻的对象一样,具有类似的规范、过程、特征以及方法论。但是,比喻只能是比喻。软件开发的方法论,只应该从软件开发的本质推导出来,而不是从一些隐喻里抄袭过来。

2、另一个隐喻

佛教有一种说法:“佛法不过是一条渡船,过河之后,你就不再需要它了。”寻求软件开发的本质,也许还是需要隐喻的帮助,只是这些船能不能把你带到彼岸,要仔细辨别。

设想这样一个场景:在公安局的一个办公室里,你的对面坐着一个目击证人,而你是一个犯罪肖像画家。这个证人在讲述他还记得的罪犯特征,你一边提问,一边在纸上沙沙的画着。一开始的提问与回答总是很概要性的。“圆脸”“不,很瘦的长脸”;“戴眼镜?”“是的”。在纸上出现了大致的轮廓之后,对话变得比较琐碎,“眼睛再小一点?”“鼻子比这个大一些。”渐渐的,证人的话越来越少,而且不断地端详着纸上的那个人,而你还在做一些细小的修正。突然,证人激动地大叫起来:“就是他!就是这个人……”于是,你的任务完成了!

这个过程像不像软件开发呢?有人也许会说,嗯,软件开发就是这样的。不!其实软件开发,并不是这样的,它应该是这样的……

你的朋友,晚上到你家来了。“我昨天晚上做了一个梦,梦见了我这辈子见过的最美的女孩,你帮我把她画出来吧。”“她的脸是……”在一段又一段如梦如幻的描述之后,你开始画起来,过程与前面有点类似,但是,似乎你的朋友没有停下来的迹象,他不断的要求你改进,希望这个她能够更加完美。终于,他放弃了:“就这样吧,虽然不是她,但是已经很像了。”你长吁了一口气,但是,你的朋友疯了,他恳求你把这个女孩变成一个活人,能跑能跳,能够跟他交流,而且还能够爱上他。没想到,其实你不是人,而是上帝,而且你大发慈悲,竟然真的满足了他的要求。终于,他满意地回去了。但是,几天之后,他又来了,他居然因为还不够满足,又来了!“上帝,”他恳求道,“你能不能够帮我把她改一下,当我……”随后的日子里,他不断地找到你,要求你再完善完善他的女人。直到有一天,你发了一道闪电,劈死了这个贪得无厌的家伙。

不不,最后这一幕没有出现,因为根据软件开发及维护合同,你不能劈死你的客户!(我敢打赌,是个程序员,就想过这么干。)如果这个合同签得不够好,他真的有可能向你提任何要求。

3、消除隐喻

这个隐喻怎么样?这是对软件开发过程的一个好的描述吗?不,它还不够好,而且我们不可能通过修正完善这个隐喻,来得到一个对软件开发的准确的描述。事实上,所有的隐喻都不够好,都会扭曲软件开发过程的真相,都会使我们对软件开发的过程产生误解。

为什么会这样呢?为什么一个挺像软件开发的隐喻会最终误导我们呢?原因在于一个隐喻是一个完整的场景,这个场景中有很多相互交织的“概念要素”。当这些要素有很多在软件开发中出现时,我们就会认为这个隐喻很贴切,而当一个隐喻越是贴切时,这个隐喻中的其他一些在软件开发中不存在的要素,或者与软件开发相矛盾的要素,就会打扰我们的分析,干扰我们的判断。使得我们不再思考软件开发本身,而是将思考建立在某个隐喻的场景中。这样思考得到的结果,肯定存在着误导的可能。再由于不同的隐喻互不相容——你无法想象一群工匠去建设现代化的高楼大厦,他们最多只能造些平房——因此,建立在各种隐喻基础上的软件开发,至今没有找到适合自己的方法论,倒是不同的隐喻之间互相打得火热。

4、分析各种现有的隐喻:

1)工程隐喻

在各种隐喻中,建筑工程与软件开发的关系最为密切,这个隐喻与软件开发的相似之处最多,因此影响也最为深远。这个隐喻有四个要点:分解、分配、设计和阶段化。

分解是一种极为深刻的思想,将整个过程分为几个阶段,将整个任务分解为几个子任务,将系统分解为多个层次,多个模块,将需求划分为多个类型等等。这样的思路,是解决复杂问题的唯一正确的方法,一团乱麻的需求、任务、项目、设计,根本不可能成功。但是分解也意味着它最好第一次就划分正确,当任务被层层分解,变成了很多很多的子任务、模块、子模块、类的时候。你发现有一个子任务的分解有问题,修改的困难可能极为惊人,而软件开发,在第一次就划分正确的情况,几乎绝无仅有。

分配与分解一样,是工程隐喻所特有的,当一个需要完成的系统,已经被仔细的分解之后,分解的粒度会达到一个人能过独立完成的范围,然后根据现有的资源以及任务的前后依赖关系,合理的分配给各有不同能力和特长的人,没有这样的分配,项目同样会一片混乱,而这个隐喻还包含一种(支配关系),存在分配的人与被分配的人,层层分解的任务与层层分解的人力资源,使得整个项目成为一个严密的金字塔结构,而这样的结构,往往使得项目的应变能力与可能性,随着项目的扩大而缩小。

基于以上的两个要点,工程隐喻极为顺理成章的推出了这样一个结论:“必须严格的控制需求的变更,如果可能,将所有的变更都顶回去。”纯正的软件工程的思想中,任何需求的变更都是不受欢迎的。

设计极为重要,无论是对于建筑还是对于软件开发来说,都是这样。但是设计与设计不同,在建筑行业,不体现设计师理念的建筑,会被称为没有灵魂的“水泥块”。但是在软件开发里,如果开发人员老是想着往程序里加入自己的东西,会被称为过度设计。但是由于软件开发对于建筑工程的模仿,过度设计变得比比皆是。

在建筑工程中,有着极为清晰的阶段划分,分析、设计、施工、验收。最早的软件工程,就是完全模仿这样的阶段而执行的。这样的模仿,后果是严重的,因为这样的阶段不是软件开发的特征,强行套用,大多失败。随后的改进似乎总也跳不出这个思维模式,就像用无数的直线去拟合一条曲线,用N多个正方形去拼出一个圆形。比如说螺旋式开发,在一个螺旋中,还要搞出四个象限,使得软件开发的过程,不断的重走这四个阶段。但是,软件开发的过程,真的是像建筑工程一样吗?

2)流水线隐喻

产生式编程和MDA,是所有“银弹”承诺中,最为大胆的两种。如果有一天世界大同,万物升平,人间与天堂无异,那应该就是MDA的时代来临了。这两种思路的理论依据(如果这能称之为理论的话)何在呢?其实还是一个隐喻:流水线。当然他们不会直接用普通的流水线来做比喻,而是一种比现代工业中最为先进的柔性制造流水线还要先进的“超级无敌自定义流水线”。用户(对,就是最终用户)可以选择、定义并且画出那个“软件装配图”(UML之类的表示方法),就能直接组装出用户想要的软件。但是,这样的隐喻其实无法用于软件开发,甚至无法用于工业生产的大多数领域。在工业领域,大多数流水线 还是用来生产有限种类的产品,种类多到一定程度之后,流水线的效率根本无法体现。当然成本优势也无法体现。这还是一个零件的粒度问题,大粒度的零件组合,使得生产的可能种类减少,而小粒度的零件,又使得装配成本与效率无法体现,这样的两难,在软件开发上同样存在,而且更加严重,所以这颗子弹,不可能是“银弹”。

3)舞蹈隐喻

CMM本身不需要隐喻,它的理论基础来源于纯正的软件工程,所有软件工程有关的隐喻,CMM都用得上,但是CMM有它自身的特点,主要是在CMM的实施方面。我看到过一个关于CMM实施的隐喻:软件开发就像跳舞,软件过程改进就像是舞蹈编排,软件开发人员在过程改进专家的知道下,就像舞蹈演员在舞蹈编导的知道下,学习新的节奏、动作。最后开发出令消费者满意的软件产品。就像舞蹈演员为观众带来出色的表演。这样的隐喻,为一个巨大的咨询市场开辟了道路;最天才的舞蹈演员,也不能没有编导的知道,所以想要公司提高CMM等级,就必须找专家来做咨询,果然巧妙!但是这样的隐喻,却经不起推敲,舞蹈编排过程中,演员们排练的目标是达到编导的要求,如果演出的效果不好,自然由编导负责。但是软件开发过程的改进,如果也是为了博得咨询专家的满意,到时候软件开发出来不赚钱,那些专家可不会负责。他们早就赚到咨询费,走人了。关键问题在于,过程改进只能是一种手段,它本身不能成为目的,更不能想当然的认为,完美的过程就一定能带来完美的产品。舞蹈编导不是观众,没有一个编导敢保证自己的这次创作,一定能赢得观众的好评,但是为什么现在CMM专家,就敢作出这样的保证呢?当舞蹈演员在一个“三角形的舞台上”,完美的跌落的时候,谁会为这样的悲剧负责呢?

4)工匠、工艺隐喻

说到工程隐喻,现在大家自然会想到最近出来的《软件工艺》这本书。如果工程的隐喻有问题,那么工艺怎么样?如果工程师的隐喻有问题,那么工匠怎么样?按照软件工艺的说法:“如果项目中的成员不具备执行项目过程所必备的技能,那么纵有世界上最好的过程,也无法挽救项目失败的命运;与此相反,真正优秀的开发者,能够让任何过程,发挥最大的作用。”真的就这么简单吗?

工匠与工艺的隐喻,与工程相对,但是这样的对立,并非如《软件工艺》所理解的那样,是由于不同的复杂程度而做出的不同的选择。如果2000个人年的项目,我们应该采用工程的隐喻,5个人年的项目,我们应该采用工艺的隐喻,那么50个人年呢?500个人年呢?我们是不是有可能将两种不同的隐喻像调鸡尾酒一样,选取适合的比例,然后调制起来呢?这样具有的“颠覆性”的理论,我想作者也没有考虑过如何与工程隐喻相调和吧?

在工艺隐喻中,还有几个特点,质量、培训、高手。

工艺隐喻,意味着工匠(程序员)会在自己的作品上签名,并终生为之负责(这与XP是有区别的)这样就能保证质量。但是我们知道,手工制作就意味着质量无法保证,第一次与第二次不同,第二次与第三次不同,现代工业比起手工业来最大的进步,就是能够保证一个始终如一的质量水平。所谓为自己的作品负责的荣誉感,最多只能保证我能够在“事发之后”找到人来修补,却不能保证我免受这样的损失。软件质量更多的取决于一个开发团队的能力,而不是他们愿意为之负责的决心与荣誉感。如果真的那么简单,中国男足立了那么多次军令状了?早就该有成效了吧?

培训开发人员,当然是非常重要的,但是现在软件开发中较多使用的“新手”,并非“工程隐喻”的罪过。作者设想的学徒的过程,也并不与软件工程相矛盾,这在日本的软件工程实践中,可以得到证实。不客气的说,这样的浮躁,不是软件工程的责任,而是文化的问题。可悲的是,中国的软件产业,较之美国,更为浮躁。

高手是宝贵的,但同样也是稀缺的。一个公司或者一个项目团队,不可能全由高手组成,再者,对于一个项目来说,所有的活都让高手来干,也同样是浪费。在这里还要指出作者的自相矛盾之处。一方面,作者强调“师—徒”式的培训,另一方面,又想把低手从公司里赶出去。那么究竟该怎么做呢?如果一个项目内,低手比高手还要多(这是几乎是必然的)。这样的项目应该如何组织呢?任务如何划分呢?作者没有告诉我们。因为在工艺里面,学徒做的可能是毫不重要的,甚至是重复的劳动,只是为了学习。但是在软件企业,谁来为这样的学徒买单呢?

工艺的隐喻,新则新已,好就未必。这本书,就是那种“用隐喻来思考的产物”。真要照做,只怕危险。

5)敏捷的场景

敏捷开发与其它模式不同,它似乎没有隐喻,但是,还记得我们是如何定义隐喻的吗?一个隐喻是一个完整的场景,这个场景中有很多相互交织的“概念要素”。 当这个场景中多出了与软件开发无关的要素时,就会误导我们。敏捷开发是一个逼真的场景,这个场景不是像软件开发,它就是软件开发,它没有多出任何东西,因此,这样就完美了吗?不,它却少了很多要素。当一个逼真的场景,向你描述了一个成功的,但是却却少了很多要素的软件开发项目时,这样的场景同样会产生误导,会使你认为其他的要素,都是不重要的,至少是可以在大型项目中才需要考虑的。我说的要素,并非CMM的KPA,或者RUP里的关键活动,然后通过剪裁就能得到XP那样的要素。而是指关键的概念,缺少关键概念,故事就会显得虚假,那么在敏捷项目中,缺少了什么呢?时间概念,成本概念以及分工概念。

在一个又一个的迭代周期中,什么时候,项目算是完成呢?这个完成,由谁来决定呢?似乎敏捷开发面对的是一个User Story集合,多一些,少一些,都没关系的。如果用户给定时间,功能的多少,就得由开发人员决定。反之,如果用户要求必须数量的功能,开发时间的多少就得由开发人员决定。这样的项目,可以说简直没有压力,这是咱们梦寐以求的项目,但是这可能吗?

再说成本概念,同样的道理,合同是在开发开始之前签订的,但是按照敏捷开发的场景,能开发出多少东西,需要多少时间,都是不一定的。那么成本如何确定?如果成本无法确定,这个合同可能就会有一方要吃亏,这样的合同,谁去签呢?

再说分工概念,敏捷开发是程序员提出的,而且完全是从程序员的角色出发,在他们的故事里,除了用户,就只剩下了程序员,你也许会说,还有项目经理呢!但是,那只不过是一个名称而已,他不过就是一堆程序员里最有权威的那个。那么其他角色呢?你在敏捷开发的故事里,看不到界面设计人员,看不到独立的、专职的测试人员,看不到数据库管理人员(随着设计的浮现,也许项目进行到40%时,程序员中会有一个人,转而承担较多的数据库管理的职责,但是这并不一定)看不到产品经理,看不到用户手册的编写人员,看不到客户培训人员(XP认为客户会和程序员一起工作,但是那些没来的可能谁去培训呢?)也许XP的支持者会说,“嗨,我们又不是要开发巨型项目。”但是我要说的是:“不管有多大的项目,一定会有不需要、也不应该程序员做的事情。”作为一个软件开发的方法论,就必须包含对这些工作的探讨,一个完全从程序员本位出发的,不考虑其他工作的方法论,不是一个完整的方法论,这样的场景如果被普遍模仿的话,也是相当危险的。

6)银弹隐喻

《没有银弹》如此著名,以至于无论它的赞同者还是反对者,都无法回避它的存在。但是银弹究竟是什么呢?“没有银弹”究竟意味着什么呢?

首先,“银弹”是一个隐喻,它的本意是能够杀死人狼(一种怪兽)的武器。用在软件开发里,银弹是什么,用通过追问“什么是软件开发中的人狼”来得到答案。在一个项目中(在一个村庄里),出现了一个困难(出现了一头人狼),如果任由困难存在,项目就会失败(如果没有办法赶走人狼,村民就会受害),一种方法出现了,解决了这个困难,项目成功了(银弹出现了,打死了人狼,村民获救了)。所以我们可以这样理解:银弹就是能够保证项目成功的方法。但是,如果Brooks真的这样简单的推出自己的结论,那么大家都会说;“废话,谁不知道,没有一种方法能够保证项目的成功?”Brooks的水平当然远不止此。但是很多人对《没有银弹》的理解,却事实上到此为止了,然后他们就拿着这个结论,四处“传道”开来。

Brooks更进了一步(或者说退了一步),他将保证项目成功的目的,弱化为提高项目效率的目的,并且给出了一个看起来能够量化的标准“单一技术,十年之内,提高十倍以上的效率。”(可靠性和简洁性根本无法量化,咱们先不讨论)

但是,我们知道,如果一个论断无法证实,又无法证伪,这个论断就毫无意义。那么我们如何能够检验他的这个论断呢?首先我们要能够明确,什么是单一技术?软件工程算单一技术吗?CMM体系算吗?CMM里的一个KPA呢?UML算吗?设计模式呢?XP呢?还是XP中的结对编程呢?怎么才算单一?没有界定!也无法界定,包括Brooks,也不能告诉我们,什么算单一技术?

然后我们还要确定,如何比较开发效率,如何量化?严格的说,必须证实两组能力,知识水平,人数,了解的信息都完全相同的人马,在互不交流的情况下,同时开发一个项目,都达到了一组项目的目标(即不是不够,也不是超过),然后两组人的开发时间,是否相差十倍。

再者,当我们要证明单一技术的功效时,必须保证这两组人马只在这一项技术上有区别,其他都一样。

最后,当我们要证明十年之内的差别时,还要保证十年后的这组人马,与十年前的那组人马使用相同的软件、硬件设备。(十年前是什么操作系统?WIN32?CPU呢?486?)这样的研究,才能够算是精确的验证。但是这样的验证,没有,也不可能有人去进行,自然这样的论断也就毫无意义!

可笑的是,居然有人,当真去寻找银弹的证据,并且兴奋的宣称找到了,最近还有一家著名的公司,出版了一本的著名的杂志,名字就叫《银弹》!但是,最可笑的还在于,Brooks居然还写了一篇《再论没有银弹》,宣称自己的论断,已经基本上成立了。

如果事情到此为止,那么Brooks也不过就是跟大家开了个玩笑罢了。但是Brooks更进一步指出:“软件开发分为根本问题与次要问题,根本问题占软件开发的90%的比重。而且很难被很好的解决。”一方面,我们要说:“这样的认识很有必要”,另一方面,我们也要说:“这样的论断,毫无疑义。”因为它既不能被证实,又不能被证伪。90%从何而来?如何证实?我们无法得知。我相信,10年,10倍,根本就是他随口说出的一个数字,同样的,90%也不过是一个“印象”。当不得真,作不得数,也无法用来指导我们的实践,更无益于我们提高软件开发水平。这样的玩笑文字,竟然风行世界,备受瞩目,的确是软件开发的方法论,还处于蒙昧的“隐喻时代”的最好证明!

二、追求定论

这篇文章的标题就叫定论,那么什么是定论呢?就是不再有异议的结论。就是每个人都能同意的结论。A方法比B方法好,好在哪里?好多少?为什么好?我们追求定论,就是追求一种有效的比较和评价标准。

软件开发有那么多方法,有那么多过程,那么多“最佳实践”,但是却从来没有定论,为什么没有定论呢?因为软件开发的“方法学”还处于蒙昧的“隐喻时代”,各家各派,都从自己的隐喻出发来看问题,所谓“鸡同鸭讲”,指的就是这种情况。

但是追求定论的努力,并不是从我才开始的。在此之前也有人追求过,这样的努力,统称为——“软件度量”,这当然是典型的西方观点:能够量化,就能够比较;能够比较,就能够改进。这样的观点,一点没错,但是还少了前面一句,首先要理解,才有可能量化。如果我们不能真正理解软件开发的本质,就无法判断哪些可以量化,如何量化,以及度量得出的数据又该如何解释,数据的重要性如何?不能回答这些问题,追求定论,依然是不可能的。

请允许我先把话题扯远一点,谈一谈管理学,谈一谈泰勒以及泰勒之后的管理学。

1.“科学管理”与“泰勒式管理”

泰勒是毫无疑问的科学管理之父,为什么我会起这样一个标题呢?“科学管理”和“泰勒式管理”还有什么不同吗?

所谓“科学管理”,在我看来,就是以科学的方式研究管理。而泰勒正是以这样的方式研究如何进行管理的第一人。在泰勒之前的所有管理,无论好坏,都只是停留在经验的层面,而经过泰勒的科学方式的研究,管理也终于可以当之无愧的称之为一门科学,而泰勒以这样的研究方式,得出的结论,就可以称之为“泰勒式的管理”,这两者并不能等同。

我们知道,一个科学体系,包含两个方面,假设(公理)与逻辑推论。从哲学上来说,我们把假设称为世界观,而把推出结论的方式,称为方法论。无论谁来研究管理,只要他运用的是科学的逻辑的方法,我们就可以称其为“科学管理研究”,而如果他的初始假设与泰勒的不同,那么他得出的结论,就不是“泰勒式的管理”,但却肯定是“科学管理”。

无数的人可以有无数种不同的假设,那么我们如何判断哪一种假设更为合理,得出的结论更有价值呢?答案是:通过解释和预言。一套理论,必须自洽,也就是仅仅依靠本体系内已知的,有限的假设,通过逻辑推理,能够解释所有已知的、相关的现象。其次就是通过推理得出的预言,要能够接受验证,并且不被证伪。两种不同的假设得出的不同的预言,就能够通过验证,判断他们的胜负。而在预言没有被证伪前,该理论体系,就和其他尚未被证伪的理论一样,是有效的。而所谓的伪科学,就是只能解释,无法给出预言的理论。

“泰勒式的管理”,首先被证明是有效的。通过发现或者发明某个具体岗位上的最佳办法和最佳工具,大幅度的提升了工作的效率。以搬运生铁为例,工场工人裁减数从400~600下降到140,人均工作量从每天16吨,上升到每天59吨,人均收入从每天1.15美元上升到每天1.88美元,平均费用从每吨0.072美元,下降到每吨0.033美元。另外还有更为重要的效果是在工人本身,工人中喝酒的人大为减少,浪费钱的人也少了,因此都比以前生活得更好,他们把自己的顶头上司和教师,看成是最好的朋友而不是强逼他们做工的人。

泰勒的研究方式十分科学,他寻找并假设了影响工人效率的几大因素:技能、工具、激励、外部环境。并一一研究这些因素对于效率的影响,进而通过实验的效果来得出结论。这所有的一切,都没有什么错,只是当时的科学研究,尚无法证伪泰勒的诸多假设。而这些假设,也只有通过更进一步的科学研究,才有可能证伪。这个研究在管理学历史上大大有名,被称之为:“霍桑试验”,由乔治.埃尔顿.梅奥主持。

“霍桑试验”原本是一次典型的“泰勒式的科学试验”。根据科学的思维模式,一个待研究的系统,接受很多输入变量,也产生很多输出变量,在严密的、可控的、量化的输入变量的变化情况下,观察输出变量的变化,通过一系列的数据去分析系统可能的数学模型,而“霍桑试验”的第一阶段,就是要研究各种外界工作条件,对生产率的影响。他们把女工分为试验组和控制组(始终不改变条件,以作对照)然后每次试验只改变一项条件,比如照明条件,工间休息时间和频率,工作日长度等等。按照试验计划,第3、第10和第13试验期的工作条件将完全相同。但实际记录到的产量,却分别是:2500、2800、3000。这是完全不符合预测的,也不是简单的测量误差可以解释的,更令人不解的是,对照组的产量也在持续的提高。

这究竟说明了什么问题?到底是哪里出错了?梅奥是这样分析这个问题的:他认为存在着两种研究方法,“临床式研究”和“实验室”式研究。“临床式研究”的目的在于对事物的本质形成正确的认识,并学会处理实际材料的技能,在此基础上,进一步区分哪些方面可以继续进行更详细的“试验室”式研究。如果随后的“试验室”方法由于排除了某些未知的重要因素而归于失败,研究人员就应当回到“临床式研究”中去,以便弄清自己忽略了哪些因素。

而在我看来,所谓的“试验室”研究,就是在不动摇基本假设的前提下,进行逻辑推理,对照现实,丰富理论的细节。只有当这一理论的预言失败,或者出现无法解释的现象时,基础假设才会被置疑,研究者需要重新去寻找能够解释现有现象的新的假设,这样的研究往往非常困难,而且一旦成功就一定意义非凡。这在科学哲学上,被成为“范式的转换”。

科学范式的转化,从来都不是科学的失败,而是科学的重要的,甚至是跨越式的进步。在管理学上,从“经济人”假设转换为“社会人”假设,就是这样一次重要的进步。但是却有很多人,既不了解科学进步的规律,也不了解管理学的演变,却简单的认为人际关系学派的兴起,就意味着科学管理学派的失败和错误,并进而认为科学管理学派的失败,就意味着以科学方法研究管理底失败,这样的误会,实在是太不应该了。

2.探寻假设

在探寻软件开发以往的方法论背后的假设之前,首先要指出的是,这些假设很难被发现,不是说它们不存在,而是这些加上很少被看成是假设,往往作为理所当然的一部分,被排除在常规的思考范围之外。让我们来看几段大家都很熟悉的文字吧。

“大多数大型软件项目都没有达到预期的目标,交付推迟,预算超支,功能不完善。许多软件项目彻底失败了。”     ——FDD

“当前,软件开发的情况并不理想。很多系统最终不能交付,或者最终交付的系统经常性地发生延期或者超出预算;系统常常不能满足用户的需要,其结果是不得不一遍又一遍地开发。”     ——AM

“许多软件项目,或许应该说大部分软件项目实际的开发周期比预期的要长,实际的花费比预期的要多,实现的功能比预期的要少。这造成了严重的质量问题。”     ——某一本CMM的书籍

怎么样,是不是似曾相识?我敢肯定,你不只在一本书的序言部分,看到过类似的文字。无论这本书写于70年代、80年代、90年代还是21世纪。情况一直都是这么“糟糕”。有趣的是,这些书都会在“痛说软件开发现状”之后,转而兜售自己的方案。当然,在Brooks的《没有银弹》之后,他们兜售的语气谦虚了很多。作为一个文化现象来说,这非常值得细细品味。但是,我们需要追问的是:为什么?

难道软件开发是全世界最难的事情吗?为什么失败率如此之高?如果我们在使用了层出不穷的手段之后,还是不能提高成功率,我们应该怎么办?其实也很容易,当年我的一个老板就想出了一个绝妙的办法,绝对简单,就是将我自己的工作量估算乘2!我们的项目几乎从不失败,总是能够在计划时间内完成。于是我想,如果我们把全世界的软件项目估算都乘以2的话。也许软件开发这个行当,也能成为一个有尊严的职业。大家都会生活得更加幸福。

“这实在是太过分了!”也许有人会说:“你这是自欺欺人、掩耳盗铃、移靶就箭!”但是且慢生气,生气的人应该冷静下来反思:如果目标如此难以达到,会不会是目标有问题呢?当然,事情没有这么简单,如果把目标直接乘2来提高成功率,全世界的老板都会发疯的!我们要做的,是提高估算的准确性。

“啧啧,还以为是什么了不得的结论呢!这个问题早就有人研究了,不就是IT度量吗?”一定会有人站出来这么说。但是,IT度量的研究,提高了估算的准确度了吗?思路在这里被卡住了。直到有一天,我看到了量子力学中的“测不准原理”!

“测不准原理”告诉我们,在物理学中存在着很多对变量,当我们想要精确测量其中一个变量时,对另一个变量的测量误差就会越来越大。但是,在软件开发里,我们是进行估算,而不是进行测量,而且也不存在一个和工作量相对的变量,当工作量估算准确时,它会变得模糊。简单地套用物理定律是行不通的,思路又卡住了。

突然有一天,我问自己:“假设工作量已经估算精确到了99.9999%会出现什么情况?”“不可能!”“如果真的达到了这个精确度了呢?”我对自己穷追不舍。“那只有一种情况,就是项目已经接近完成了!”“我们估算完成时,项目接近完成,这意味着什么呢?”“这毫无意义,没有一个项目会花这个多时间来估算,而且如果要这样估算,估算本身要花多少时间都不知道。”停!我已经想通这个问题了。

估算工作量也是一种工作,同样也需要工作量。对于大多数任务来说,估算所花费的工作量,相对与总的工作量来说,几乎可以忽略不计,或者说:为了能够得到一个有指导价值的估算值,所花费的工作量,几乎可以忽略。但是,对于软件开发来说,这只是一个假设。我们假设对于软件开发的工作量估算,同样只需要花费极少的工作量。但事实上,当我们花费三五天时间得出结论,这个项目需要20个人月时,我们估算的误差,可能(甚至一定)会大于200%这就是我们这个行业显得如此失败的原因。

为什么这个行业与其它行业不同呢?在建筑行业,工程概预算的费用,不超过总费用的百分之一、甚至千分之一。为什么软件项目的估算做不到这一点?因为两个原因:

一是由于技术的复杂性,以及这个行业技术的飞速发展(也可说尚未定型),同样的需求,采用不同的设计,不同的技术实现,工作量相差极大。仅仅根据需求,无法估算出工作量。而随着概要设计、详细设计的层层分解,工作量估算的精确度的确会提高,但是对于软件开发来说,项目也越来越接近完成了。

二是由于需求的变动性以及不可预测性。早期的估算、设计甚至代码,都有可能作废。一个项目实际上重做了N遍,在软件开发领域也是常有的事。估算的误差,自然也就大到不可思议了。

然而,绝大多数人没有想过这个问题,大家都自然而然的根据最初的工作量估算,来评价以后的工作。

我们根据最初估算的工作量,来推出项目的时间、成本和质量目标,我们假设工作量估算只花费可以忽略不计的工作量,我们依据这些目标来衡量项目的成败,然后我们发现大多数项目都失败了,然后我们研究技术、改进过程、寻找银弹!最终,我们发现自己还是这么失败!

是到了彻底反省我们的假设的时候了。

(注:Brooks在《人月神话》中指出了另一个重要的假设:人与月是可以互换的。)

三、软件开发的特征

软件开发究竟是怎么一回事呢?在我的前一个连载《敲响OO时代的丧钟》里,我也讨论到了软件开发的实质,自己引一段来用用。

软件开发的定义:“软件开发,就是在一个受到限制的环境中,利用环境提供的可能性,修改或添加环境允许的各种状态,去满足某一组需求。”

1) 软件开发所处的环境,不仅仅是一个限制,同时也是一个可能性。软件的能力,局限性与硬件的能力,比如说,如果计算机没有喇叭,那么任何软件都不能使计算机播放音乐。但是,另一个必须考虑的方面是,同样有能力发声的计算机,要想使他播放音乐,可能很容易,也可能很困难。用专业一点话来描述就是:“有些硬件的API设计很合理,有些则非常愚蠢。”由于我们对于软、硬件的定义是一个连续体,因此,这个观点不只是可以用来评价硬件API设计,也可以用来评价语言、虚拟机、框架、平台等等软件的一个方面的优缺点——是否有利于二次开发,这是一个重要的评价标准。

2) 修改、添加状态,比较拗口,其实就是编程的意思。在一个受限制的范围内编程,我们需要考虑很多东西,语法、接口、规范、内存大小诸如此类,当然,不同级别的,不同领域的编程,需要考虑的限制是有巨大差别的。软件开发的水平高低也就体现在,满足同样的需求,有些方法速度更快,有些方面却要慢很多。而软件开发的方法的选择,受到很多因素的影响:环境限制,经验多少以及对于需求的了解程度等等。

3) 满足需求,是啊!提起这个需求,每一个程序员都会有好多的苦水要倒出来。为什么满足需求就这么难呢?因为,对于程序员来说,那是另外一个世界(这是比较客气的说法),那些提需求的家伙根本不懂怎么说话(这个说法稍为激烈一些),那是一些不知道自己要什么的蠢货(你遇到过这样的用户吗?)作为程序员,我知道我有很多同行,非常苦恼于与客户谈需求这样的任务——“至少电脑不会出现前后矛盾的逻辑错误”——这就是做程序员的难处。如果我们不仅仅是抱怨的话,也必须承认,程序员是非常挑战的职业,一个好的程序员,不但得是软件开发领域的专家,还得是他开发的那一类软件所在领域的专家。但事实上,其他行业的人,只需要做一种专家就能够混得很好了。

软件开发的实质,与软件开发的特征之间,还是有区别的。毕竟我的前一篇文章,是从技术的角度出发来看软件开发,而现在我们的要讨论的是从管理的角度来看待,它又有哪些特征呢?

软件开发的管理特征,在外行看来,也就是一堆人在做个东西。但是,软件开发的独特之处就在于,软件开发是由一堆独特的人,以独特的方式,做独特的东西。我们先来看看软件开发,遇到了哪些独特的困难:

1、沟通困难:同为软件开发,可能面对的思维模式,是完全不同的世界。比如二进制的世界,函数的世界、逻辑的世界、过程的世界、对象的世界、二维表的世界等等等等。在这些不同的世界中开发软件,需要的思考方式、思维习惯都是不同的。开发项目大到一定程度以后,不同的世界必须在一个完整的项目中和谐并存,这些差异,有时候就会带来沟通障碍。再加上技术与需求世界之间的差异,沟通成为一个非常重要的工作。软件开发中的人与事,如何才能有效沟通,是一个非常重大的课题。

2、控制困难:程序员都是些怪人,至少都是些聪明人。要让他们听话,很难啊。一个项目,要想顺利进行,程序员们能够接受的,必须是“稳定而合理的命令”。而在软件开发过程中,往往需求频繁变动,领导层层叠叠,用户花样百出,计划一改再改。程序员们经常会接到朝令夕改的命令,而且还来自于那些莫名其妙,连说话的逻辑都成问题的家伙。如何才能知道,那些小伙子是在严格地执行命令而不是在那里磨洋工呢?

3、评价困难:要控制,必须要能够赏善罚恶,但是在软件开发中,何为善?何为恶?如何评价一个程序员的工作?我们当然可以在项目计划该结束的时候,再去问他们,做完了吗?但是如果他们那时候没有完成,再要挽救就来不及了。必须在项目开发过程中建立即使有效的反馈机制。以小而高密度的评价手段,来对开发过程进行较为准确的控制,这一切,都必须建立在合理的评价机制的基础上。但是,这样一套评价机制,非常困难。什么才算是好的需求分析?好的代码?好的设计?好的测试用例?没有定论。举个例子:两三年前,在项目中加入EJB的成分,越多越好。现在呢?设计人员,随时都可能被人指责滥用EJB。这风向变得也太快了。

4、估算困难:这个在上一章我们也讨论到了,软件开发与其它行业的一个重大区别,就在于对于软件开发的估算成本,不能忽略不计。想要估算变动剧烈的项目的时间、人力、成本,简直就是不可能的任务。

怎么办?

讨论软件开发的特征,需要站在一个大的背景下来看。我以前考过PMP,在PMBOK中,软件项目管理,是作为项目管理下的子课题来讨论的。

按照PMBOK的知识结构图,PMBOK已经告诉了我们那么大一个圆。而要进一步搞好软件的项目管理,我们只需要再掌握相关应用领域的知识和实践,就ok了。

这其实是大多数项目管理的理论,对于软件项目管理的看法,所有的项目,都是项目。软件项目与大多数其它项目,大同而小异。至于差异部分,往往被归入“风险管理”的领域,就算是“一切尽在掌握了”。

而事实上,软件项目与其它项目的差异是如此之大,以至于由量变而导致了质变,使得我们以传统的工程项目管理的方式来管理软件开发项目,注定是要失败的。

我们来看看这样一个关键词:“迭代”。这是其它的项目管理中,基本上不可能出现的概念,而在软件项目管理领域,却是几乎每一种方法学中,都要极力强调的概念。这就是最大的区别。如果我们能够搞清楚迭代的本质,也就能够搞清楚软件项目与其它项目的本质区别了。

在我看来,在软件开发的过程中,引入迭代,就是承认,软件开发需要承受大大小小的失败,而减少失败的办法,就是不跑步,不走路,尽可能的爬行,这样就算跌倒,也不会跌得太重。我们来看一个有趣的数据。这是我在竹笋炒肉的blog上看到的一段话。

1994年,由于其非凡的软件开发能力和优秀的软件质量,SEL成为第一个因软件过程的成就而赢得IEEE奖励的软件开发组织。与普通的软件开发组织相比,在同样的软件开发条件下,NASA所开发的软件的质量要好10到20倍。

这个成就是如何得出的呢?那么是怎样的项目呢?我搜索了一个google,找到另外一段话:

To put it a little differently, the average MIS shop would need about 14 calendar months and 110 staff-months to deliver a 100,000 line-of-code MIS system, and it would typically contain about 850 defects when delivered. The NASA SEL would deliver a system of that size with about the same amount of time and effort, but it would contain only about 50 defects.

也就是说,10万行代码的一个MIS系统,他们花了110个人月,一共14个月,才完成。平均下来,每个人每天大约需要写30行代码!如果这样也算成功的软件项目管理的话,我以后只要将所有的项目工作量估算,乘以10,就能同样拿到IEEE的奖励了,如果我的老板允许的话。

各位一定非常惊讶(如果是读过前面几篇连载《定论》的人),怎么这就完了呢?看着架势,应该还早啊。

是啊,按照原定的计划呢,的确是还早,但是那样的写法,我自己都不知道会写到何年何月去了,因此打算结束这个东西,把我要表达的想法,一口气跟大家说了,也是一种解脱。

总结我的想法,主要有以下几点:

1、现有的软件开发方法,都不是定论,不过是你说你的好,我说我的好罢了。要能够得到定论,必须要有一种能够判断方法好坏的方法。也就是说,能够判断一个方法,用或不用,有多少好处。几个方法比较,哪个能够胜出的“检验标准”。

2、要能够检验软件开发方法的优劣,必须基于对于软件开发本质的正确认识,这样才能量化两个因素:软件需求的复杂程度以及软件开发的实际工作量。而现在的软件复杂度的度量,并未区分“需求”与“实际”的不同,或者“代码行数”,或者“功能点”,都是如此。

3、在能够正确度量需求复杂度与实际工作量之后,我们会发现,过去那么多号称是为了保证软件顺利开发的手段,往往只会坏事,耽误事。但是,完全不提前设计的方法,也并不可取。

原文写于:2005年11月,最后其实是草草结束,并没有写完。当然,后续我也一直在思考,直到最近,我又另外写了一篇《从软件工程到研发管理》,希望能够把这个问题思考明白。