敏捷开发(纪念版)
上QQ阅读APP看书,第一时间看更新

前言

“可是老兄,你说你去年就会完成这本书的。”距离1999年Claudia发出这一正当的抱怨,已经过去7年了,但我(Bob)(1)觉得已经做出了补偿。我要经营一家咨询公司,做大量编码、培训、辅导和演讲工作,写文章、专栏和博客,更不用提还要养家糊口并享受大家庭的乐趣。所以,这期间写三本书(每两年一本)真的是一个巨大的挑战。但是,我乐在其中。

敏捷开发是在需求快速变化的情况下快速开发软件的一种能力。为实现这种敏捷性,需使用能提供必要纪律和反馈的实践,需遵守保持软件灵活且易于维护的设计原则,需知道已证明能为特定问题权衡那些原则的设计模式。本书旨在将这三个概念整合成一个有机的整体。

本书介绍了这些原则、模式与实践,然后通过多个案例来演示其实际运用。更重要的是,这些案例都不是“成品”。相反,它们是进行中的设计。你会看到设计人员犯错,观察到他们如何发现并最终纠正错误,会看到设计人员对一个难题苦思不得其解,并担心歧义和得失。总之,你看到的是设计实际在进行。

2005年初,我(Micah)在一个小开发团队做事,当时要着手用C#来写一个.NET应用程序。项目要求采用敏捷开发实践,这正是我进入该项目的原因之一。虽然以前用过C#,但我最熟悉的还是Java和C++。

当时没想过用.NET会有多大区别,事实证明确实如此。项目进行了两个月,我们发布了第一个版本。不是完整版本,只包含所有预期功能的一部分,但足够用。他们也真的在用。仅过了两个月,公司就从我们的开发收获了好处。管理层高兴,嚷着要雇更多人,启动更多项目。

多年来一直出没于敏捷社区,我知道有许多敏捷开发人员能帮到我们。我给他们打了电话,请他们加入。最终,没有任何一个搞敏捷的人加入我们的团队。为什么?或许最重要的原因是我们用的是.NET。

几乎所有敏捷开发人员都有Java,C++或Smalltalk的背景。但几乎没听说过有敏捷.NET程序员。我说要用.NET进行敏捷软件开发,我的那些朋友可能根本没有把我的话当真,或者他们就是不想和.NET扯上关系。这是一个大问题。而且,发生过好多次。

为期一周的有关各种软件主题的课程使我能结识来自世界各地的开发人员。

就各种软件主题讲授大约一周的课程,使我有机会接触来自世界各地有代表性的开发人员。许多学员都是.NET程序员,也有许多是Java或C++程序员。虽然不好听,但根据我的经验,.NET程序员通常比Java和C ++程序员要弱一些。显然,并非总是如此。但通过在课堂上反复观察,我只能得出这样的结论:.NET程序员在敏捷软件实践、设计模式和设计原则等方面通常要弱一些。据我观察,许多.NET程序员从未听说过这些基本概念。这种情况必须改变!

我父亲Robert C. Martin于2002年出版了的《敏捷软件开发:原则、模式与实现》荣获了2003年Jolt大奖。那是本好书,受到许多开发人员的推崇。遗憾的是,它对.NET社区影响甚微。虽然书的内容同样适合.NET,但鲜有.NET程序员读过。

我希望讲.NET的这一版能在.NET和开发社区其余部分之间建立起一座桥梁。希望程序员能读一读,了解构建软件的更优方式。希望他们开始使用更好的软件实践,创建更好的设计,提升.NET应用程序员的质量标准。希望.NET程序员不再比其他程序员弱。希望.NET程序员在软件社区取得更多话语权,就连Java开发人员也乐意加入一个.NET团队。

写书的过程中,我经常纠结于要不要把我的名字放在一本.NET书的封面。这样会不会将我和.NET联系起来,会不会有不好的暗示?但最终我不再纠结。我是一名.NET程序员。不对!一名敏捷.NET程序员!我为此感到骄傲。

