﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-软件工艺之路……-文章分类-项目管理技术</title><link>http://www.blogjava.net/t19y80/category/1976.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 10:17:51 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 10:17:51 GMT</pubDate><ttl>60</ttl><item><title>程序开发的心理研究——“以人为本”</title><link>http://www.blogjava.net/t19y80/articles/7905.html</link><dc:creator>Tianye</dc:creator><author>Tianye</author><pubDate>Mon, 18 Jul 2005 02:25:00 GMT</pubDate><guid>http://www.blogjava.net/t19y80/articles/7905.html</guid><wfw:comment>http://www.blogjava.net/t19y80/comments/7905.html</wfw:comment><comments>http://www.blogjava.net/t19y80/articles/7905.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/t19y80/comments/commentRss/7905.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/t19y80/services/trackbacks/7905.html</trackback:ping><description><![CDATA[<TABLE cellSpacing=0 cellPadding=0 width=770 border=0>
<TBODY>
<TR>
<TD vAlign=top align=middle width=620>
<TABLE cellSpacing=0 cellPadding=0 width=620 border=0>
<TBODY>
<TR>
<TD align=middle width=600 height=10></TD></TR>
<TR>
<TD class=title1 align=middle width=600><B>程序开发的心理研究——“以人为本”</B></TD></TR>
<TR>
<TD align=middle height=30><FONT color=#999999>(2005.07.13)&nbsp;&nbsp; 来自：csdn blog&nbsp;&nbsp; sunlen </FONT></TD></TR>
<TR>
<TD align=middle height=10></TD></TR>
<TR>
<TD bgColor=#999999 height=1></TD></TR>
<TR>
<TD></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width=600 border=0>
<TBODY>
<TR>
<TD height=20>&nbsp;</TD></TR>
<TR>
<TD class=tdmain align=left width=600>
<TABLE style="MARGIN: 10px 7px 3px 4px" cellSpacing=0 cellPadding=0 align=left border=0>
<TBODY>
<TR>
<TD>
<SCRIPT type=text/javascript><!-- 
 csdn_AD_Position_GroupID = "{e025b96b-2fda-4e82-84ef-3e0772838ed3}"; 
 csdn_AD_Page_Url = document.location; 
 csdn_AD_CurrPage_CharSet = "gb2312"; 
 //--></SCRIPT>

<SCRIPT src="http://ggmm.csdn.net/AD/Show_JavaScript_AD.js" type=text/javascript></SCRIPT>

