2009年3月26日星期四

《持续集成》的译者序

我发现在项目团队中真正实现持续集成是一件不容易的事情,因为需要改变一个团队做事的方式和习惯。这里特别把当初写的译者序贴出来,并郑重向大家推荐这本书。下面是原文:

软件项目开发有两大难题:一是确定软件的需求,即确定目标;二是确定目前离目标还有多远,即确定剩余的工作量。第二个问题就是项目缺少可见性的问题,这对“人月神话”做出了“巨大贡献”。当一个项目经理或一名开发者说已经完成了80%的任务,您必须保持审慎的乐观。因为剩下的20%可能还需要80%的时间,甚至永远也不能完成。您可能迟迟不能拿到可以部署的软件,对此所有的人都无能为力,只能表示深深的遗憾。这确实让专业软件开发者的声誉蒙羞。但是对于大型软件开发这样的复杂工作,我们的经验确实显得有些不够。

《持续集成》这本书向我们介绍了一种增加项目可见性、降低项目失败风险的有效实践。许多软件开发的资深人士认定,这种方法非常不错。我们不必把宝全部押在最后那一次“大爆炸”式的集成上,而是采用“早集成、常集成”的策略。这样做可以减少缺陷引入和缺陷发现之间的时间,提高开发效率,降低风险。您对项目完成百分比的报告将有更大的信心,而且任何时候,您都可以得到一个可以部署的软件。虽然功能可能还没有全部实现,但它是可用的!

这本书向我们揭示了这样一个道理:如果一件事很难,而您又必须做,不妨经常去做,每次做一点点。其实这也是古老的“分而治之”思想的一种应用。滴水穿石,跬步千里。
敏捷软件开发的许多实践都是互相关联的。持续集成在与其他实践结合时,才能将它的效用发挥到极致。这本书除了介绍
CI的基本原则和工具之外,也介绍了如何将测试驱动、代码审查、数据库集成、信息反馈等实践和工具。人(思想)、过程和自动化工具的完美结合,将形成一个和谐的开发生态环境。如果您一直在追求效率更高的软件项目管理方法,我相信这本书一定能给你带来一些启发和灵感。

一本好书使您改变。它将改变您的思想,您看待问题的角度和方式,最终,它将改变您的行为。然而,所有具有重要意义的改变都不会在一夜之间发生。改变随时都在发生,但按照您的意志去领导变革却很难。如果您相信这种变革必须发生,不妨朝着这个方向去努力,经常改变,每次改变一点点。

软件业中没有银弹,不可能有某种东西在短时间内让您的开发效率提高
10倍。但是我们也很容易发现不同个人和不同团队之间的开发效率相差巨大,不止10倍。那些软件高手和明星团队就像职业围棋选手,他们高得惊人的效率是多年用心改进实践的结果。

在这本书的翻译过程中,我学到了很多,因此郑重地向大家推荐它。如果这本书对于您改进软件开发实践有所帮助,我将十分高兴。

2009年3月20日星期五

Socket编程和协议设计

眼下在写的一个程序涉及Socket编程,最初我写的是Java tutorial上推荐的方法,即封装出BufferedReader,再调用readLine()方法。然而请求发出去之后,却阻塞在readLine()上了,没有读到预期的应答数据。

基于TCP协议应用协议有一个好处,可以用telnet来调试。于是我祭起Putty,发起请求,这下看到了预期的应答数据。

我的程序错在哪里?错在readLine(),它要等待一个'\n'。而按照应用协议的规定,不会在一次应答结束时返回'\n'。所以readLine阻塞了。

正确的写法应该是怎样的?只从socket读取一次数据是不对的。由于网络延时是不确定的,所以读一次数据不知道是否读到了完整的应答。一定要根据应用协议的规定,读到结束字段。而这个应用协议规定了用''分隔字段。于是我必须根据应答字段的个数进行读取,直到读完一条完整应答为止。

事情还没完。根据请求是否成功,服务器应答信息的字段数是不一样的。所以应答读取的程序应该先读到成功失败标识,再判断成功失败,读取后面的应答字段。