关于本书

20世纪90年代初,我(Bob)写了Designing Object-Oriented C++ Applications Using the Booch Method一书,是我的代表作,我对其影响和销量都很满意。其实你现在正在看的最开始就是想作为那本书的第3版,只是后来完全不是那么回事。原作内容在本书所剩无己,不超过3章,而且都进行了大幅修订。书的意图、精神和许多启发并没有改变。在该书问世后的十年里,我在软件设计和开发方面学到了很多。本书反映了我学到的东西。

这是怎样的十年啊!该书是在互联网时代之前出版的。互联网问世后,需要掌握的缩写词数量大增。我们现在有了EJB、RMI、J2EE、XML、XSLT、HTML、ASP、JSP、ZOPE、SOAP、C#和.NET,另外还有设计模式、Java、Servelets和Application Servers。基本上,要使本书所有章节的内容保持“最新”是很难的。

本书和Booch的关系

1997年,Grady Booch(2)邀请我帮忙写他那本大获成功的Object-Oriented Analysis and Design with Applications一书的第3版。我以前和Grady在一些项目上合作过,是其许多作品(包括UML)的热心读者和内容贡献者。所以,我高兴地接受了邀请,并请我的好友Jim Newkirk共同参与。

接下来的两年,我和Jim为Booch写了许多章节,花在本书上的精力自然就少了。但是,我觉得Booch的书值得投入。另外,当时还在想本书反正只是第2版,所以并不是特别上心。如果我要写一些有份量的内容,我会写一些新的、不一样的。

遗憾的是,Booch的书难产了。本来就很难在正常时间写书,在互联网泡沫的那段时间更是不太可能。Grady在Rational Software的工作更忙了,同时还忙于像Catapulse这样的风投企业。所以,项目陷入停顿。最终,我问Grady和Addison-Wesley出版社能不能把我和Jim写的章节放到本书。他们慷慨地同意了。本书的几个案例分析和UML章节就是这么来的。

极限编程的影响

1998年末,极限编程(XP)崭露头角,挑战我们对于软件开发的传统观念。是应该在写任何代码之前创建大量UML图,还是避免一切形式的图,直接写大量代码?是应该写许多说明性的文档来描述设计,还是使代码更具说明性,从而无需辅助文档?要结对写程序吗?写生产代码前要先写好测试代码吗?我们到底应该怎么做?

这个变革来得恰是时候。20世纪90年代中期,Object Mentor帮助许多公司解决OO(面向对象)设计和项目管理问题。我们帮这些公司完成其项目。在这个过程中,我们向团队灌输了自己的态度与实践。遗憾的是,这些东西没有形成书面记录。相反,只是从口头上传达给了客户。

1998年,我意识到需要把我们的过程和实践记录下来,以便更好地向客户传达。所以我在C++ Report上写了许多关于这一过程的文章(3)。但是,这些文章没有达到目标。信息量大,有时还十分有趣,但它们没有将我们在项目中采用的实践和态度整理成文,面是对数十年来我形成的价值观的一种无意识的折衷。最后是Kent Beck提醒了我。

本书和Kent的关系

1998年末,正当我为Object Mentor过程的整理而烦恼时,Kent和Beck在极限编程(XP)方面的成果让我眼前一亮。这些成果散见于Ward Cunningham(4)的wiki(5),和其他许多人的作品混在一起。尽管如此,作为一个有心人,我还是掌握了Kent的要点。感兴趣的同时,我也有了一些疑虑。极限编程的某些东西契合我的开发过程目标。但另一些东西,比如缺乏一个明确的设计阶段,却让我疑惑。

我和Kent处于截然不同的软件环境。他是公认的Smalltalk顾问,我是公认的C++顾问。这两个世界相互很难沟通,存在像库恩范式(6)那么大的鸿沟。

