日期:2009-06-14  浏览次数:20537 次

模式与XP
  

Joshua Kerievsky著,Gigix 译

  


概述
模式和极端编程(XP)都为软件设计、开发者提供了无法用金钱衡量的帮助。但是迄今为止XP大量关注于重构(refactoring),而对模式只字不提。在这篇文章中,我问“为什么”,并且最终描述出模式怎样以XP的方式更好地实现、以及XP怎样因为包含对模式的使用而变得更好。

致谢
非常感谢Kent Beck、Martin Fowler和Ward Cunningham,他们为这篇文章提出了友善的评论。

--------------------------------------------------------------------------------------------------------------------------------

仍在所知不多的时候我们就开始了自己的程序设计生涯,生产出的软件也反映出了我们的缺乏经验:我们创建的代码臃肿、错误百出、脆弱、难以维护、难以扩展。随着时间的流逝,我们成为了更好的软件设计者:我们从技术作家、专家那里学习,我们从自己的错误中学习。现在我们编写具有高度灵活性的软件,它适应广泛而且坚固。当被请求编写一个新的系统时,我们知道查明当前和将来的需求,这样我们可以设计软件来处理当前和将来的需要。

在软件开发生涯的这个阶段,极端编程告诉我们,我们经常对软件过分设计(over-engineer)了。我们从自己的错误中学到了太多,我们不希望重复这些错误,所以我们在系统生命周期的早期做了大量的努力来创造灵活而坚固的设计。不幸的是,我们没有认识到:如果这个系统永远不需要这个程度的灵活性和坚固性,那么我们所有的工作就都没有意义了。我们过分设计了。

我也曾经过分设计过。说实话,与其他设计者坐在一间房间里考虑如何设计软件来适应许多当前和将来的需求,这的确是一种乐趣。我们把自己学到的所有东西——尤其是那些最好的经验——应用在设计中。我们常常知道需求的列表会改变,但用户或客户总是改变需求。不过,我们认为我们可以足够聪明地设计软件,使软件足够灵活,使它能应付所有的需求变化。

典型的过分设计。

今天,极端编程将告诉你这是多么愚蠢的做法。XP说,我们必须让设计自己显现出来,而不是去预测设计将是什么样子。XP说,“做可能起作用的最简单的事”,因为“你将不再需要它”。另外,Kent Beck说:

你需要在一个强调沟通、简单、反馈和勇气的价值系统中选择最好的工作方法,这样你才能勇敢的脱离过分设计。[Beck1 00]

同意。但是,现在我必须提到我的朋友Norm Kerth。Norm在软件开发领域有丰富的经验和见识。一年以前我问他“对XP有什么想法”。他说:

              我喜欢XP里的每样东西。我关心的是:还有什么不在XP中。[Kerth 99]

当时,我只认为Norm是一个保守派。但现在我不能确定了。XP明显缺少的就是使用模式的经验。尽管一些XP的创始人帮助建设了模式社团,但没有哪一个坚定清楚的说明模式如何适应XP。

一开始,这还没有让我感到迷惑。但现在,我的确感到迷惑。

我感到迷惑,因为我在XP和模式上的经验让我相信:在XP的场景中模式会工作得更好;并且当XP包含模式时,XP也会工作得更好。

这需要一些解释。我将从描述我自己使用模式和XP的一些经验开始。

从1995年开始,我开始沉浸入模式之中。我学习模式文献、主办了一个每周一次的模式学习组、使用模式设计和开发软件、并进行UP(一个关于使用模式的国际学术会议)的组织和运转工作。说我“热衷于模式”实在是一种保守的说法。

当时,就象很多第一次学习模式的人一样,我有一点过分渴望使用它们。这不是一件好事,因为它会让你的设计比需要的更复杂。但我没有意识到这一点,直到我开始学习重构。

大概在1996年,我第一次接触到了重构。我开始实证它并很快观察到重构带我离开了我在模式学习中学到的某些原则。

举个例子,那本里程碑式的书——《设计模式:可复用面向对象软件的基础》——中的一个原则是:

针对接口编程,而不是针对实现编程。[GHJV1 95]

《设计模式》的作者们做了相当精彩的工作来解释为什么我们需要遵循这条建议。几乎在所有的模式中,都讨论了当你针对某个特定实现编程时你的软件如何变得缺少灵活性和可修改性。几乎每一次都是接口过来帮忙。

但如果我们不需要灵活性和可修改性,情况又是怎样?为什么我们要在开始设计时预料一些可能永远不会出现的需要?这是我的一次觉悟。所以随后我记录下了下面这个JAVA技巧:

不要分离类和接口

我曾经习惯于在我的接口名字后面加上一个“I”。但当我继续学习更多的重构技术时,我开始看到一种明智的做法:把类名和接口名设计成一样。下面是原因:在开发过程中,你知道你可以使用一个接口来让某些东西变得灵活(使实现多样化),但可能你现在根本不需要让实现多样化。所以,放下预测太多的“过分设计”吧,你仍然保持简单,仍然把东西放在一个类中。在某个地方你会写一个方法语句来使用这个类的对象。然后,几天、几星期、几个月之后,你明确“需要”一个接口。因此你就将原来的类转换成一个接口,再创建一个实现类(实现新的接口),并且让你原来的语句保持不变。[Kerievsky 96]

我继续学习类似于重构的课程,逐渐的,我使用模式的方式开始改变了。我不再预先考虑使用模式。现在,我更加明智了:如果某个模式可以解决某个设计问题,如果它提供一种方法来实现一个需求,我就会使用它,但我将从可以编码出的模式的最简单实现开始。晚些时候,当我需要增加或修改时,我将让这个实现更加灵活、稳固。

这种使用模式的新方法是一种更好的方法。它节约了我的时间,并让我的设计更简单。

由于我继续学到更多关于XP的知识,我很快开始考虑这样一个事实:那些清楚介绍“XP是什么”和“XP如何工作”的人毫不提及模式。看起来,焦点已经全部从开发转向了重构。构造一点,测试一点,重构一点,然后再重复。

那么,模式怎么了?

我收到的一般的答案是:模式鼓励过分设计,而重构保持事情简单、轻量级。

现在,我和其他任何人一样喜欢重构——我回顾了Martin Fowler的书的关于这个主题的两份手稿,然后知道重构将成为一个标准。但我仍然喜欢模式,我发现模式在“帮助人们学会如何设计更好的软件”方面是无价之宝。所以,XP怎么能不包括模式呢?!

我小心的在Portland Pattern Repository上写下了我的不安。我问:是否完美的XP模式应该由完全不知道模式的程序员和指导者组成,是否他们应该完全依赖重构来“让代码去它该去的地方”。Ron Jeffries,世界上最有经验的XP实践者,与我争论了这个主题,并且这样写:

一个初学者不能倾听代码所说的话。他需要学习代码质量的模式(在一般意义上)。他需要看好的代码(以及,我猜,差的代码),这样他才能学会写出好的代码。

一个问题——我的意思是一个可能的问题——是,现在的模式是否被用于帮助提高代码的质量。我想Beck的Smalltalk Best Practice Patterns会有帮助,因为那些都是非常小型的模式。我想设计模式都更值得怀疑,因为模式和讨论有时变得相当大,而且它们可能造成看起来合理的庞大解决方案。Martin Fowler的精彩的分析模式也有同样的危险:在可以选择一个小规模解决方案的时候选择了大规模的解决方案。[Jeffries 99]

一个非常有趣的关于模式的观点。尽管我已经看到模式可以被明智的实现、使用,但Ron看起来却认为它们是危险的,因为它们“让庞大的解决方案看起来合理”。在其他地方,Ron观察了一件经常发生的事情:第一次学习模式的人们如何过分渴望使用它们。

我无法不同意后面这个观察结果。就象任何新事物——甚至是XP——一样,人们可能会过分渴望使用它们。但模式真的鼓励在可以使用小规模解决方案时使用大规模解决方案吗?

我想这主要取决于你如何定义、使用模式。举个例子,我观察了许多模式的初级使用者,他们认