技术开发 频道

成功实践敏捷开发的26条“军规”

【IT168 专稿】    如何才能成功实践敏捷开发是一个课题。最近Keith Swenson一直在考虑这个问题,并最终总结出26条重要原则,以指导敏捷软件开发团队更好地工作。

    原则1:第1个用例完全处理好后再开始处理第2个用例。打个比方说,好比“先上这道菜,再开始做下一道菜”。软件开发方面的最大问题是同时开始处理一堆任务,因为免不了会出现部分工作后来被丢弃的结果,而这意味着浪费工作。先处理好某个用例,确保它完全可以使用,进行测试,编写说明文档,签入所有代码,作为一件完成的工作,之后开始处理下一个用例。

    原则2:千万不要破坏编译版本。这一条原则显而易见,但必须包括在任何软件开发忠告清单当中。如果程序员在签入代码之前采取了所有相应的防范措施进行测试,就永远不会破坏编译版本(build)。如果编译版本被破坏,十有八九是因为有人在抄捷径。

    原则3:除非用例确实需要,否则不要实现例行程序。实现某个特定的类时,你应该想好了某个特定的用例,而且应该只实现该用例需要的那些方法。你可能会考虑该类可能具有的其他功能,不妨把这写入到注释中,但应该等到用例实际需要时,再去实现。

    原则4:除非用例确实需要,否则不要添加数据成员。与上面这条原则如出一辙,只不过涉及的是类的数据成员。“客户”记录似乎显然需要“送货地址”,但直到有一个用例明确需要送货地址,才应该实现它。

    原则5:不要害怕做决定;也不要害怕改变之前所做的决定。敏捷开发的本质就是遇到不确定状况后,迅速响应。在开发的早期阶段,你没有完整信息。应当尽可能推迟决定,但到时候终究需要做决定,才能开展进一步工作。你可以推迟决定,直到拥有了相应的信息。应当根据现有信息,做出最合理的决定。以后等有了新的信息,不要害怕改变之前所做的那个决定。(有些老派的人称之为朝令夕改,但我称之为是应对不断变化的环境。)

    原则6:不断学习如何改善质量。这项工作永远不会结束,所以你应该不断留意哪些方面可以改善,并收集如何确认及处理质量问题的实际方法。

    原则7:重视度量。敏捷开发是为了帮助处理将来不确定的问题,但过去毫无不确定性可言。应该不断进行测试。应该度量并记录每次测试所得到的性能。

    原则8:奉行以人为本、而不是以系统为本的设计理念。开发人员常常会走入为技术而设计的误区。我们绝不能忘了软件的最终目的,即软件是用来帮助人完成工作的。

    原则9:测试是产品的一部分。许多开发人员和经理认为产品就是交付给客户的东西,其他一概都不那么重要。其实,应该把测试看作是产品的一个实际部分,值得在设计阶段予以全面考虑;甚至在许多情况下,要与产品一同交付给客户。(这后一种做法颇有争议,但是内建自测作为交付软件的一部分占用的空间微不足道,却在必要时提供了显著效益。所以,这种方法值得考虑。)

    原则10:先编写测试用例,后编写代码。测试本身可以用来让设计体系清楚到底需要什么样的代码。在执行测试用例时,往往可以发现设计方法存在的缺陷。想一想在编写代码之前执行测试用例可以省下多少时间。但要注意:先编写第1个测试用例,并编写代码,然后开始处理第2个用例。

    原则11:消除浪费。坦率地说,这是另一条老生常谈的普遍原则;因为它实在太重要了,所以任何开发原则清单中都少不了它。一旦发现浪费,就要消除,这项工作要坚持不懈。消除无法为客户增添价值的任何代码。如果你发现代码无法为客户带来价值,那么可能不需要该代码。

    原则12:营造发现编译版本被破坏、立即采取对策的文化氛围。要明白当编译版本被破坏时,它会影响参与项目的每个人;因此,没有什么比确保核心代码进行合理编译及测试更重要的了。我见过有些团队任由不完整的测试持续数个月,因为他们觉得那是别人的工作,不关自己的事。每个人都受到了不利影响,却没有人采取行动。而是需要达到一种共识:自己多做一点工作,就有望为整个团队带来很大的回报。

    原则13:团队的每个成员都要了解客户需求。大型的复杂项目必须进行划分,交给不同团队;这些任务需要进一步细分,分派给开发人员。但是在这么做的同时,要确保开发人员了解使用最终产品的实际用户的需求和目标。

    原则14:把相关的定义放在一起。设计代码结构时,确保高度相关的部分放在一起,有可能放在同一个类中。这是面向对象设计方法在封装方面的一条标准原则。理想情况下,某个类之外的所有代码不需要知道内部运行的细节。有些开发人员喜欢将细节分散在多个文件中,以便按不同方式加以组织:比如为了把所有相同的数据类型放在一起,或者按字母顺序进行组织。比方说,把一个类中所有常量放在与使用它们的包不同的另一个包当中,就会增加不必要的程序复杂性。指导原则应该是按相关性进行分组,那样可以隐藏复杂性。

    原则15:始终在签入代码之前运行测试。这条准则会帮助你满足“千万不要破坏编译版本”的准则。

    原则16:仓促优化是万恶之源。程序教父Don Knuth的这句名言今天依然适用。应当精心编写代码,避免微观层面出现不必要的浪费,但应该等到基于实际的最终用户用例对整个程序进行压力测试,再进行单个方法层面之外的优化。要是仅仅基于对代码的静态了解,就凭直觉判断什么对整体性能来说很重要,几乎肯定出错。相反,要度量整个系统的行为,找出真正影响性能的那1%的代码,并关注这部分代码。

    原则17:尽量减少积压下来的没有完成的编码任务。开发人员开始编写某个用例时,所有已被修改、但没有完成及测试的代码会发生成本。没有完成的变更积压几天或几周,会大大增加因改写而导致浪费的风险。设想一下有三个任务,每个任务估计需要一天。同时开始这三个任务,同时工作三天就需要累计9个“单位”的成本。但如果按顺序处理每个任务,一个任务完成后开始下一个,那么只需要3个“单位”的成本。这并不直观。直觉告诉我们:我们在处理任务时,最好还是同时做三件事。但软件不像实体构造。短小、快速、完整的任务不但可以减轻认知负荷,还能减小未完成工作与另一个人的未完成工作发生冲突的可能性。

    原则18:千万不要过于强调代码的通用性。这就是有名的YAGNI,即“你不会需要它”。程序员在编写某个特定类时,喜欢认为:只要稍加改动,该类可用于另外几个用途。如果当前用例需要这些用途,那很好;但是程序员通常会考虑还没有发明出来的用途,或者是实际上根本不需要的用途。(这个话题老是让我想到宣传某款产品既是地板蜡、又是甜食配料的搞笑电视节目。)

    原则19:能用两行代码,就坚决不要用三行。每当别人要读代码时,简单的代码总是一目了然。但也不要把代码简化到人家很难读懂的地步。与冗长代码相比,简洁代码更容易维护,也更容易发现其中的错误。始终要尽量简化,但避免简化过头。

    原则20:千万不要用行数来度量代码。就完成特定任务所需的代码行数而言,不同的程序员和编程风格会造成很大的差异。代码行数说明不了代码有多全面、质量有多好。代码质量有可能千差万别;与代码质量相比,代码行数显得没有太大的意义。而是应统计切实可行的用例有多少。

    原则21:持续不断地重新设计和重构。运用这条原则要慎重,因为有些代码很脆弱、很难改变,但一般而言,你用不着害怕更改代码以符合实际用例。某个数据成员过去可能是整数,但是当用例要求它是浮点数时,不要害怕更改。

    原则22:删除无用代码。说到并不完全了解的大段代码,人们往往采取“别惹事生非”的做法。一个例子就是,为某个类增加一种新方法以替换另一种旧方法,而开发人员往往让旧方法留在那里,仅仅为了“以防万一”。应当花一番工夫,看看需不需要该方法;如果没有证据表明需要它,就删除。最糟糕的做法莫过于注释掉了大段代码,却任由这些注释代码留在原处。一旦你知道测试完毕,就应当删除注释代码,当然要在签入之前。随时添加代码很容易,随时删除代码却很难。因此,如果你清楚不需要某部分代码,那么只需下一点力气,核实并消除此代码就能让代码库维护起来更容易。

    原则23:不要发明新语言。程序员喜欢让驱动功能的文本文件在运行时可以灵活配置。有好多配置文件在不重新编译的情况下能够改变程序的行为。XML的出现让一批专门定制的“脚本语言”层出不穷:有了这些语言,最终用户不必编译,就能够“编程”以实现功能。这种推论的缺陷在于,要是离开了具体实现的环境,就几乎根本无法明确规定操作行为的精确定义;而这些类型的脚本语言主要只适用于那些对相应代码的内部运行有深入了解的人。因此,并不详细了解内部运行的实际最终用户永远不可能知道如何才能预料到复杂的命令组合会带来什么影响。脚本语言是有用,也不能被抹杀,但是设计者必须采取一种极其保守的态度,尽可能使用现有语言,避免发明新的语言。

    原则24:等准备好了实现并测试实现代码,再进行设计。你应该总体上对工作方向有一些了解,并大致了解争取建立的系统架构。但在进入到可以实现及测试该设计的开发迭代阶段之前,不要做详细设计,也不要编写功能实现的详细描述。详细设计应当只涉及处理当前用例所需的那部分。软件开发中造成浪费的最主要根源在于,把时间花在设计不需要、或者因为设计方面某些错误的假定而需要重新设计的部分上。

    原则25:设计是可塑的。不像实体构造,软件可以轻而易举地进行重大改变。事实上,有许多证据可以证明:软件比描述软件的设计规格更容易改变。此外,软件比规格更有效地传达了设计思想。因此,你应当把时间花在直接实现设计上,以便客户能看到设计的具体细节。如果你缺少某些功能、因而要改变设计,改变软件会比改变规格来得容易。但最重要的是,客户看到代码运行后,你就能非常清楚地知道客户想要什么。

    原则26:花些时间编写代码来完整描述发现和报告异常情况的代码中的问题。程序员往往很懒惰,对抛出的异常情况只给出简单肤浅的描述,说明哪里出了错。以为只有他们自己才会看到这个问题;只要借助含糊笼统的描述,就会记得该问题的意思。但实际上,因错误报告不准确或不完整而浪费在客户支持情景上的时间比其他任何原因都要多。要编写每一个错误消息,就好像你向刚走入房间、对代码毫无经验的某个人说明情况。毕竟,客户以及客户支持团队对代码是毫无经验的。

0
相关文章