其他时候我绝不会邀请Kent为C++ Report撰稿。但是,由于我们对于过程的看法取得了一致,所以语言的鸿沟不再重要。1999年2月,我在慕尼黑的OOP大会上见到了Kent。我当时在讲OOD的原则,他就在对面的房间里讲XP。由于没法听到他的演讲,我在午餐时找到了Kent。我们讨论了XP,我提出了让他为C++ Report撰稿的请求。这是一篇很棒的文章,讨论了Kent如何和一名同事花一小时左右的时间在某个live system中进行一次全面的设计更改。

接着几个月,我慢慢梳理出了自己对XP的忧虑。最担心的是如何采纳一个没有明显前期设计阶段的过程。感觉自己好像卡在了这里。对于我的客户及其整个行业,我难道不应该告诉他们值得花时间在设计上吗?

最后,我终于意识到自己都没有真正注重过这样的一个阶段。即使在我写的关于设计、Booch图和UML图的所有文章和书里,都总是将代码作为验证图是否有意义的一种方式来使用。在我的所有客户咨询中,我会花一两个小时帮客户画图,再指导他们通过代码来利用这些图。我意识到虽然XP关于设计的说法有点陌生,有点库恩(7),但其背后的实践我本来就熟悉。

我对XP的其他担心较容易解决。我私底下一直拥护结对编程。XP使我能光明正大地和伙伴一起编程。重构、持续集成、在客户现场工作……所有这些对我来说都很容易接受。它们很接近我向客户建议的工作方式。

XP的一个实践对我来说是新的发现。第一次听说“测试驱动开发”(Test-driven development,TDD)(8)时可能感觉没什么:写生产代码前先写好测试用例,写所有生产代码的目的都是使失败的测试用例通过测试。但是,我对这种开发模式所带来的深远影响始料未及。该实践彻底改变了我写软件的方式:变得更好了。

所以,1999年秋,我确信Object Mentor应采纳XP作为其选择的过程,并且我应该放弃写自己的过程的想法。Kent已经很好地归纳了XP的实践与过程,我的小小尝试与之相比不值一提。

.NET

各大企业正在进行一场战争,目的是争取你的效忠。它们认为,只要拥有了语言,就拥有了程序员以及雇用这些程序员的公司。

这场战争的第一个争夺点是Java。Java是第一个由大公司为赢得程序员关注而创建的语言,并取得了极大成功。Java在软件社区深得人心,基本上是现代多层IT应用程序的事实上的标准。

相应的一个还击来自IBM,它通过Eclipse开发环境夺走了很大一块Java市场。Microsoft技术精湛的开发人员也不甘落后,他们提供了常规意义上的.NET和最为特殊的C#。

令人惊讶的是,Java和C#很难区分。两种语言语义一致,语法也相似,以至于许多代码段没有差别。虽然Microsoft在技术创新上差点意思,但它赶超别人并取得最终胜利的能力还是相当不错的。

本书第一版采用Java和C++作为编码语言。本书则完全采用C#和.NET平台。不要把这当成是背书。这场战争我们不选边站。事实上,大公司为争夺程序员的关注而发起的战争没有太大意义。未来几年一旦出现更好的语言,程序员的心思立即就会发生转移。

本书之所以出.NET版,自然是为了方便.NET读者。虽然书中的原则、模式与实践和语言无关,但案例分析不是。.NET程序员看.NET的案例分析更舒服,Java程序员看Java的例子更愉快。

魔鬼就在细节里

本书包含大量.NET代码。希望你能仔细读代码,因为代码在很大程度上就是本书的重点。代码具现了本书要表达的意思。

本书采用固定写作模式:大小不一的一系列案例分析。有的非常小,有的则需要用几章来讲解。每个案例分析都有一些前置材料,描述了该案例分析要用到的面向对象设计原则和模式。

本书首先讨论开发实践和过程,其中穿插了许多小的案例分析和例子。然后开始讨论设计和设计原则,接着讨论一些设计模式,对包进行管控的更多设计原则,以及更多模式。所有这些主题都伴随有相应的案例分析。

所以,要做好读一些代码和研究一些UML图的准备。本书技术性很强,它要传授的经验教训如同恶魔一样隐藏在细节里(细节决定成败)。