这导致了协议对话部分的程序相当复杂,而这种复杂本来是可以避免的。为什么会出现这样的结果?

原来的协议还附了一段C程序例子。正是这段例子,让我对问题的原因有了一个大概的猜测。

这段C程序初始化了一个缓冲区,并往里面填充了0。然后从socket中进行了一次读取,放在缓冲区中。不幸的是,这段程序是错误的。因为网络延时不确定,所以读取的数据可能是不完整的应答。写例子的人就当它是完整应答了!这样写是简单,但是却是错的。

我想,如果设计协议和写C例子的人(可能是一个人)如果概念清楚,还是会把协议设计成以'\n'来结束一次应答吧。

2009年3月19日星期四

FDD伸缩性和实现客户价值的TOC理论

FDD在敏捷方法学中最独特之处就在于,它声称可以实现伸缩性和可重复的成功。那么,它的这一特征有什么意义呢?

前两天,我刚好看到James Shore的一份Presentation,其中提到增加客户价值的5种方式,真是敏捷方法学的强人,抓住了客户价值这一点不放。

提到这份Presentation的原因是,他的5种方式中的第一种要求一个团队同时只做一个项目。他的图示说明非常具有说服力,一下子就让我完全同意。但接下来问题出现了,如果是一个千人的公司,同时也只做一个项目?这是不是有点荒唐?他自己也意识到了这一点。

关键之处仍是大部分敏捷方法学的软肋:可伸缩性不好。

FDD声称可以适应很大的项目,于是我们可以设想这样的场景:一个50人15个月规模的项目(新加坡项目的规模),如果给我750人,那么1个月就搞定了!这将为客户提前14个月获得投资回报。如果真能实现这一点,我想世界会震惊的。

干一个月的活,收钱。这是我喜欢的方式。干一天的活,收钱,这是我爱的方式。

好吧,我承认,我身体里理想主义的部分和浪漫主义诗人气质在发挥作用了。事实上,这样的事情还没有发生。存在就是合理。合理之处在哪里?有什么理论支持?

实际上,IT系统为业务带来价值不是只有开发这一个环节。存在着一个“开发-实施-反馈-接受”的循环。假设750个人一个月开发了1500个特征,这将在业务部门带来巨大的冲击。只要想想ERP的实施就知道了。按照TOC的理论,实施、反馈、接受的环节将成为实现客户价值流水线上的新瓶颈。

按照精益制造的思想,一个环节的产能超出系统其他部分的产能太多,绝对是坏事而不是好事。我们应该根据系统的总吞吐量,不断发现新的瓶颈,提升瓶颈的产能。

不管怎么说,这样想想还是挺妙的。现在瓶颈不在我负责的这一块了。也许在不久的将来,企业能够接受一下实施1500个新特征的冲击。

2009年3月17日星期二

Mediator模式


一个朋友问起Mediator模式,为什么类图中具体类之间存在着依赖关系?这样耦合是不是太厉害?是不是“Gang of Four”当年不太严谨所致?

这要从Mediator模式要解决的问题说起。Mediator模式是为了解决对象间多对多的通信协议问题。碰巧的是,我在《基于组件开发》一书中也读到了相关的内容。

如果A组中的M个对象与B组中的N个对象相互之间都需要通信,那么在未使用Mediator之前,它们之间需要M*N个通信协议。这在对象很多的情况下很麻烦,在添加一个对象时要做的工作也很多。

“所有问题,都可以通过添加一个间接的中间层来解决”。所以我们引入Mediator作为中间层,它的工作就是进行协议翻译。设计一个中间表示模式,实现所有对象通信协议到中间表示模式的翻译。这样,原来的M*N个通信协议就变成了M+N个通信协议。在添加一个新的通信对象时,也只要增加一种互译协议。

回到朋友的问题。根据这样的设计,Mediator必须知道如何完成这种协议翻译。因此,它必须了解具体参与通信对象的协议实现方式。所以,Mediator的实现就依赖于通信对象的实现了。