<SCRIPT language=JavaScript1.1 src="http://ggmm.csdn.net/AD/ShowJavaScriptAD.aspx?show=true&amp;position={e025b96b-2fda-4e82-84ef-3e0772838ed3}&amp;CharSet=gb2312"></SCRIPT>
<BR></TD></TR></TBODY></TABLE>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 今天看到CSDN网友sunlen在BLOG中写的“程序开发的心理研究”，让我想起了<A href="http://www.dearbook.com.cn/book/viewbook.aspx?pno=TS0012285"><FONT color=#a0a0a0><STRONG>Weinberg先生的著作——《程序开发心理学》</STRONG></FONT></A> 。在计算机界，还没有任何一本计算机方面的书，在初次出版之后，能够在长达25年的岁月中一直保持活力，而且这种活力到今天仍在继续。 《程序开发心理学》 是开创“以人为本”研究方法的先驱，它以其对程序员们在智力、技巧、团队和问题求解能力等方面独特的视角和敏锐的观察经受住了时间的考验。以下是 sunlen在程序开发心理学的一些个人见解：</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本文只是根据本人的一些经验，还有外界的一些文章，总结出来的程序开发过程中程序员的心理的一些总结，并没有通过严格的验证。</P>
<P align=center><STRONG>一、开发项目的原则</STRONG></P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一般研究发现，一个人刚进行一个新的公司，或者接受一个新的任务，他总得要一个适应的过程，这段时间叫做适应期，这个过程根据不同的人所需要适用的时间长度不同，对于一个程序员来说，如果接受一个难度适中的项目，他一般需要3个月的时间来适应，当然，这个时间只是一个一般比较普遍的情况，可能有些人1个月就可以适应了，有些人搞了半年，还是对系统很不熟悉。这个适应期大概包括下面几个部分：1。对环境的适应。社会是由人组成的社会，当然程序员进行一家新的公司、或者一个新的环境，总免不了要跟人打交道，可能有人会说，“每次开发系统都是我独自一人完成”，恕我坦白一点的说，这样开发出来的系统根本不能算是一个系统，现代项目开发一般需要包括前期需求分析、需求文档开发、设计文档开发、代码编写、系统测试等。要使得这一总个流程顺利的进行下去，那就需要人与人之间的合作，所以一个程序员到了一个新的环境、面对一些陌生的人、总得有一点的时间相互之间进行交流，建立起一种友谊。2。对项目的适应。我们接受一个项目，不管是全新的还没开发的项目，还是已经处于维护状态的项目，我们总得对它的业务逻辑、开发风格、编程规范、系统构架等有一个了解。业务逻辑是指一个项目相关的操作是怎么进行的、各个操作具体如何操作等等。开发风格是系统原有是如何进行开发的，现在国内有很多系统都是一招了一个新人就叫他进行代码的开发，结果他等到开发完了才发现原来他花了很久才开发出来的类（java和c＋＋中的一种概念，相当于一个功能模块，可以被其它功能使用），其实系统早就已经有了，使用的时候这样调用就可以了，等等。编程规范大家应该都知道了，现在基本不同的语言都有自己的编程规范，比如说java有java编程规范，同时，不同的公司可能根据自己的情况定义了一些规范，比如说，判断一个变量是否为空，有些公司要求将null放在前面等。系统构架是指一个项目的总的框架是如何搭建的，采用哪种语言等，比如说、现在很多开发网上应用系统都采用Struts＋Spring＋Hibernate构架（采用java语言）。这些都需要一个适应的过程，如果对这些都还没了解清楚就匆忙的开发编写代码，那写出来的将会是一些格格不入的代码、不管这个代码单独拿出来看的时候是多么的完美。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 适应期过后，接下来是一段比较长的稳定期。这段时间一般有半年到一年的时间。在这段时间里面，程序员对系统业务比较熟悉，开发系统得心应手，他们一般在定位一个系统问题的时候，能够比较快的查找出问题并处理，而不像一些新手一样，对系统调试N久之后，才将问题处理，之后才发现，问题只不过处理了一半，在其它地方存在的相同的问题没有处理，或者处理完一个问题之后，却导致其它地方出了问题。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 稳定期过后，程序员开始陷入了厌烦期。这个厌烦期是没有期限的，随着时间的推移，程序员可能越来越讨厌自己的工作，他经常抱怨系统编码是如何的差劲，而完全忘记了这个差劲的系统也有他的一份功劳在内。他们工作的时候不像以前那样有积极性，经常在上班前2分钟到达公司，还可能在下班前半个小时就开始收拾东西、给家人打电话、等待的下班时间的到来。他们开始对反馈的一些问题应付了事，他们开始对新近来的员工指手画脚，在开会的时候发短信，等等。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 根据上面我们可以发现，一个程序员新接触一个新的项目的时候，我们要给他一段时候熟悉系统，而不管他是多么强的一个高手。很遗憾的是，现在国内很多公司一招了一个新人，就开始压一大堆任务给他，而完全不给他们适应的机会。这样产生出来的经常是一个千疮百孔的系统，甚至完全就是一个失败、无法使用的系统。当一个人开发对现在的系统厌烦的时候，就要开始分配新的任务给他，让他去熟悉、开发新的系统，而不要总抱着这样的想法，就是现在系统他最熟悉了，让他开发最合适，让他去开发新系统还要让他花时间去熟悉新系统等等。这样下去的结果可能有两种，一是开发人员被迫辞职了，剩下来的就是一个没有人熟悉的系统，招来的新员工在这个系统上花费了大量的时候，才搞个一知半解，甚至系统可能就这样寿终正寝了。还有一种结果就是开发人员因为高工资继续留下来，但是系统的开发进度越来越慢，bug越来越多，开发人员也变得有恃无恐的，而领导层却越来越担心由于开发人员辞职导致系统无法进行下去。</P>
<P align=center><STRONG>二、今天周末、早点回家吧！</STRONG></P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我想国内企业最擅长的就是剥削劳动者的劳动力的，甚至有人叫嚷着：“没有程序员是不需要加班的”。他们将一个又一个的任务压在程序开发人员的身上，将完成时间压缩后再压缩，直压得开发人员两眼冒星，口吐三口鲜血后在当天的工作日志上写道：“今天是我连续第三天通宵了，今天总共处理了283个系统问题，最后系统终于跑起来了，用户终于同意通过了检查，我光荣的完成了使命！”。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在这里我并不想批驳公司对程序开发人员的剥削，这种高强度开发对系统的影响，它最终也会损坏到公司的利益。项目开发跟一般工厂上组装一件电器是不一样的，我们的项目要实现一个功能，是有很多中实现方式的，还要考虑系统构架、可重用性、可读性等。比如说，一个好的系统构架，你会发现实现起功能来又快又好，而且能够应付系统开发过程中业务逻辑的变化，而一个差的构架，实现起功能来很困难，而当业务逻辑变化时，你会发现几乎所有的代码都需要重新修改，这会令你陷入绝望的境地，而不像一个好的架构那样修改一下配置文件或者两段代码都搞定了，这其中的快慢有时可以用N次方来形容的。而恰恰是这种好的构架在前期需要大量的时候进行设计，如果一味求快的话，那么开发人员根本就没有时间进行一个好的构架的设计，这样前头快的做法，将会对后续的开发带来影响，使得开发起来更加困难。可重用性也是一样，如果考虑可重用性的话，那么可以将一些逻辑抽象出现，写出一个类，这样，还后续开发的时候，如果有相同的逻辑，就可以使用这个类了，如果对这个逻辑进行修改的话，那只要修改了这个类，所有的逻辑都同时改变了。如果完全不考虑这些的话，那么后续开发都要开发类型的代码，如果对逻辑修改的话，那么将是很麻烦的事情，当然，这个进行抽象成一个类的动作，比自己开发更花时间，但是更好。对于可读性，对于一个紧急的开发，你可能发现里面连一个注释都没有，很可能开发人员后来翻出这些代码来看的时候，他已经不记得这到底是什么意思了，甚至连是不少他开发的都不记得了。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 所以，我想说的就是，不要给程序开发人员太大的压力，只要适中就可以了。还有，不要一味的要求开发人员干活，要适当的表现出对他们的关心，比如说，周末的时候，跟他们说：“今天周末，早点回家吧！”，这样对开发人员的作用是很大的。</P>
<P align=center><STRONG>三、监狱里的囚犯</STRONG></P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我想大概国内的软件公司是全世界男女比例最失调的吧，随便走进那家公司，你经常会看到的是大批的男性开发人员的，而作为女性的一般都是些文员，市场人员，资料开发人员等，领导层他们有自己的想法，他们这样想着，如果招了一个女性开发人员进公司的话，那么她晚上就不能加班太晚，不然还得负责她的安全。还有，在中国程序员眼里，女性程序员大多不懂编程，整天问东问西。还有，领导们可能担心招了女性程序员之后，会影响到大家的情绪，可能是造成公司内部分裂的根源，等等。同样的，也是女性自身方面的问题，国内的女性一般偏向于学习文科方面的东西，在大学里面，学习理科的女性要比男性少得多。等等这些都造成了现在程序开发行业阳盛阴衰的现象。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这种现象所引起的后果就是国内很多的男性开发人员都很内向，不善于跟女性交流，见了女性有些还会脸红。很多在公司里面勤勤恳恳，工资也不低，人长得也不衰，但是就是没有女朋友。他们的生活是压抑的（至少是性压抑吧）。程序员就好像被关在监狱里的囚犯，白天干活，经常加班，晚上回去就睡觉，第二天又开始新的工作。他们在公司里的经常是在处在一个被压迫的状态，很少有时间进行其它的活动等。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我想这是有害的，中国如果继续这样发展的话，将会阻碍软件行业的发展。领导应该多考虑招一些女性的程序员，多组织一些活动等。让程序员感觉到公司里面的一些人性化管理，这就是一个公司的软环境，让程序员安居乐业的软环境。</P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><img src ="http://www.blogjava.net/t19y80/aggbug/7905.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/t19y80/" target="_blank">Tianye</a> 2005-07-18 10:25 <a href="http://www.blogjava.net/t19y80/articles/7905.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Martin Fowler：新方法学</title><link>http://www.blogjava.net/t19y80/articles/7278.html</link><dc:creator>Tianye</dc:creator><author>Tianye</author><pubDate>Thu, 07 Jul 2005 05:43:00 GMT</pubDate><guid>http://www.blogjava.net/t19y80/articles/7278.html</guid><wfw:comment>http://www.blogjava.net/t19y80/comments/7278.html</wfw:comment><comments>http://www.blogjava.net/t19y80/articles/7278.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/t19y80/comments/commentRss/7278.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/t19y80/services/trackbacks/7278.html</trackback:ping><description><![CDATA[<SPAN class=javascript id=text5202>新方法学 <BR><BR>英文原文版权由Martin Fowler拥有 <BR>Original text is copyrighted by Martin Fowler <BR><BR>Martin Fowler <BR>Chief Scientist, ThoughtWo rks <BR><BR>过去几年中兴起的敏捷型（agile）软件开发方法，以矫正官僚繁琐过程，或者许可对过程进行自主调整为特征，在软件业引起了极大的兴趣。在这篇文章里，我将探索敏捷型方法的合理性，着重点并不是放在其“轻重”上，而是于它们的适配性（adaptive）性质和以人优先的理念。我在本文也简要介绍了一些敏捷型方法并给出了进一步的参考材料。另外，我还给出了一些你在决定是否要走这条刚踏出来的敏捷之路时需考虑的因素。 <BR><BR>最近一次主要修改: 2001年11月 <BR><BR>在SD East 上我作了一次演讲 “让软件恒软〔Keeping Software Soft）” 其材料就是基于这篇文章（你若有充足的时间可浪费的化，不妨一观）。此文的节略版发表于 Software Development Magazine（软件开发杂志） 的2000年12月期。 <BR><BR>从无，到繁重, 再到敏捷 <BR>预设性与适配性 <BR>将设计与建造分离开来 <BR>需求的不可预设性 <BR>预设性是不可能的吗？ <BR>不可预设过程的控制 <BR>适配性的客户 <BR>让人优先 <BR>可兼容性程序插件 <BR>程序员是负责任的专业人员 <BR>面向人的过程的管理 <BR>应用域专家的引领作用 <BR>自适配过程 <BR>敏捷型方法 <BR>XP（Extreme Programming －－ 极端编程） <BR>Cockburn的水晶系列方法 <BR>开放式源码 <BR>Highsmith的适配性软件开发方法〔ASD） <BR>SCRUM <BR>Coad的功用驱动开发方法〔FDD） <BR>动态系统开发方法〔DSDM） <BR>敏捷软件开发宣言 <BR>RUP是一种敏捷型方法吗？ <BR>其他参考材料 <BR>你是否应走向敏捷？ <BR>该用哪个适配性过程？ <BR>鸣谢 <BR>修改记录 <BR>从无，到繁重, 再到敏捷 <BR>多数软件开发仍然是一个显得混乱的活动，即典型的“边写边改” （code and fix）。设计过程充斥着短期的，即时的决定，而无完整的规划。这种模式对小系统开发其实很管用，但是当系统变得越大越复杂时，要想加入新的功能就越来越困难。同时错误故障越来越多，越来越难于排除。一个典型的标志就是当系统功能完成后有一个很长的测试阶段，有时甚至有遥遥无期之感，从而对项目的完成产生严重的影响。 <BR><BR>我们使用这种开发模式已有很长时间了，不过我们实际上也有另外一种选择，那就是“正规方法”（methodology）。这些方法对开发过程有着严格而详尽的规定，以期使软件开发更有可预设性并提高效率，这种思路是借鉴了其他工程领域的实践。 <BR><BR>这些正规方法已存在了很长时间了，但是并没有取得令人瞩目的成功，甚至就没怎么引起人们的注意。对这些方法最常听见的批评就是它们的官僚繁琐，要是按照它的要求来，那有做太多的事情需要做，而延缓整个开发进程。所以它们通常被认为是“繁琐滞重型”方法，或 Jim Highsmith 所称的“巨型”（monumental)方法。 <BR><BR>作为对这些方法的反叛，在过去几年中出现了一类新方法。尽管它们还没有正式的名称，但是一般被称为“敏捷型”方法。对许多人来说，这类方法的吸引之处在于对繁文缛节的官僚过程的反叛。它们在无过程和过于繁琐的过程中达到了一种平衡，使得能以不多的步骤过程获取较满意的结果。 <BR><BR>敏捷型与滞重型方法有一些显著的区别。其中一个显而易见的不同反映在文档上。敏捷型不是很面向文档，对于一项任务，它们通常只要求尽可能少的文档。从许多方面来看，它们更象是“面向源码”（code-oriented）。事实上，它们认为最根本的文档应该是源码。 <BR><BR>但是，我并不以为文档方面的特点是敏捷型方法的根本之点。文档减少仅仅是个表象，它其实反映的是更深层的特点： <BR><BR>敏捷型方法是“适配性”而非“预设性”。重型方法试图对一个软件开发项目在很长的时间跨度内作出详细的计划，然后依计划进行开发。这类方法在计划制定完成后拒绝变化。而敏捷型方法则欢迎变化。其实，它们的目的就是成为适应变化的过程，甚至能允许改变自身来适应变化。 <BR>敏捷型方法是“面向人”的(people-oriented) 而非“面向过程”的 (process-oriented)。 它们试图使软件开发工作顺应人的天性而非逆之。它们强调软件开发应当是一项愉快的活动。 <BR>在以下各节中，我将详细地探讨这些差别，这样你可以了解适配性和以人为中心的过程是什么，它们的好处与不足，以及你作为软件开发人员或用户时是否应该使用它们。 <BR><BR>预设性与适配性 <BR>将设计与建造分离开来 <BR>传统的软件开发正规方法的基本思路一般是从其他工程领域借鉴而来如土木工程模式对软件工程的影响较大。这类工程实践中，在实际建造之前，通常非常强调设计规划。工程师首先给出一系列的图纸，这些图纸准确地说明了要建造什么以及如何建造（包括部分和整体）。许多工程问题，如怎样处理一座桥梁的负荷，图纸上都有说明。然后，这些图纸分发给另外一组人员，通常是另外一个公司，去建造。这种方式其实已假定了建造过程将按图纸而来。当然，施工中也会碰到一些问题，但这些都是次要的。 <BR><BR>图纸其实就是一个详细的建造计划，它说明了一个项目中必须完成的各项任务，以及这些任务之间的依赖关系。这样，管理层能较为合理地制订出生产进度表和项目预算。这种模式实际上也规定了建造者如何做（施工），这也隐含着建造者不须是高智能型的，尽管他们可能都有非常高超的手上功夫。 <BR><BR>在此，我们看到的是两类非常不同的活动。设计是难于预设的，并且需要昂贵的有创造你的人员，建造则要易于预设。我们有了设计之后，便可对建造进行计划了。而有了建造计划后，我们进行建造则可以是非常可预设性的了。在土木工程中，建造不论在经费上还是在时间上的花销都要比设计和计划大得多。 <BR><BR>所以，多数正规方法的途径是象这样的：我们想要可预定的生产进度计划，以便能使用技能较低的人员。要达到这一点，我们必须得把设计与建造分离开来。因此，在软件开发中，我们得想法作出这样的设计，使得计划一经完成，建造将会是直接而明确的。 <BR><BR>那么，计划应该采用什么形式呢？对许多人来说，这是设计“标识符号” （notation），如象UML，需承担的角色了。如果我们能用UML作出所有主要的技术决定，那么就可以用UML来做建造计划，然后把计划交给程序员去编码，即是建造活动。 <BR><BR>但这里存在几个问题。你是否能作出这样的设计使得它能够让编码成为一项建造活动？如果能，那么建造是否能在资金和时间上的花销都充分地大于设计而使得这种途径值得一用？ <BR><BR>第一个问题是到底有多困难能使一个用类似UML作出的设计达到交给程序员就能直接编码的状态。用象UML那样的语言作出的设计在纸上看起来非常漂亮，而实际编程时可能会发现严重的缺陷。土木工程师使用的模型是基于多年的工程实践，并结晶在工程典章中。更进一步来说，一些设计上的关键部分，如应力作用，都是建立于坚实的数学分析之上。而在软件设计中，我们对UML图纸所能做的只是请专家审阅。这当然是很有帮助的，但是往往一些设计错误只能在编码和测试时才能发现。甚至于熟练的设计者，我自认为我属此列，就常常对在把设计变成软件的过程中出现的错误感到意外。 <BR><BR>另一个问题是费用比较。建一座桥梁时，设计费用一般占整个工程的10％，左右，余下的90％左右为施工建造费用。而在软件开发中，编码所占的时间一般要少得多（McConnell 指出在大型项目中，编码和单元测试只占15％，这几乎和桥梁工程中的比例倒过来了。即使把所有测试工作都算作是建造的一部分，设计仍要占到50％）。这就提出了一个重要问题，那就是和其他过程领域的设计相比，软件设计到底是什么性质。 <BR><BR>更有甚者，Jack Reeves 认为源码也应是设计文档，而建造应该是编译和链接，因为任何属于建造的工作都应当是自动化的。 <BR><BR>这些讨论导致了下面一些结论： <BR><BR>在软件开发中，具体建造费用非常低，几可忽略不计。 <BR>软件开发的绝大部分工作是设计，因此需要富有创造性的才智之士。 <BR>创造性的过程是不太容易计划的，因此，可预设性不可能成为一个要达到的目标。 <BR>我们应该对用传统工程模式来进行软件开发的做法保持足够的警觉，因为它们是不同类型的活动，因此需要不同的过程。 <BR>需求的不可预设性 <BR>在每个我参加的项目都有这样一种情况，开发人员跑来抱怨说， “这个项目的问题是需求老是在变”。而让我意外的是每个人都对此感到意外。其实在建造商用软件系统中，需求变更是常态，问题是我们如何来处理它。 <BR><BR>一种方法是把需求变更看成是因需求工程（requirements engineering）没作好而导致的结果。一般来说，需求工程（或曰进行需求分析）是要在着手建造软件之前，获取一幅已完全理解了的待建系统的画面，然后取得客户认可签发，并且还要建立一套规章来限制需求变更。 <BR><BR>该方法的一个问题是要准确获取所有需求是困难的，特别是当开发商不能提供某些需求的费用信息时。例如，你买车时想在你的车上装一个天窗，而推销员却不能告诉你要在车价上只再加10元钱呢，还是10000元。如果不知道这点，你如何能决定你是否愿意在车上加个天窗呢。 <BR><BR>作软件开发的费用估算是不容易的，这有多种原因。部分原因是因为软件开发是一种设计活动，因此难于精确计划。部分原因是系统的“基本材料”变化非常之快。部分原因是开发活动极大地依赖于项目参与人员，而个体是难于预测和量化的。 <BR><BR>软件的“不可触摸”性也是一个原因。在系统建成之前，有时很难判断一项功能的具体价值。也就是说，只有当你在实实在在地使用系统时，你才能知道哪些功能是有用的，哪些没什么用。 <BR><BR>这样的结果颇具讽刺意味，即人们期待需求应该是可变的。毕竟，软件应该是 “软”的。所以，需求不仅是可变的，简直就是应该变的。要让客户把需求固定下来要花很大的力气，特别是当他们“参与”了软件开发并且“知道”软件是多么易于修改。 <BR><BR>但是，即使你能把所有的需求都固定下来，并不意味着你的开发就是阳光灿烂了，你可能仍然会在昏暗之中。在当今的经济形势下，决定并推动软件系统功能特性的商业因素飞快地变化着。现在一组很好的功能六个月以后可能就不那么好了。 <BR><BR>商业世界并不会因你的系统的需求固定下来了而停止不动，商业世界的许多变化是完全不可预测的。如果有人不承认这一点，要么他在撒谎，要么他已炒股成了百万富翁了。 <BR><BR>软件开发的一切都取决于系统需求，如果需求不固定，你就不能制订出一个可预设性的计划。 <BR><BR>预设性是不可能的吗？ <BR>一般来说，不可能。当然，有一些软件开发项目中，预设性是可能的。象 NASA的航天飞机的软件开发项目，应是这样一个例子。它需要大量的会议，充足的时间，庞大的团队，以及稳定的需求。毕竟，这些是航天飞机的项目。但我并不认为一般的商用软件开发属于这类系统，所以你需要不同的开发过程。 <BR><BR>如果你不能遵循一个可预性方法，而你强装能够，那么这是非常危险的。通常，一个正规方法的创造者不是很善于（或乐于）给出其方法的边界条件，换句话说，当这些边界条件不满足时，则该方法就不适用。许多方法学者希望他们的方法能够放之四海而皆准，所以他们既不去了解，也不公布他们方法的边界条件。这导致了人们在错误的情形下来使用一种方法，例如，在不可预设性的环境中使用一种预设性的方法。 <BR><BR>使用预设性方法具有强烈的诱惑力，因为预设性毕竟是一个非常需要的特性。可是，当你不能达到预设性时而你相信你能够，这将会导致这样一种局面：你可以很早就制订出计划，但不能适当地处理计划崩溃的情形。你看见现实与计划慢慢的偏离，而你可以在很长的时间里，装着认为计划仍是有效可行的。但是当偏离积累到足够的时候，你的计划就崩溃了，这通常是很痛苦的。 <BR><BR>所以说，在不可预设性的环境中是不能使用预设性方法的。认识到这点是一个很大的冲击。它意味着我们用的许多控制项目的模式，许多处理客户关系的模式，都不会再是正确的了。预设性的确有非常多的好处，我们很难就放弃预设性而失去这些益处。象很多问题一样，最困难的一点是认识到这些问题的存在。 <BR><BR>可是，放弃预见性并不意味着回到不可控制的一片混乱之中。你所需要的是另一类过程，它们可以让你对不可预设性进行控制，这就是“适配性” 的作用了。 <BR><BR>不可预设过程的控制 <BR>那么，我们如何对付一个不可预测的世界呢？最重要，也是最困难的是要随时知道我们在开发中的情形处境，这需要一个诚实的反馈机制来不断准确地告诉我们。 <BR><BR>这种机制的关键之点是“迭代式”（iterative）开发方法。这并不是一个新思路，迭代式开发方法已存在很久了，只是名称不同，如“递增式” （Incremental），“渐进式”（Evolutionary)，“阶段式”（Staged），“螺旋式”（Spiral）等等。迭代式开发的要点是经常不断地出最终系统的工作版本，这些版本逐部地实现系统所需的功能。它们虽然功能不全，但已实现的功能必须忠实于最终系统的要求，它们必须是经过全面整合和测试的产品。 <BR><BR>这样做的理由是：没有什么比一个整合了的、测试过的系统更能作为一个项目扎扎实实的成果。文档可以隐藏所有的缺陷，未经测试的程序可能隐藏许多缺陷。但当用户实实在在地坐在系统前来使用它时，所有的问题都会暴露出来。这些问题可能是源码缺陷错误（bug），也有可能是对需求理解有误。 <BR><BR>虽然迭代式开发也可用于可预性环境，但它基本上还是用作“适配性” （adaptive）过程,因为适配性过程能及时地对付需求变更。需求变更使得长期计划是不稳定的，一个稳定的计划只能是短期的，这通常是一个“迭代周期”（iteration）。迭代式开发能让每个迭代周期为下面的开发计划提供一个坚实的基础。 <BR><BR>迭代式开发的一个重要问题是一个迭代阶段需要多长。不同的人有不同的答案， XP（极端编程）建议一到两周，SCRUM建议一个月，Crystal（水晶系列）更长一些。不过，一般的趋势是让每一个周期尽可能地短。这样你就能得到频繁的反馈，能不断地知道你所处的状况。 <BR><BR>适配性的客户 <BR>这类适配性过程需要与客户建立一种新型的关系，特别是当开发是由一家签约公司来进行的时候。因为当雇佣一家签约公司来进行开发时，多数客户愿意订一个固定价格的合同。他们告诉开发方他们所需要的功能，招标，签约，然后剩下的便是开发方去建造系统了。 <BR><BR>固定价格合同需要稳定的需求，即一个可预设性过程。适配性过程和不稳定的需求意味着你不能做这种固定价格的合同。把一个固定价格模式弄到适配性过程将导致一个痛苦的结局。最糟糕的是客户将与软件开发者受到同样的伤害，毕竟客户不会想要一个不需要软件。即使他们未付开发方一分钱，他们仍然失去许多。 <BR><BR>因此，在可预设性过程不能用的情况下，签订固定价格合同对双方来说都有危险。这意味着客户须换一种工作方式。 <BR><BR>在适配性过程中，客户实际上能够对软件开发过程进行很深入细微的控制。在每一个迭代阶段中，他们都能检查开发进度，也能变更软件开发方向。这导致了与软件开发者更密切的关系，或曰真正的伙伴关系。但并不是每一个客户，也并不是每一个开发商都准备接受这种程度的介入，不过如要让适配性过程能很好工作，这种合作程度是基本的要求。 <BR><BR>适配性过程对客户最关键的益处是软件开发中的“回应性”很好。一个可用的，尽管是很小的系统能够尽早投入使用。根据实际使用情况，以及变更了的需求，客户可及时改变一些系统功能。 <BR><BR>让人优先 <BR>实施一个适配性过程并不容易，特别是它要求一组高效的开发人员。高效既体现在高素质的个体，也体现在有能让团队协调一致的工作方式。这里有一个有趣的和谐：并非只是适配性过程需要很强的团队，多数优秀的开发人员也愿意采用适配性过程。 <BR><BR>可兼容性程序插件 <BR>传统正规方法的目标之一是发展出这样一种过程，使得一个项目的参与人员成为可替代的部件。这样的一种过程将人看成是一种资源，他们具有不同的角色，如分析员，程序员，测试员及管理人员。个体是不重要的，只有角色才是重要的。这样一来，在你计划一个项目时，你并不在乎你能得到哪个分析员，哪些测试员，你只需关心你可得到多少，知道资源数量会如何影响你的计划。但这有一个关键问题：参与软件开发的人员是可替代的部件吗？轻灵型方法的一个重要特征就是拒绝这种观点。 <BR><BR>也许最明确地反对这种观点的当数Alistair Cockburn. 在他的论文 “人是非线性，一阶的部件”中，他指出可预设性软件开发过程要求 “部件”的行为也是可预性的。 <BR><BR>但是，人并非可预性的部件。更进一步，他对软件项目的研究导致了如下结论：人是软件开发中最重要的因素。 <BR><BR>在本文的标题里，我将人称为“部件”。其实（传统）过程/方法就是这样看待人的。这种观点的错误在于“人”是非常可变的和非线性的，不同的个体具备特有的成功或失败模式。那些因素是一阶的，不可忽略的。一种过程或方法的设计者如不能充分考虑到这些因素，那麽其后果就是项目的无计划轨迹。就象我们经常看到的那样。 <BR>-- Alistair Cockburn <BR><BR>Cockburn是最鲜明地主张在软件开发中应以人为中心，其实这种概念在许多软件行业的有识人士中已是共识。问题在于所使用的方法是与这种理念背道而驰的，这造成了一个很强的正反馈机制。如果你期望你的开发人员是可互替的编程插件，则你不会去试着把他们看成是不同的个体。这会降低士气（和生产率），并使优秀的人才跳到一个能发挥其个性特长的地方，最后你倒是得到你所需要的：可互替的编程插件。 <BR><BR>决定使人优先是件大事，它需要很大的决心来推行。把人作为资源的思想在工商界是根深蒂固的，其根源可追溯到泰勒的“科学管理”方法。当管理一个工厂时，这种泰勒主义途径是有效的。但是对有着高度创造性和专业性的工作，我相信软件开发当属此类，泰勒主义并不适用（事实上现代制造业也在脱离泰勒主义模式）。 <BR><BR>程序员是负责任的专业人员 <BR>泰勒主义的一个关键的理念是认为干活的人并非是那些知道怎样才能把这件活干的好的人。在工厂中可能是这样，原因是许多工厂里的普通工人并非是最具聪明才智和最富创造力的人员。另一个原因也许是由于管理层和工人的的工资悬殊太大而导致的关系紧张。 <BR><BR>历史证明这种情形在软件开发中是不存在的。不断有优秀人才被吸引到软件行业中，吸引他们的既有耀眼的光芒也有丰厚的回报（正是这两样诱使我离开电子工程）。其他一些福利如对公司的股份持有使得程序员的利益与公司紧联在一起。 <BR><BR>〔可能还有一个“产生”（generational)效应。一些所见所闻让我想到是否在过去十来年中有很多的优秀人才转入软件行业。如果是这样，这可能是当今年轻人崇尚IT业的原因，就象其他时尚一样，其后总有一些实在的理由。） <BR><BR>如果你想聘到并留住优秀人才，你得认识到他们是有能力的专业人员。因此，他们最有资格决定如何干好他们的技术工作。泰勒主义里让计划部门来决定如何干好一件工作的作法只有当计划者比实际操作者更能知道怎样作时才有效。如果你拥有优秀的、自觉自励的员工，那么这点并不成立。 <BR><BR>面向人的过程的管理 <BR>敏捷型过程中“以人为本”的理念可以有不同的表现，这会导致不同的效果，而并非所有结果都是完全一致的。 <BR><BR>实施敏捷型过程的一个关键之处是让大家接受一个过程而非强加一个过程。通常软件开发的的过程是由管理人员决定的，因此这样的过程经常受到抵制，特别是如果管理人员已脱离实际的开发活动很长时间了。而接受一个过程需要一种“自愿致力”，这样大家就能以积极的态度参与进来。 <BR><BR>这样导致了一个有趣的结果，即只有开发人员他们自己才能选择并遵循一个适配性过程。这一点在XP中特别明显，因为这需要很强的自律性来运行这个过程。作为一个互补，Crystal（水晶系列）过程则只要求最少的自律。 <BR><BR>另一点是开发人员必须有权作技术方面的所有决定。XP非常强调这一点。在前期计划中，它就说明只有开发人员才能估算干一件工作所需的时间。 <BR><BR>对许多管理人员来说，这样形式的技术领导是一个极大的转变。这种途径要求分担责任，即开发人员和管理人员在一个软件项目的领导方面有同等的地位。注意我说的同等。管理人员仍然扮演着他们的角色，但需认识并尊重开发人员的专业知识。 <BR><BR>之所以强调开发人员的作用，一个重要的原因是IT行业的技术变化速度非常之快。今天的新技术可能几年后就过时了。这种情况完全不同于其他行业。即使管理层里的以前干技术的人都要认识到进入管理层意味着他们的技术技能会很快消失。因此必须信任和依靠当前的开发人员。 <BR><BR>应用域专家的引领作用（The Role of Business Leadership） <BR>技术人员并不能包打天下，他们需要应用系统的需求分析，即他们需要与应用领域专家非常紧密的联系，这是适配性过程一个重要的方面。这种联系的紧密度远远超过了一般项目中应用领域分析人员的介入程度。如果开发人员和应用领域专家只有偶尔的沟通，那么敏捷型过程是不可能存在的。此外，这种沟通不是由管理层来处理的，而是每个开发人员需要做的事。因为开发人员在他们的行业里是有能力的专业人员，因此他们能够与其他行业的专业人员同等地在一起工作。 <BR><BR>这是由适配性过程的特点来决定的。因为在整个开发过程中，事情变化很快，你需要经常不断的联系沟通以使每个人都能及时知道这些变化。 <BR><BR>对开发人员来说，没有什么比看见自己的辛勤工作白白浪费更让人痛苦的了。因此，开发人员能随时获取准确的高质量的应用系统的（需求）知识就显得很重要了。 <BR><BR>自适配过程 <BR>到目前为止，我谈到的适配性是指在一个开发项目中如何频繁地修改软件以适应不断的需求变更。但是，还有另一种适配性，即是过程本身随着时间推移变化。一个项目在开始时用一个适配性过程，不会到一年之后还在用这个过程。随着时间的推移，开发组会发现他们的工作有些什么变化，然后改变过程以适应之。 <BR><BR>自适配的第一步是经常对过程进行总结检讨。一般来说，在每一次迭代结束后，你可以问自己如下问题〔Norm Kerth）： <BR><BR>有哪些做的好的部分 <BR>有哪些教训 <BR>有哪些可以改进的部分 <BR>有哪些没搞清楚的部分 <BR><BR>这些问题会帮助你考虑在下一次迭代中如何对过程进行修正。在样，如果开始时使用的过程有问题的话，随着项目的进行，该过程会得以逐步的完善，以使其能更好地适合开发组。 <BR><BR>如果一个项目采用了自适配方法，则可以进一步在一个组织内引入这种方法。如果要深化自适配过程，我建议开发人员专门用一段时间做一次更为正式的回顾总结，象Norm Kerth所建议的那样，这些活动包括离开工作地点，到另外一个地方开2－3天的总结会。这不仅是给开发组提供一次学习机会，同时也给整个组织一次学习机会。 <BR><BR>自适配性导致的结果是你绝不能期待着只用一个过程。相反，每个项目组不仅能选择他们自己的过程，并且还能随着项目的进行而调整所用的过程。公开发表的过程和其他项目的经验都可以拿来作为参考和样本。但是开发人员需根据手中项目的具体情况而对其加以调整，这也是开发人员的专业职责。 <BR><BR>这种自适配性在ASD和Crystal（水晶系列）中都鲜明地提及。XP的严格规则似乎不允许这样，但这只是表面现象，因为XP是鼓励调整过程的。这一点上XP和其他方法的主要区别之处在于，XP的倡导者建议在采用XP时，先根据书本循规蹈矩不走样地做几个迭代之后，再考虑调整。另外，回顾总结这点在XP 中没有被强调，也不是这个过程的组成部分，尽管XP建议经常性的回顾应作为XP的实践准则之一。 <BR><BR>敏捷型方法 <BR>好几个方法都可以归入敏捷型旗下，它们有许多的共同特征，但也有一些重要的不同之处。在此简短的综述中，我不可能列出这些过程所有的特点，但至少我可以告诉你可以到什么地方去查找更详细的材料。对大多数这些方法我都没有深入的实际经验。我有很多工作是基于XP的，也对RUP有些经验。但是对其他方法来说，我的知识主要是来自书本（当然这是很不够的）。 <BR><BR>XP（Extreme Programming －－ 极端编程） <BR>在所有的敏捷型方法中，XP是最为引人瞩目的。部分原因是因为XP的领军人物们的卓越能力，特别是Kent Beck，他能够把人们吸引到这种方法来，并一直处于领先地位。但是XP热也带来了一个问题，就是它把其他一些方法和它们非常有价值的思想给挤了出去。 <BR><BR>XP根源于Smalltalk圈子，特别是Kent Beck和Ward Cunningham在80年代末的密切合作。90年代初，他们在一系列项目上的实践深化扩展了他们关于软件开发应是适配性的、应以人为中心思想。 <BR><BR>从非正式的、探索性的实践到形成系统化的正规方法的关键一步是在1996年春。Kent被邀对Chrysler的一个工资管理项目（C3）的开发进度进行审核。该项目由一个签约公司用Smalltalk开发，正处于困境之中。由于源码质量低劣，Kent建议推倒重来。该项目然后在他的领导下从头开始并成了早期 XP的旗舰和培训基地。 <BR><BR>C3的第一期系统在1997年初投入运行。项目继续进行了一段时间后，遇到了麻烦，导致了在1999年开发计划被撤销。在我写此文时，该系统还在用来给万余员工发工资呢。 <BR><BR>XP的四条基本价值原则是：沟通，反馈，简单和勇气。在此基础上建立了十多条XP项目应遵循的实践准则。其实，许多准则是以前就存在的并经过实践检验的，而常常被忽略了的。XP重新建立了这些准则，并把它们编织成了一个和谐的整体，使得每一项准则都能在其他准则里得以强化。 <BR><BR>XP有一个最具冲击力的，也是最初吸引我的特点，是它对测试的极端重视。诚然，所有的过程都提到测试，但一般都不怎么强调。可是XP将测试作为开发的基础，要求每个程序员写一段源码时都得写相应的测试码。这些测试片段不断地积累并被整合到系统中。这样的过程会产生一个高度可靠的建造平台，为进一步开发提供了良好的基础。 <BR><BR>在此基础上XP建立了一个渐进型的开发过程，它依赖于每次迭代时对源码的重组（refactoring）。所有的设计都是围绕着当前这次迭代，而不管将来的需求。这种设计过程的结果是“纪律性”与“适配性”的高度统一，使得XP在适配性方法中成为发展的最好的一种方法。 <BR><BR>XP产生了一批领军人物，许多是从C3项目中出来的。关于XP有许多文献可读。最好的一篇总结文章是Jim Highsmith的Cutter论文（有趣的是Jim Highsmith并不是XP道中人，他的方法我将稍后介绍）。Kent Beck写的 Extreme Programming Explained，是一篇XP的宣言，它阐述了隐藏在 XP后面的道理。此书对有心于XP并致力于将其发扬光大者提供了充足的说明和解释。过去两年里也出版了一批“多姿多彩”的XP书籍，但多数都很相似，主要是从一些XP早期的实践者们的角度上描述了 XP的整个过程。 <BR><BR>除了书之外，还有不少网上资源。如果你想找到更有结构性的材料，你最好访问两位C3成员的网站：Ron Jefferies的 xProgramming.com 和Don Wells的 extremeProgramming.org。 Bill Wake的 xPlorations 里也有一些很有用的文章。许多XP早期的倡导和发展可在Ward Cunningham的 wiki web （合作写作）中找到。wiki是个令人着迷的地方，尽管它的漫游性质常令人身不由己的陷入其中。 Robert Martin是一位知名的C++和OO设计的专家，他也加入了XP鼓吹者行列。他的公司 ObjectMentor 网站上有不少文章论及XP，其中一篇提出可把XP看成是一个最小RUP实现，他称之为 dX。另外，他们也资助 XP讨论组〔xp discussion egroup）。还有一篇很有意思的文章从“外面”来审视XP，这就是Mark Paulk所写的从CMM的角度看XP。Mark Paulk是CMM的领军人物之一。 <BR><BR>Cockburn的水晶系列方法 <BR>Alistair Cockburn 在90年代初受IBM之约进行正规方法的研究。从那时起他就活跃于这个领域。他的研究途径和其他方法学者有所不同。一般的方法学者是将他们个人的经验升华成理论。而Cockburn除了归纳整理他自己的实践经验以外，他还积极地造访其他项目，和项目组成员进行广泛的讨论，考察这些项目是怎样运作的。难能可贵的是，他从不固守自己的观点，他会根据新的发现而随时修正自己的理论。他的这些特点使得他成为我最喜欢的方法学者。 <BR><BR>他的著作 “Surviving Object-Oriented Projects” 汇集了很多如何顺利运行软件开发项目的建议，此书也是我推荐的运行迭代式项目的首选书。最近，Alistair写了一本关于 敏捷型软件开发的综述性著作，探讨了这些方法的基本原则。 <BR><BR>Alistair还更进一步地探索了敏捷型方法，并提出了水晶（Crystal）方法系列。之所以是个系列，是因为他相信不同类型的项目需要不同的方法。他认为决定一个方法与两个因素有关：项目参与人数和出错后果。如果用两个坐标轴来分别表示这两个变量的话，那么在这张图上，每一种方法都有其相应的位置。例如，有两个项目，一个是有40人参加，如果失败造成的资金损失可以接受；另一个项目只有6人，其成败生存悠关。那么这两个项目所用的方法在坐标图上就有不同的位置。 <BR><BR>水晶系列与XP一样，都有以人为中心的理念，但在实践上有所不同。Alistair 考虑到人们一般很难严格遵循一个纪律约束很强的过程，因此，与XP的高度纪律性不同，Alistair探索了用最少纪律约束而仍能成功的方法，从而在产出效率与易于运作上达到一种平衡。也就是说，虽然水晶系列不如XP那样的产出效率，但会有更多的人能够接受并遵循它。 <BR><BR>Alistair也费了不少笔墨强调每次迭代后的总结回顾，因而鼓励过程本身的自我完善。他的理由是迭代式开发是用来尽早发现问题并解决之。这样就更加强调了开发人员要随时观察他们所用的过程，并随着项目的进行而调整。 <BR><BR>2001年2月，Alistair宣布他和Jim Highsmith将合并他们的方法。这个方法有何影响，如何命名，都还是有待回答的问题。 <BR><BR>开放式源码 <BR>看到这个标题你可能会有些意外。毕竟，开放式源码（Open Source）是软件的一类风格，而非一种过程。这里我是指开放源码界所用的一种运作方式，这种方式适用于开放源码项目，其实它的许多做法也可为封闭式源码项目所用。开放式源码项目有一个特别之处，就是程序开发人员在地域上分布很广。注意到这点相当重要，因为一般适配性过程都强调项目组成员在同一地点工作。 <BR><BR>多数开放源码项目有一个或多个源码维护者（maintainer）。只有维护者才能将新的或修改过的源码段并入源码库。其他众人可以修改源码，但需将他们所做的改动送交给维护者，由维护者对这些改动进行审核并决定是否并入源码库。通常来说，这些改动是以“补丁”（patch）文件的形式，这样处理起来容易一些。维护者负责协调这些改动并保持设计的一致性。 <BR><BR>维护者的角色在不同的项目中有不同的产生和处理方式。有些项目只有一个维护者，有些项目把整个系统分成若干个模块，每个模块有一个维护者。有些是轮流做维护者，有些是同一个源码部分有多个维护者，有些则是这些方式的组合。许多开放源码项目的参与者只是部分时间（或业余时间）干，如果项目要求是全日制的，那么这有一个问题，就是怎样才能把这些开发人员有效地协调组织起来。 <BR><BR>开放源码的一个突出特点就是查错排故（debug）的高度并行性，因为许多人都能同时参与查错排故。如果他们发现了错误，他们可将改正源码的 “补丁”文件发给维护者。这种查错排故角色对非维护者来说合适，对那些设计能力不是很强的人来说，也是一项挺好的工作。 <BR><BR>关于开放源码的方法过程还没有很系统的文献。目前最著名的一篇文章是 Eric Raymond写的 The Cathedral and the Bazaar（教堂与集市），文章虽短，但很精彩。另外，Karl Fogel所著的关于CVS的书中也有几章描述了开放源码的方法。即使你不想使用CVS，这几章还是值得一看。 <BR><BR>Highsmith的适配性软件开发方法（ASD－－Adaptive Software Development) <BR>Jim Highsmith 多年来一直从事可预性方法的研究，建立和教学，而最后得出的结论是这些方法都有着根本性的缺陷，特别是在用来作现代应用系统的开发时。 <BR><BR>他最近的 一本书 集中论述了新方法的适配特性，重点讨论了把一些起源于复杂适配性系统（通常称之为混沌理论－－chaos theory）的思想在软件开发中加以应用。此书没有象XP那样提供详尽的实践准则，但它从根本上说明了为什么适配性开发方法是重要的，并进一步说明了其对组织结构和管理层的影响。 <BR><BR>ASD的核心是三个非线性的、重迭的开发阶段：猜测，合作与学习。 <BR><BR>在一个适配性环境中，因为结果是不可预的，Highsmith把计划看成是一个 “反论”〔paradox）。在传统的计划中，偏离计划是错误，应予纠正。而在一个适配性环境里，偏离计划则是在引导我们向正确的目标迈进。 <BR><BR>在不可预的环境里，你需要大家能以多种多样的方式合作来对付不确定性。在管理上，其重点不在于告诉大家做什么，而是鼓励大家交流沟通，从而使他们能自己提出创造性的解决方案。 <BR><BR>在可预性环境里，通常是不大鼓励学习的。设计师已经都设计好了，你跟着走就行了。 <BR><BR>在适配性环境中，学习对所有各方，包括开发人员和客户， 都是一个挑战。他们需要学习以检验他们作的假设，需要学 习以便能用每次开发周期的结果去适配下一个周期。 <BR>-- Highsmith <BR><BR>这样的学习是连续不断的，这已成为这种方法的一个重要特点，因此我们必须得认识到计划和设计都得随开发的推进而改变。 <BR><BR>适配性开发周期的最大而不可见的好处是其对我们自以为是的心理 模式的挑战，它迫使我们更实际地估计自己的能力。 <BR>-- Highsmith <BR>有了这样的出发点，Highsmith把他的工作集中放在适配性开发的难点上，特别是如何在一个项目中增强合作和学习。基本上说，他的这本书是侧重于 “软”方法，这样对那些从开发实践中提炼出来的方法如XP，FDD 和水晶系列来说，这本书将是一个很有益的互补。因此Highsmith在2001年 2月宣布他将把他的方法于Cockburn的水晶系列合并，就是顺理成章并且很有意义的了。 <BR><BR>SCRUM <BR>SCRUM在OO界里已很有些时日了，不过我得承认我对其历史发展并不是太知其详。象前面所论及的方法一样，该方法强调这样一个事实，即明确定义了的可重复的（defined and repeatable）方法过程只限于在明确定义了的可重复的环境中，为明确定义了的可重复的人员所用，去解决明确定义了的可重复的问题。 <BR><BR>SCRUM把一个项目分成若干个为期30天的迭代阶段，称之为一“冲” （sprint）。开“冲”之前，你得明确这一“冲”要实现的功能，然后交给开发组去完成。但是，在“冲”期间，需求必须是固定的。 <BR><BR>管理人员并非在“冲”的时候就撒手不管了。每天，他需召集一个短会（15分钟左右），称之为一个scrum，会上大家讨论决定第二天干什么。特别是大家会对管理层提出那些阻碍项目进行的因素，并希望管理层能予以解决。当然，他们也需要报告目前完成了什么，这样管理层每天都能了然项目的进展情况。 <BR><BR>SCRUM文献多集中论述迭代阶段计划与进度跟踪。它与其他敏捷型方法在许多方面都很相似，特别是它可以与XP的编程准则很好地结合起来。 <BR><BR>相当长的一段时间没有关于SCRUM的专门书籍，直到最近 Ken Schwaber和Mike Beedle写了 第一本SCRUM的专著。Ken Schwaber还主持了一个网站 ControlChaos.com，可能是对SCRUM的最好的综述。Jeff Suthurland有个总是很活跃的网站讨论OO技术，其中有 一部分是专门讨论SCRUM的。另外，在 PLoPD 4书中也有一篇关于SCRUM的很好的综述。 <BR><BR>Coad的功用驱动开发方法（FDD－－Feature Driven Development） <BR>FDD是由Jeff De Luca和OO大师Peter Coad提出来的。象其他方法一样，它致力于短时的迭代阶段和可见可用的功能。在FDD中，一个迭代周期一般是两周。 <BR><BR>FDD有以下五项任务： <BR><BR>建立总体模型 <BR>提出功用清单 <BR>针对功用逐项制订计划 <BR>针对功用逐项进行设计 <BR>针对功用逐项开发实现 <BR><BR>头三项在项目开始时完成，后两项在每一次迭代周期时都要做。每一项任务又可进一步分解并制订出相应的检验准则。 <BR><BR>在FDD中，编程开发人员分成两类：首席程序员和“类”程序员（class owner）。首席程序员是最富有经验的开发人员，他们负责开发实现系统的各项功能。对每一项功能，首席程序员要定出需要哪些类（class）来实现这项功能，并召集“类”程序员们组成一个针对这项功能的开发组。首席程序员作为协调者，设计者和指导者，而“类”程序员则主要作源码编写。 <BR><BR>FDD的主要论述见于Peter Coad等所著的 UML in Color 。他的公司 TogetherSoft 也从事FDD的咨询和培训工作。 <BR><BR>动态系统开发方法〔DSDM－－Dynamic System Development Methods） <BR>DSDM在1994年始于英国。英国一些想用RAD和迭代方式进行系统开发的公司组成了一个社团〔Consortium）。刚开始有17个组建成员，到现在成员已超过1000个，遍布英国内外。DSDM由于是由一个社团所发展，它与其他一些敏捷型方法有些不同。它有专门的组织支持，有手册，培训课程，认证程序等。因为它上面的价格标签而限制了我对此方法的进一步调查。不过Jenifer Stapleton已写了 一本书来介绍这种方法。 <BR><BR>如果你要用这种方法，你得先作可行性和应用域分析。可行性分析要考虑 DSDM是否适合手上这个项目。而应用域分析则是开一系列的讨论会，以期能充分了解应用域，同时也要提出大致的系统结构与项目计划。 <BR><BR>余下的工作由三个互相交织的周期组成：功能模型周期产生文档和原型（实验系统），设计建造周期生成可操作使用的系统，实现周期处理系统安装部署（deployment）问题。 <BR><BR>DSDM有一些基本的原则包括与用户积极的沟通，频繁的出活（delivery）。有充分职权的项目组，完全的系统测试。象其他敏捷型方法一样， DSDM的一个周期在2－6周之间。它强调高质量的系统以及需求变更的高度适配性。 <BR><BR>我还没有在英国之外的地方看到有项目使用DSDM。DSDM的基本结构有许多成熟的传统方法的东西，同时又遵循了敏捷型途径。但这里的确有一点值得注意，即是这种方法是否有鼓励一种面向过程与繁琐的倾向。 <BR><BR>敏捷软件开发宣言 <BR>可以看出，前面所提到的这些方法有很多的相似之处，那么自然大家就会有兴趣进行某种形式的合作。 2001年2月，这些方法的代表人物们被邀至犹它州Snowbird 举行了一个为期两天的讨论会。我也在其列，但开始并未抱太大希望。毕竟，当你把一堆方法学者塞进一间房子时，他们能以礼相待就是上上大吉了。 <BR><BR>结果却出乎我的意料之外。每个与会者都认识到这些方法有许多的共同点，这种共识远远大于他们之间的分歧。这次讨论会使这些一流的方法学者们增进了联系，大家还有意发表一份联合声明－－呼吁推动发展敏捷型开发过程（我们也同意用“敏捷”（agile）这个词来表达我们共有的理念）。 <BR><BR>成果便是一份 敏捷软件开发宣言〔Manifesto for Agile Software Development），它表述了敏捷型过程所共同具备的价值和原则。与会者也有意在将来进一步合作，并鼓励方法学者与商界人士使用敏捷型方法进行软件开发。 Software Development Magazine〔软件开发杂志）有一篇关于 宣言的评注与解释的文章，它的片断可见于敏捷宣言的将来。 <BR><BR>RUP是一种敏捷型方法吗？ <BR>当我们开始讨论OO领域的方法时，不可避免地会碰到 RUP（Rational Unified Process）。该过程由Philippe Kruchten， Ivar Jacobson以及Rational Rose 的其他一些人士开发，主要是作为一个与UML相配合和补充的过程。RUP其实是个过程的框架，它可以包容许多不同类型的过程，这一点正是我对RUP的主要批评。因为它可以是任何东西，那么就跟什么都不是一样了。我愿意选择的过程是它能明确告诉你干什么，而不是给你无穷无尽的选择。 <BR><BR>由于RUP是一种框架，你可以以不同的方式来使用它，如象非常传统的“瀑布” 式开发方式，或敏捷式。你可以把用得轻捷灵便，也可把它弄成繁文缛节。这取决于你如何在你的环境中对它裁剪运用。 <BR><BR>Craig Larman极力主张以敏捷型方式来使用RUP。在他的关于OO开发的 引论著作中，他提出了一个过程，就是基于这种“轻型”RUP的思想。他的观点是：目前如此众多的努力以推进敏捷型方法，只不过是在接受能被视为RUP 的主流OO开发方法而已。在做一个项目时，Craig要干的事情之一便是在为期一月的迭代周期的头两三天和整个开发组呆在一起，用UML勾勒出这个迭代阶段的设计。这个设计并非是一个不可更改的，它只是一个使大家能知道这个阶段如何干的草图。 <BR><BR>另一种对待RUP的策略是Robert Martin的 dX过程。dX过程是一个完全符合RUP 的过程，而又碰巧与XP完全等同（把dX转180度可见，一句戏言）。dX是特别适合于那些不得不用RUP而又想用XP的伙计们。由于dX既是XP又同时是 RUP，它可作为以敏捷方式运用RUP的一个极好的例子。 <BR><BR>对我而言，在运用RUP时的一个关键之处在于业界RUP的领头者们需强调他们的软件开发途径。曾经不止一次，我听到使用RUP的人是在使用“瀑布”式开发过程。根据我在业界的联系，我知道Philippe Kruchten和他的小组是坚定的迭代式开发信奉者。澄清这些原则并鼓励敏捷式使用RUP，如象Craig Robert的工作，将对软件开发有着重要的影响和作用。 <BR><BR>其他参考材料 <BR>关于敏捷型方法有不少文章和讨论组，它们可能不会提供完整的方法，但可以给你一个窗口以观察这个正兴起的领域在如何发展。 <BR><BR>程序设计的模式语言（Patterns Language of Programming）大会经常会有一些材料讨论这个题目，这也许是因为许多对模式（Pattern）感兴趣者也对适配型和“人道”方法过程感兴趣的缘故吧。这方面有一篇早期的一流论文， Jim Coplein所著，收集在 PLoP1 中。Ward Cunningham的Episodes模式语言收集 PLoP2 中。Jim Coplein现主持一个网站， OrgPatterns，以wiki方式收集了不少组织结构模式。 Dirk Riehle在XP2000大会上提交了一篇论文，该文比较了XP和适配性软件开发（Adaptive Software Development, ASD）的 价值系统。Coad Letter的 七月期比较了XP和FDD。IEEE Software的七月期有几篇文章论述 “过程多样性”（process diversity），也提及这些方法。 <BR><BR>Mary Poppendieck写了一篇很精彩的文章 比较敏捷型方法与精悍（lean）型制造业。 <BR><BR>你是否应走向敏捷？ <BR>并非人人都能使用敏捷型方法。当你决定走这条路时，你得记住许多准则。但是，我确切相信，这些新方法可被广泛的应用。只是考虑使用它们远远不够，应该有更多的人来实践中运用它们。 <BR><BR>在目前的软件开发中，多数方法仍是边写边改（code and fix），那么，引入一些纪律约束肯定会比一片混乱要好。敏捷型途径的主要优点在于它比重型方法的步骤要少得多。如果你已习惯于无过程，那么遵循简单过程应该比遵循繁琐过程更容易一些。 <BR><BR>这些新方法的主要局限是如何对付较大的项目组。水晶类方法可在最多到50人的项目组内使用。如果超过了这个规模，则还没有证据或经验来说明如何运用这些适配性方法，甚至这些方法是否工作都很难说。 <BR><BR>这篇文章至少传递了这样一个信息，就是适配性方法对需求不确定或常常变更的情形是有效的。如果你没有稳定的需求，那么你就不可能进行稳定的设计并遵循一个计划好了的过程。这种情况下，适配性过程可能感觉上不太舒服，但实践上会更有效一些。通常来说，使用适配性方法最大的障碍来自客户。我认为，重要的一点是让客户理解在一个需求不断变更的环境中，遵循可预性过程对他们是有风险的，同样对开发方也是有风险的。 <BR><BR>你可能已注意到我说过50人以上的项目组应使用传统的可预性过程，需求不断变更的话，则应使用适配性过程。那么，如果你的项目很大而需求又在不断地变更，又当如何呢？对这个问题我并无一个满意的答案，我建议你去寻求其他意见。但我可以告诉你，这种情形下事情将会非常困难，不过我想你肯定已知道这一点了。 <BR><BR>如果你要采用适配性方法，你需要信任你的开发人员，并让他们参与（技术）决策。适配性过程的成功依赖于你对你的开发人员的信任。如果你认为你的开发人员素质不够，那么你应采用可预性途径。 <BR><BR>总结一下，如下的因素建议你采用适配性过程： <BR><BR>不确定或常变更的需求 <BR>负责任的，自觉自励的开发人员 <BR>理解并愿意参与其中的客户 <BR><BR>而如下这些因素则建议你使用可预性过程： <BR><BR>50人以上的项目组 <BR>固定价格，或更确切的说，固定任务范围的合同 <BR><BR>该用哪个适配性过程？ <BR>本文论及的这些适配性过程都还很新，我只能提供一些第一手经验以供参考。我对过程的选择通常视项目组人数，以及他们愿意遵循多少纪律规章而定。 <BR><BR>如果开发人员有十二个或以下，那么我肯定推荐XP。开发组有可能不会严格地把所有XP的过程都走一遍（特别是刚开始时），但这种部分XP过程仍能让你获益不少。我认为，用好XP的一个关键的部分是要将单元测试（unit test）自动化。如果开发组愿意这样做，系统就有了一个坚实的技术基础。如果他们不想这样干，我不怀疑他们自己就得来做这些测试。 <BR><BR>如果没有纪律规章，或项目组太大，那么我倾向于水晶系列。水晶系列肯定是敏捷型方法中最轻的，Cockburn特别主张吸取开发中的经验教训（而对过程进行调整）。不过，在这种情况下，我仍会用XP来作过程计划。 <BR><BR>我虽然这样说了，可是我现在的项目组有40人，我们成功地试验了许多XP准则，实际上也很接近完全的XP了。所以说，如果有一个有决心有热忱的团队，你在选择过程的时候，完全可以突破一些我提到的边界条件。 <BR><BR>还有一点非常关键，那就是不管你开始时用的是什么过程，该过程都不会是完全如你想象的那样得心应手，你得不停地对它进行监查与修改以适配你的环境。最后一点，它必须得是你自己的过程，其他标签都是次要的。 <BR><BR>鸣谢 <BR>本文得益于许多朋友的意见，恕难一一列出。但是，我要特别感谢Marc Balcer， Kent Beck，Alistair Cockburn，Ward Cunningham，Bill Kimmel 和Frank Westphal。 <BR><BR>请记住这是一篇不断改进的网络文章。我将附上主要修改记录，而小改动将不作记录。 <BR><BR>修改记录 <BR>2001年11月：更新一些最近的参考材料。 <BR>2001年3月： 加上关于“敏捷联盟”的内容。 <BR>2000年12月：本文缩写发表于Software Development杂志。 <BR>2000年11月：更新ASD部分并加上DSDM和RUP的章节。 <BR>2000年7月： 初稿发于martinfowler.com。 <BR><BR>-------------------------------------------------------------------------------- <BR><BR>译后注： <BR>我去年（2000年）曾参加过一个ECommerce系统的软件开发工作。这个项目采用了一种类似XP（极端编程）的开发方式，一个迭代周期约为三周，实现一项use case〔use case driven）。开发中特别强调单元测试（unit testing，使用JUnit）与每天的“冒烟测试”（smoke test）。今年〔2001年）初读到Martin Fowler的网站（http://www.martinfowler.com/）上的这篇 “The New Methodology”时，我正参加一个投资银行的证券分析信息系统的开发工作，该项目也采用了迭代式开发过程。但由于环境不同，这个项目的迭代周期较长一些，约六到八周。这个项目的另一个特点是开发人员和系统分析员〔business analysts）以及测试人员〔testers）的沟通特别频繁。读了这篇文章后，我觉得它能够让人从一个比较广阔而系统的角度来考察一个迭代式项目的运作。 <BR><BR>诚如作者所言，这是一篇不断改进的网络文章。我将尽力随原文的更新而及时更新译文。此译文中如有所译不当之处，望诸位同行不吝赐教。 <BR><BR>原文： <A class=ilink href="http://www.martinfowler.com/articles/newMethodology.html" target=_blank>http://www.martinfowler.com/articles/newMethodology.html</A> <BR>译文： <A class=ilink href="http://members.tripod.com/jian_hu/fowler/newMethodology.html" target=_blank>http://members.tripod.com/jian_hu/fowler/newMethodology.html</A> <BR>2001年12月：译自原文2001年11月版。 <BR>胡健 <BR>Email: jian4_hu2@hotmail.com <BR>Web: <A class=ilink href="http://members.tripod.com/jian_hu" target=_blank>http://members.tripod.com/jian_hu</A> </SPAN><img src ="http://www.blogjava.net/t19y80/aggbug/7278.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/t19y80/" target="_blank">Tianye</a> 2005-07-07 13:43 <a href="http://www.blogjava.net/t19y80/articles/7278.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Martin Fowler：持续集成</title><link>http://www.blogjava.net/t19y80/articles/7088.html</link><dc:creator>Tianye</dc:creator><author>Tianye</author><pubDate>Mon, 04 Jul 2005 05:37:00 GMT</pubDate><guid>http://www.blogjava.net/t19y80/articles/7088.html</guid><wfw:comment>http://www.blogjava.net/t19y80/comments/7088.html</wfw:comment><comments>http://www.blogjava.net/t19y80/articles/7088.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/t19y80/comments/commentRss/7088.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/t19y80/services/trackbacks/7088.html</trackback:ping><description><![CDATA[<P>在任何软件开发过程中都有一个重要的部分：得到可靠的软件创建（build）版本。尽管知道创建的重要性，但是我们仍然会经常因为创建失败而惊讶不已。在这篇文章里，我们将讨论Matt（Matthew Foemmel）在 ThoughtWorks的一个重要项目中实施的过程，这个过程在我们的公司里日益受到重视。它强调完全自动化的、可重复的创建过程，其中包括每天运行多次的自动化测试。它让开发者可以每天进行系统集成，从而减少了集成中 的问题。 </P>
<P>ThoughtWorks公司已经开放了CruiseControl软件的源代码，这是一个自动化持续集成的工具。此外，我们还提供CruiseControl、Ant和持续集成方面的顾问服务。如果需要更多的信息，请与Josh Mackenzie jmackenz@ThoughtWorks.com）联系。 </P>
<P></P>
<P>在软件开发的领域里有各种各样的“最佳实践”，它们经常被人们谈起，但是似乎很少有真正得到实现的。这些实践最基本、最有价值的就是：都有一个完全自动化的创建、测试过程，让开发团队可以每天多次创建他们的软件。“日创建”也是人们经常讨论的一个观点，McConnell在他的《快速软件开发》中将日创建作为一个最佳实践来推荐，同时日创建也是微软很出名的一项开发方法。但是，我们更支持XP社群的观点：日创建只是最低要求。一个完全自动化的过程让你可以每天完成多次创建，这是可以做到的，也是完全值得的。 </P>
<P></P>
<P>在这里，我们使用了“持续集成（Continuous Integration）”这个术语，这个术语来自于XP（极限编程）的一个实践。但是我们认为：这个实践早就存在，并且很多并没有考虑XP的人也在使用着它。只不过我们一直用 XP作为软件开发过程的标准，XP也对我们的术语和实践产生了深远的影响。尽管如此，你还是可以只使用持续集成，而不必使用XP的任何其他部分——实际上，我们认为：对于任何切实可行的软件开发活动，持续集成都是很 基本的组成部分。 </P>
<P></P>
<P>实现自动化日创建需要做以下几部分的工作：</P>
<OL>
<LI>将所有的源代码保存在单一的地点，让所有人都能从这里获取最新的源代码（以及以前的版本）。 
<LI>使创建过程完全自动化，让任何人都可以只输入一条命令就完成系统的创建。 
<LI>使测试完全自动化，让任何人都可以只输入一条命令就运行一套完整的系统测试。 
<LI>确保所有人都可以得到最新、最好的可执行文件。 </LI></OL>
<P>所有这些都必须得到制度的保证。我们发现，向一个项目中引入这些制度需要耗费相当大的精力。但是，我 们也发现，一旦制度建立起来，保持它的正常运转就不需要花多少力气了。 </P>
<P></P><A name=N10028></A><A name=""></A>
<H2 class=boxed>持续集成的优点 </H2>
<DIV class=section>
<P>描述持续集成最大的难点在于：它从根本上改变了整个开发模式。如果没有在持续集成的实践环境中工作过，你很难理解它的开发模式。实际上，在单独工作的时候，绝大多数人都能感觉到这种气氛——因为他们只需要与自己的系统相集成。对于许多人来说，“团队开发”这个词总让他们想起软件工程领域中的一些难题。持续集成减少了这些难题的数量，代之以一定的制度。 </P>
<P></P>
<P>持续集成最基本的优点就是：它完全避免了开发者们的“除虫会议”——以前开发者们经常需要开这样的会，因为某个人在工作的时候踩进了别人的领域、影响了别人的代码，而被影响的人还不知道发生了什么，于是 bug就出现了。这种bug是最难查的，因为问题不是出在某一个人的领域里，而是出在两个人的交流上面。随着时间的推移，问题会逐渐恶化。通常，在集成阶段出现的bug早在几周甚至几个月之前就已经存在了。结果，开发者需要在集成阶段耗费大量的时间和精力来寻找这些bug的根源。 </P>
<P></P>
<P>如果使用持续集成，这样的bug绝大多数都可以在引入的同一天就被发现。而且，由于一天之中发生变动的部分并不多，所以可以很快找到出错的位置。如果找不到bug究竟在哪里，你也可以不把这些讨厌的代码集成到产品中去。所以，即使在最坏的情况下，你也只是不添加引起bug的特性而已。（当然，可能你对新特性的要求胜过了对bug的憎恨，不过至少你可以多一种选择。） </P>
<P></P>
<P>到现在为止，持续集成还不能保证你抓到所有集成时出现的bug。持续集成的排错能力取决于测试技术，众 所周知，测试无法证明已经找到了所有的错误。关键是在于：持续集成可以及时抓到足够多的bug，这就已经值 回它的开销了。 </P>
<P></P>
<P>所以，持续集成可以减少集成阶段“捉虫”消耗的时间，从而最终提高生产力。尽管现在还不知道是否有人 对这种方法进行过科学研究，但是作为一种实践性的方法，很明显它是相当有效的。持续集成可以大幅减少耗费 在“集成地狱”中的时间，实际上，它可以把地狱变成小菜一碟。 </P>
<P></P></DIV><A name=N1003C></A><A name=""></A>
<H2 class=boxed>集成越频繁，效果越好 </H2>
<DIV class=section>
<P>持续集成有一个与直觉相悖的基本要点：经常性的集成比很少集成要好。对于持续集成的实践者来说，这是 很自然的；但是对于从未实践过持续集成的人来说，这是与直观印象相矛盾的。 </P>
<P></P>
<P>如果你的集成不是经常进行的（少于每天一次），那么集成就是一件痛苦的事情，会耗费你大量的时间与精 力。我们经常听见有人说：“在一个大型的项目中，不能应用日创建”，实际上这是一种十分愚蠢的观点。 </P>
<P></P>
<P>不过，还是有很多项目实践着持续集成。在一个五十人的团队、二十万行代码的项目中，我们每天要集成二 十多次。微软在上千万行代码的项目中仍然坚持日创建。 </P>
<P></P>
<P>持续集成之所以可行，原因在于集成的工作量是与两次集成间隔时间的平方成正比的。尽管我们还没有具体的衡量数据，但是可以大概估计出来：每周集成一次所需的工作量绝对不是每天集成的5倍，而是大约25倍。所以，如果集成让你感到痛苦，也许就说明你应该更频繁地进行集成。如果方法正确，更频繁的集成应该能减少你的痛苦，让你节约大量时间。 </P>
<P></P>
<P>持续集成的关键是自动化。绝大多数的集成都可以而且应该自动完成。读取源代码、编译、连接、测试，这些都可以自动完成。最后，你应该得到一条简单的信息，告诉你这次创建是否成功：“yes”或“no”。 如果成功，本次集成到此为止；如果失败，你应该可以很简单地撤消最后一次的修改，回到前一次成功的创建。在整个 </P>
<P>创建过程中，完全不需要你动脑子。 </P>
<P></P>
<P>如果有了这样一套自动化过程，你随便想多频繁进行创建都可以。唯一的局限性就是创建过程本身也会消耗 一定的时间。（译注：不过与捉虫所需的时间比起来，这点时间是微不足道的。） </P>
<P></P></DIV><A name=N10055></A><A name=һ></A>
<H2 class=boxed>一次成功的创建是什么样的？ </H2>
<DIV class=section>
<P>有一件重要的事需要确定：怎样的创建才算是成功的？看上去很简单，但是如此简单的事情有时却会变得一团糟，这是值得注意的。有一次，Martin Fowler去检查一个项目。他问这个项目是否执行日创建，得到了肯定 的回答。幸亏Ron Jeffries也在场，他又提了一个问题：“你们如何处理创建错误？”回答是：“我们给相关的人发一个e-mail。”实际上，这个项目已经好几个月没有得到成功的创建了。这不是日创建，这只是日创建的尝 试。 </P>
<P></P>
<P>对于下列“成功创建”的标准，我们还是相当自信的： </P>
<OL>
<LI>所有最新的源代码都被配置管理系统验证合格； 
<LI>所有文件都通过重新编译； 
<LI>得到的目标文件（在我们这里就是Java的class文件）都通过连接，得到可执行文件； 
<LI>系统开始运行，针对系统的测试套件（在我们这里大概有150个测试类）开始运行。 </LI></OL>
<P>如果所有的步骤都没有错误、没有人为干涉，所有的测试也都通过了，我们就得到了一个成功的创建 </P>
<P>绝大多数人都认为“编译+连接=创建”。至少我们认为：创建还应该包括启动应用程序、针对应用程序运行 简单测试（McConnell称之为“冒烟测试”：打开开关让软件运行，看它是否会“冒烟”）。</P>
<P>运行更详尽的测试 集可以大大提高持续集成的价值，所以我们会首选更详尽的测试。 </P>
<P></P></DIV><A name=N1006F></A><A name=""></A>
<H2 class=boxed>单一代码源 </H2>
<DIV class=section>
<P>为了实现每日集成，任何开发者都需要能够很容易地获取全部最新的源代码。以前，如果要做一次集成，我 们就必须跑遍整个开发中心，询问每一个程序员有没有新的代码，然后把这些新代码拷贝过来，再找到合适的插 入位置……没有什么比这更糟糕的了。 </P>
<P></P>
<P>办法很简单。任何人都应该可以带一台干净的机器过来，连上局域网，然后用一条命令就得到所有的源文 件，马上开始系统的创建。 </P>
<P></P>
<P>最简单的解决方案就是：用一套配置管理（源代码控制）系统作为所有代码的来源。配置管理系统通常都设计有网络功能，并且带有让开发者轻松获取源代码的工具。而且，它们还提供版本管理工具，这样你可以很轻松地找到文件以前的版本。成本就更不成问题了，CVS就是一套出色的开放源代码的配置管理工具。 </P>
<P></P>
<P>所有的源文件都应该保存在配置管理系统中。我说的这个“所有”常常比人们想到的还要多，它还包括创建脚本、属性文件、数据库调度DLL、安装脚本、以及在一台干净的机器上开始创建所需的其他一切东西。经常都能看到这样的情况：代码得到了控制，但是其他一些重要的文件却找不到了。 </P>
<P></P>
<P>尽量确保所有的东西都保存在配置管理系统的同一棵代码源树中。有时候为了得到不同的组件，人们会使用配置管理系统中不同的项目。这带来的麻烦就是：人们不得不记住哪个组件的哪个版本使用了其他组件的哪些版本。在某些情况下，你必须将代码源分开，但是这种情况出现的几率比你想象的要小得多。你可以在从一棵代码源树创建多个组件，上面那些问题可以通过创建脚本来解决，而不必改变存储结构。 </P>
<P></P></DIV><A name=N10083></A><A name=""></A>
<H2 class=boxed>自动化创建脚本 </H2>
<DIV class=section>
<P>如果你编写的是一个小程序，只有十几个文件，那么应用程序的创建可能只是一行命令的事：javac *.java。更大的项目就需要更多的创建工作：你可能把文件放在许多目录里面，需要确保得到的目标代码都在适当的位置；除了编译，可能还有连接的步骤；你可能还从别的文件中生成了代码，在编译之前需要先生成；测试 也需要自动运行。 </P>
<P></P>
<P>大规模的创建经常会耗费一些时间，如果只做了一点小小的改动，当然你不会希望重新做所有这些步骤。所以好的创建工具会自动分析需要改变的部分，常见的方法就是检查源文件和目标文件的修改日期，只有当源文件的修改日期迟于目标文件时，才会重新编译。于是，文件之间的依赖就需要一点技巧了：如果一个目标文件发生 </P>
<P>了变化，那么只有那些依赖它的目标文件才会重新编译。编译器可能会处理这类事情，也可能不会。 </P>
<P></P>
<P>取决于自己的需要，你可以选择不同的创建类型：你创建的系统可以有测试代码，也可以没有，甚至还可以 选择不同的测试集；一些组件可以单独创建。创建脚本应该让你可以根据不同的情况选择不同的创建目标。 </P>
<P></P>
<P>你输入一行简单的命令之后，帮你挑起这副重担常常是脚本。你使用的可能是shell脚本，也可能是更复杂 的脚本语言（例如Perl或Python）。但是很快你就会发现一个专门设计的创建环境是很有用的，例如Unix下的make工具。 </P>
<P></P>
<P>在我们的Java开发中，我们很快就发现需要一个更复杂的解决方案。Matt用了相当多的时间开发了一个用于企业级Java开发的创建工具，叫做Jinx。但是，最近我们已经转而使用开放源代码的创建工具Ant （http://jakarta.apache.org/ant/index.html）。Ant的设计与Jinx非常相似，也支持Java文件编译和 Jar封 装。同时，编写Ant的扩展也很容易，这让我们可以在创建过程中完成更多的任务。 </P>
<P></P>
<P>许多人都使用IDE，绝大多数的IDE中都包含了创建管理的功能。但是，这些文件都依赖于特定的IDE，而且经常比较脆弱，而且还需要在IDE中才能工作。IDE的用户可以建立自己的项目文件，并且在自己的单独开发中使用它们。但是我们的主创建过程用Ant建立，并且在一台使用Ant的服务器上运行。 </P>
<P></P></DIV><A name=N1009C></A><A name=""></A>
<H2 class=boxed>自测试的代码 </H2>
<DIV class=section>
<P>只让程序通过编译还是远远不够的。尽管强类型语言的编译器可以指出许多问题，但是即使成功通过了编 译，程序中仍然可能留下很多错误。为了帮助跟踪这些错误，我们非常强调自动化测试——这也是XP提倡的另一 个实践。 </P>
<P></P>
<P>XP将测试分为两类：单元测试和容纳测试（也叫功能测试）。单元测试是由开发者自己编写的，通常只测试一个类或一小组类。容纳测试通常是由客户或外部的测试组在开发者的帮助下编写的，对整个系统进行端到端的测试。这两种测试我们都会用到，并且尽量提高测试的自动化程度。 </P>
<P></P>
<P>作为创建的一部分，我们需要运行一组被称为“BVT”（Build Verification Tests，创建确认测试）的测试。BVT中所有的测试都必须通过，然后我们才能宣布得到了一个成功的创建。所有XP风格的单元测试都属于 BVT。由于本文是关于创建过程的，所以我们所说的“测试”基本上都是指BVT。请记住，除了BVT之外，还有一条测试线存在（译注：指功能测试），所以不要把BVT和整体测试、QA等混为一谈。实际上，我们的QA小组根本不会看到没有通过BVT的代码，因为他们只对成功的创建进行测试。 </P>
<P></P>
<P>有一条基本的原则：在编写代码的同时，开发者也应该编写相应的测试。完成任务之后，他们不但要归还 （check in）产品代码，而且还要归还这些代码的测试。这也跟XP的“测试第一”的编程风格很相似：在编写完相应的测试、并看到测试失败之前，你不应该编写任何代码。所以，如果想给系统添加新特性，你首先应该编写一个测试。只有当新的特性已经实现了以后，这个测试才可能通过。然后，你的工作就是让这个测试能够通过。 </P>
<P></P>
<P>我们用Java编写这些测试，与开发使用同样的语言，所以编写测试与编写代码没有太大的区别。我们使用JUnit（http: //www.junit.org/）来作为组织、编写测试的框架。JUnit是一个简单的框架，让我们可以快速编写测试、将测试组织为套件、并以交互或批处理的模式来运行测试套件。（JUnit是xUnit家族的Java版本 ——xUnit包括了几乎所有语言的测试框架。） </P>
<P></P>
<P>在编写软件的过程中，在每一次的编译之后，开发者通常都会运行一部分单元测试。这实际上提高了开发者的工作效率，因为这些单元测试可以帮助你发现代码中的逻辑错误。然后，你就没必要去调试查错，只需要注意最后一次运行测试之后修改的代码就行了。这个修改的范围应该很小，所以寻找bug也就容易多了。 </P>
<P></P>
<P>并非所有的人都严格遵循XP“测试第一”的风格，但是在第一时间编写测试的好处是显而易见的。它们不但让每个人的工作效率更高，而且由这些测试构成的BVT更能捕捉到系统中的错误。因为BVT每天要运行好几次，所以BVT检查出的任何问题都是比较容易改正的，原因很简单：我们只做了相当小范围的修改，所以我们可以在这个范围内寻找bug。在修改过的一小块代码中排错当然比跟踪整个系统来排错要有效多了。 </P>
<P></P>
<P>当然，你不能指望测试帮你找到所有的问题。就象人们常说的：测试不能证明系统中不存在错误。但是，尽 善尽美不是我们唯一的要求。不够完美的测试只要经常运行，也比永远写不出来的“完美测试”要好得多。 </P>
<P></P>
<P>另一个相关的问题就是：开发者们为自己的代码编写测试。我们经常听人说：开发者不应该测试自己的代码，因为他们很容易忽视自己工作中的错误。尽管这也是事实，但是自测试过程需要快速将测试转入代码基础中。这种快速转换的价值超过独立测试者的价值。所以，我们还是用开发者自己编写的测试来构造BVT，但是仍 然有独立编写的容纳测试。 </P>
<P></P>
<P>自测试另一个很重要的部分就是它通过反馈——XP的一项核心价值——来提高测试的质量。这里的反馈来自于从BVT中逃脱的bug。自测试的规则是：除非你在BVT中加入了相应的测试，否则就不能修正任何错误。这样，每当要修正某个错误的时候，你都必须添加相应的测试，以确保BVT不会再把错误放过去。而且，这个测试应该引导你去考虑更多的测试、编写更多的测试来加强BVT。 </P>
<P></P></DIV><A name=N100BF></A><A name=""></A>
<H2 class=boxed>主创建 </H2>
<DIV class=section>
<P>创建过程的自动化对于单个开发者来说很有意义，但是它真正发光的，还是在整个系统的主创建（master build）的生成。我们发现，主创建过程能让整个团队走到一起来，让他们及早发现集成中的问题。 </P>
<P></P>
<P>第一步是要选择运行主创建的机器。我们选择了一台叫做“投石车”的计算机（我们经常玩“帝国时代” J），这是一台装有四个CPU的服务器，非常适合专门用来做创建。（由于完整的创建需要相当长的时间，所以这 种马力是必须的。） </P>
<P></P>
<P>创建进程是在一个随时保持运行的Java类中进行的。如果没有创建任务，创建进程就一直循环等待，每过几 分钟去检查一下代码仓库。如果在最后的创建之后没有人归还任何代码，进程就继续等待。如果代码仓库中有了 新的代码，就开始创建。 </P>
<P></P>
<P>创建的第一阶段是完全提取仓库中的代码。Starteam已经为我们提供了相当好的Java API，所以切入代码仓库也很容易。守护进程（daemon）会观察五分钟以前的仓库，看最近五分钟里面有没有人归还了代码。如果有，守护进程就会考虑等五分钟再提取代码（以免在别人归还代码的过程中提取）。 </P>
<P></P>
<P>守护进程将全部代码提取到投石机的一个目录中。提取完成之后，守护进程就会在这个目录里调用Ant脚本。然后，Ant会接管整个创建过程，对所有源代码做一次完整的创建。Ant脚本会负责整个编译过程，并把得到的class文件放进六个jar包里，发布到EJB服务器上。 </P>
<P></P>
<P>当Ant完成了编译和发布的工作之后，创建守护进程就会在EJB服务器上开始运行新的jar，同时开始运行BVT 测试套件。如果所有的测试都能正常运行通过，我们就得到了一个成功的创建。然后创建守护进程就会回到 Starteam，将所有提取出的源代码标记上创建号。然后，守护进程会观察创建过程中是否还有人归还了代码。如果有，就再开始一次创建；如果没有，守护进程就回到它的循环中，等待下一次的归还。 </P>
<P></P>
<P>创建结束之后，创建守护进程会给所有向最新一次创建归还了代码的开发者发一个e-mail，汇报创建的情 况。如果把创建留在代码归还之后去做，而又不用e-mail向开发者通报创建的情况，我们通常认为这是不好的组 织形式。 </P>
<P></P>
<P>守护进程将所有的步骤都写在XML格式的日志文件里面。投石车上会运行一个servlet，允许任何人通过它检 查日志，以观察创建的状态。（见图1） </P>
<P></P>
<P>屏幕上会显示出创建是否正在运行、开始运行的时间。在左边有所有创建的历史记录，成功的、失败的都记 录在案。点击其中的某一条记录，就会显示出这次创建的详细信息：编译是否通过、测试的结果、发生了哪些变 化…… </P>
<P></P>
<P>我们发现很多开发者都经常看看这个页面，因为它让他们看到项目发展的方向，看到随着人们不断归还代码 而发生的变化。有时我们也会在这个页面上放一些其他的项目新闻，但是需要把握好尺度。 </P>
<P></P>
<P>要让开发者能在自己的本地机器上模拟主创建过程，这是很重要的。这样，如果集成错误出现了，开发者可 以在自己的机器上研究、调试，而不必真的执行主创建过程。而且，开发者也可以在归还代码之前先在本地执行 创建，从而降低了主创建失败的可能性。 </P>
<P></P>
<P>这里有一个比较重要的问题：主创建应该是干净的创建（完全从源代码开始）还是增量创建？增量创建会快得多，但是也增大了引入错误的风险，因为有些部分是没有编译的。而且我们还有无法重新创建的风险。我们的创建速度相当快（20万行代码约15分钟），所以我们乐于每次都做干净的创建。但是，有些团队喜欢在大多数时候做增量创建，但是当那些奇怪的问题突然出现时，也经常性地做干净的创建（至少每天一次）。 </P>
<P></P>
<P></P>
<P>图1：运行在投石车上的servlet </P>
<P></P></DIV><A name=N100EC></A><A name=""></A>
<H2 class=boxed>代码归还（Check in） </H2>
<DIV class=section>
<P>使用自动化创建就意味着开发者应该遵循某种节奏来开发软件，最重要的就是他们应该经常集成。我们曾经见过一些组织，他们也做日创建，但是其中的开发者却不经常归还代码。如果开发者几周才归还一次代码，那么日创建又有什么意义呢？我们遵循的原则是：每个开发者至少每天要归还一次代码。 </P>
<P></P>
<P>在开始新的任务之前，开发者应该首先与配置管理系统同步。也就是说，他们应该首先更新本地机器上的源 代码。在旧的代码基础上编写代码，这只会带来麻烦和混乱。 </P>
<P></P>
<P>然后，开发者要随时保持文件的更新。开发者可以在一段任务完成之后将代码集成到整个系统中，也可以在 任务的中途集成，但是在集成的时候必须保证所有的测试都能通过。 </P>
<P></P>
<P>集成的第一步是要再次使开发者的本地文件与代码仓库同步。代码仓库中所有新近有改动的文件都要拷贝到 开发者的工作目录中来，当文件发生冲突时，配置管理系统会向开发者提出警告。然后，开发者需要对同步后的 工作集进行创建，对这些文件运行BVT，并得到正确的结果。 </P>
<P></P>
<P>现在，开发者可以把新的文件提交到代码仓库中。提交完成之后，开发者就需要等待主创建。如果主创建成功，那么这次归还也是成功的。如果主创建失败了，开发者可以在本地修改。如果修改很简单，就可以直接提交；如果修改比较复杂，开发者就需要放弃这次修改，重新同步自己的工作目录，然后继续在本地开发、调试,然后再次提交。 </P>
<P></P>
<P>某些系统强制要求归还进程逐个进行。在这种情况下，系统中会有一个创建令牌，同一时间只有一个开发者能拿到令牌。开发者获取创建令牌，再次同步文件，提交修改，然后释放令牌。这就确保创建过程中，最多只能有一个开发者在更新代码仓库。不过我们发现，即使没有创建令牌，我们也很少遇到麻烦，所以我们也不用这种方法。经常会有多个人同时向同一个主创建提交代码的情况，但是这很少造成创建失败，而且这样的错误也很容 易修复。 </P>
<P></P>
<P>同时，我们还让开发者自己来决定归还过程中的小心程度。这反映出开发者对集成错误出现几率的评估。如果她觉得很有可能出现集成错误，那么她就会在归还之前先做一次本地创建；如果她觉得根本不可能出现集成错误，那么她可以直接归还。如果犯了错误，在主创建运行时她立刻就会发现，然后她就必须放弃自己的修改，找到出错的地方。如果错误很容易发现、很容易修补，那么这种错误也是可以接受的。 </P>
<P></P></DIV><A name=N10106></A><A name=""></A>
<H2 class=boxed>总结 </H2>
<DIV class=section>
<P>发展一个制度严密的自动化创建过程对于项目的控制是很重要的。许多软件先贤都这样说，但是我们发现， 这样的过程在软件开发领域中仍然罕见。 </P>
<P></P>
<P>关键是要让所有的事情都完全自动化，并且要经常进行集成，这样才能尽快发现错误。然后，人们可以随时 修改需要修改的东西，因为他们知道：如果他们做的修改引起了集成错误，那也是很容易发现和修补的。一旦获得了这些利益，你会发现自己再也无法放下它们。 </P></DIV><img src ="http://www.blogjava.net/t19y80/aggbug/7088.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/t19y80/" target="_blank">Tianye</a> 2005-07-04 13:37 <a href="http://www.blogjava.net/t19y80/articles/7088.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>