本书的结构

本书包含4部分38章和2个附录。

第Ⅰ部分:敏捷开发。本部分描述敏捷开发的概念。首先展示敏捷联盟宣言,概述了极限编程(XP),然后通过许多小的案例分析来阐述一些单独的XP实践,尤其是对设计和代码编码方式有影响的那些。

第Ⅱ部分:敏捷设计。本部分讨论面向对象软件设计,包括它的定义,对复杂性进行管理的问题和技术,以及面向对象类设计的原则。本部分最后用几章描述了UML的一个实用子集。

第Ⅲ部分:案例学习:Payroll系统。本部分描述面向对象设计和一个简单的批处理Payroll系统的C++实现。前几章描述本案例分析遇到的设计模式。最后一章是完整的案例分析,是本书最大和最完整的一个。

第Ⅳ部分:案例学习:打包Payroll系统。本部分首先描述面向对象包设计的原则,然后通过增量打包上一部分的类来演示这些原则。最后几章描述了Payroll应用程序的数据库和UI设计。

附录A:两家公司的讽刺故事

附录B:Jack Reeves的“什么是软件”一文。

如何使用本书

如果你是开发人员,请将本书从头读到尾。本书主要为开发人员而写,包含以敏捷方式开发软件所需的资讯。先学习实践,然后是原则,然后是模式,然后是把所有这些结合起来的案例分析。整合所有这些知识将有助于你完成项目。

如果你是管理人员或业务分析师,请阅读第Ⅰ部分“敏捷开发”。第1章~第6章深入讨论了敏捷原则和实践,从需求到计划,再到测试、重构和编程。本部分将指导你建立团队和管理项目。

如果想学习UML,请先阅读第13章~第19章,然后阅读第Ⅲ部分“案例学习:薪水支付系统Payroll”的全部章节。这将帮助你在UML的语法和使用方面打下良好基础,同时帮助你在UML和C#之间转换。

如果想学习设计模式,请阅读第Ⅱ部分“敏捷设计”,从而先学习设计原则。然后阅读第Ⅲ部分“案例学习:薪水支付系统Payroll”和第Ⅳ部分“案例学习:打包Payroll系统”。它们定义了所有模式,并展示了它们在典型情况下的使用。

如果想学习面向对象设计原则,请阅读第Ⅱ部分“敏捷设计”和第Ⅲ部分“案例学习:薪水支付系统Payroll”和第Ⅳ部分“案例学习:打包Payroll系统”。它们描述了面向对象设计原则并展示了如何使用它们。

如果想学习敏捷开发方法,请阅读第Ⅰ部分“敏捷开发”。本部分描述了敏捷开发的需求、计划、测试、重构和编程。

如果想找乐子,请阅读附录A“两家公司的讽刺故事”。


(1)前言为两名作者共同写成,因而在“我”的后面指出了具体的作者名称,以示区分。

(2)译注:Grady Booch是统一建模语言(UML)的缔造者之一。

(3)有4篇文章。前三篇是“Iterative and Incremental Development”(I, II, III)。最后一篇是“C.O.D.E Culled Object Development process”。

(4)译注:沃德·坎宁安,Wiki概念的发明者,设计模式和敏捷软件方法的先驱之一。

(5)http://c2.com/cgi/wiki包含涉及广泛主题的大量文章。有数百上千的作者。有人说,也就Ward Cunningham才能用几行Perl代码发起一次社会革命。

(6)1995年到2001年任何可靠的学术著作采用的都肯定是“库恩”(Kuhnian)一词。它是指托马斯·库恩(Thomas S. Kuhn)所著的《科学革命的结构》一书(芝加哥大学出版社1962年出版)。库恩认为科学不是通过新知识的线性积累进步,而是经历周期性的革命,称“范式转移”。

(7)如果在文章中两次提到库恩的话,论文的可信度更高。

(8)Kent Beck著,中文版《实战测试驱动开发》。