CORBA就是这样的一个例子。当然,我们可以把协议翻译这一块拿出来,做成一个协议适配器,通过再添加一个中间层,消除Mediator的具体实现与通信对象的具体实现之间的耦合,这是故事的续集。

我们还可以让通信对象各自负责实现协议翻译。毕竟,架构就是系统由哪些组件构成以及这些组件之间的关系。猜猜我们得到了什么?MQ(消息队列)/MOM(基于消息的中间件)/ESB(企业服务总线)!

2009年3月4日星期三

免费的UML建模工具

ArgoUML。画出的图中规中矩,不能算漂亮。项目一直没太大动静,据说最近又活跃了。

StarUML。画出的图不够漂亮。似乎是韩国人用Delphi写的。据说停止开发很久了。

Netbeans的UML模块。6.5以后的免费UML模块由Visual Paradigm接手继续做了,易用性方面有明显改进,图也一如既往地漂亮。这是我主要的画图工具。

Eclipse插件eUML2 。没有使用过,看截屏似乎还比较漂亮。

Eclispes插件 MDT-UML2。没有使用过,网页上没找到截屏,看EclipseCon 2008的一些Slide似乎还比较漂亮。

UML图和代码的正、逆向工程是很有用的特征,但敢于展示这项强大特征的工具似乎不多。如何维护UML模型到代码的可追踪性,是项目团队要认真考虑的一个问题。

2009年3月1日星期日

Amdahl's Law与伸缩性(scalability)

读到这篇博客:Hitting the Scalability Wall - Amdahl's Law

Amdahl's Law指出,如果您的系统中的任一部分要求串行化处理,而不能并行化,那么系统就会撞上伸缩性之墙,不能再提升性能,不论您再投入多少硬件。

关于Amdahl's Law的细节,请参考Wikipedia的条目

伸缩性是架构设计中考虑的一个重要方面。基本上,我们是在讨论如何提高系统的吞吐量。这让我想到《目标》一书中的约束理论(TOC),扩大系统吞吐量方法是找到瓶颈并消除。书中有一个例子,新购买的一台强大的加工机器取代了原来的两台旧机器,但不幸却成为了系统的瓶颈,因为大多数零件需要“串行地”经过这台机器的加工。解决办法?找回原来的两台旧机器,让工作能够“并行的”进行!

Prevayler在主页上声称比MySQL快3000倍,比Oracle快9000倍。但不管怎样,它也会撞上伸缩性之墙,因为它的事务是“串行”处理的。硬盘的访问也是串行的。这是否意味着我们无法设计出高伸缩性的系统?

不是的。我们可以通过硬盘阵列,数据库表分区(Sharding),让硬盘访问能够并行地进行。我们也可以用Prevayler实现LDAP的后端,利用LDAP协议本身的复制和分子树的能力,化解串行访问对伸缩性的影响,构造高伸缩性的系统。(做一个支持大量并发的身份证查询系统?)

开发方法学也有伸缩性问题。我们曾听说过,许多敏捷方法“don't scale very well”。不能支持大型团队,在短时期内交付大量的特征(客户价值)。究其原因,很大程度上是因为“隐式的知识”沟通是串行式进行的。

传统开发方法学也存在沟通问题。团队加入新成员后,短期会出现产能下降。因为新成员需要学习,老成员要抽出时间来教他们。

提高产能的方法就是把串行消除掉,让项目能够并行地开发。这一点恰恰是特征驱动开发(FDD)做得比较好的地方。前期经过尽可能短的串行处理(整体建模、特征列表、优先级)之后,后续的开发就可以并行展开了。所以搞FDD的人声称,可以实现可重复的成功,可以适应大型的开发项目。新加坡项目就是50个人15个月的银行项目。

FDD是一系列最佳实践的组合。并行开发的另一个关键在于组件化。使用同样的组件化架构风格,处理子系统、系统、和“众系统之系统”。让开发者熟悉了系统的一个部分,就很容易熟悉系统的另一个部分。这就是Fred Brooks所谓的“概念完整性”。将不同粒度的业务事件,开发成不同粒度的组件,用Peter Coad的话来说,实现了“模型的伸缩性”。

开发完了再测试(瀑布式)还是开发一点测试一点(迭代增量式)?Amdahl's Law告诉我们,要并发!得到详细的需求规格说明书后再开始设计和编码,还是像FDD那样把局部的详细需求放到迭代开发之中去?Amdahl's Law告诉我们,要并发!各模块开发好了之后再集成,还是持续集成?Amdahl's Law告诉我们,要并发!

由此我甚至进一步想到,FDD的前面三项串行工作也不是必须的。在实践中也遇到了这样的情形,特别是在创新的业务领域中。新加坡项目刚好是成熟的业务领域。我们可以让业务模型一点点长出来。清楚一部分,做一部分,但要在同一种架构风格(如彩色UML或5w and an H)指导下,确保整个系统的概念完整性。

和这些前辈高人神交,人生一大快事也!

我想讲的课

以下这些内容,是我这些年来的兴趣所在:

1. 软件需求过程
软件开发中最难的部分是确定需求。需求是一项社会工程。
博学多才的需求分析师再加上得到良好理解的需求过程,一定能找到正确的、创新的需求,实现产品在构建前的品质。

2. 软件测试与自动化
按传统软件工程理论,测试占到开发工作量的50%。而在软件投入使用后的维护和升级工作中,还有不少于一半的工作量要花在测试上。如何降低测试成本,是提高软件质量、解决软件危机、降低软件总体拥有成本的关键。

3. 彩色UML建模与特征驱动开发
哪一种建模方法让许多接触它的人觉得“一旦拥有,别无所求”?哪些大型项目会把UML建模作为项目成功的主要因素之一?彩色UML建模方法让我们了解了这样一种方法和这样一群人。特征驱动开发是敏捷方法学的一种,和其他多数敏捷方法学不同,它声称可以复制成功,而且可以很好地适应大型开发项目(如50人15个月的银行项目)。特征驱动开发与彩色UML建模相映生辉。

4. 持续集成
日构建是微软最值得称道的开发实践之一。持续集成让客户、管理层和项目成员了解真实的软件进度,避免交付期临近时让人崩溃的压力。持续集成是诸多软件开发最佳实践的集中体现。

5. SOA
个人、团体和大型企业都在向其客户提供服务,同时从供应商处消费服务。全球化让我们能够在更大的范围内选择质优价廉的服务。SOA首先是公司治理理念的体现,然后是业务与IT的密切配合。向SOA迁移是企业决策层首要考虑的问题之一,也是企业员工需要明白的趋势。

6. 敏捷开发方法学
敏捷开发方法学是业界顶尖思想家赠予我们的财富。它包含的内容彻底改变了业界对软件开发的认识。在经过多年的实践之后,这些方法学得到了很好的检验,足为我们所效法。

7. 过程改进与CMMI
如果你只想学一个日语单词,那我推荐“Kaizan”,它的意思是“持续改进”。反思和持续改进是取得成功的唯一途径。CMMI为我们提供了一个框架,指出了在提高软件能力的过程中,那些需要持续改进的领域。

8. UML建模
做软件就像开车,你不能设定好一个方向就一直往前冲。模型就像地图,没有它会有麻烦。建筑业、制造业都有丰富的建模经验,设计师基本上都是在和模型打交道。软件业还年轻,建模还不是那么受到重视和流行。一旦掌握了建模的三昧,定然有“向来枉费推移力,此日中流自在行”的感觉。

9. 软件配置管理
版本控制/配置管理是绝大多数开发项目都会执行的一项日常实践,而且它与需求管理、自动化测试和持续集成等实践关系密切。在这方面的一点改进,都会为软件开发带来可观的收益。

10. 软件复用
复用是实现令人满意的效率和品质的唯一途径。SOA的一个目标就是促进企业中的软件复用。要让复用成为企业文化的一部分,必然需要知其当然,不惧困难,而徐为之图。