您的位置:首页 > 其它

《敏捷软件开发(原则、模式与实践)》第四章到第八章笔记

2008-02-26 22:15 706 查看
第4章 测试

烈火验真金,逆境磨意志。
——卢修斯.塞尼加(公元前4-公元65)

1 测试驱动的开发方法
测试驱动的方法对于我们正在编写的软件的设计有积极的影响:
(1) 程序中的每一项功能都有测试来验证它的操作的正确性。
(2) 首先编写测试可以迫使我们使用不同的观察点,可以设计出便于调用的软件
(3) 通过首先编写测试,可以迫使自己把程序设计为可测试的,迫使我们解除软件中的耦合(force us to decouple the software)
(4) 测试可以作为一种无价的文档形式
我们相信,只要按照测试所暗示的结构去编写程序,就能通过测试,这种方法成为有意图的编程(intentional programming)。
测试促使模块之间隔离和解耦合

2 验收测试
对于验证工具来说,单元测试是必要的,但是不够充分。单元测试用来验证系统的小的组成单元应该按照所期望的工作方式,但是它们没有验证系统作为一个整体时工作的正确性。单元测试是用来验证系统中个别机制的白盒测试(white-box tests)。验收测试是用来验证系统满足客户需要的黑盒测试(black-box tests)。
验收测试由不了解系统内部机制的人编写。客户可以直接或者和一些技术人员(比如QA等)一起来编写验收测试。验收测试是程序,因此是可以运行的。然而,通常使用专为应用程序的客户创建的脚本语言来编写验收测试。 在这里不能由系统代码编写人员来编写验收测试!
验收测试是关于一项特性(feature)的最终文档。 单元测试作为可编译、运行的有关系统内部结构的文档,而验收测试是有关系统特性的可编译、执行的文档。
此外,首先编写验收测试的行为对于系统的架构方***有深远的影响。为了使系统具有可测试行,就必须要在很高的系统架构层面对系统进行解耦合。
验收测试可以促使你在大的方面做出优良的系统架构决策。
创建一个验收测试框架(framework)看起来是件困难的任务。然而,如果仅仅创建框架中对单个迭代包含的特性进行验收测试所需要的那部分,就会发现并不困难。你还会发现所花费的努力是值得的。 在这里可以看到,每次迭代都需要进行验收测试,而且这样的工作量也不会太大。
我们还没有编写任何代码,也没有进行任何设计。这是开始考虑验收测试的的最好时机,揭示意图编程再一次成为有用的工具。我们应该以我们认为验收测试应该的样子去编写它们,然后可以构建脚本语言,并根据脚本语言的结构来构造所将要开发的系统。 (这一点是非常值得我们在项目开发过程中借鉴的,当没有开始对系统进行设计和代码编写的时候就优先对系统进行验收测试的考虑和用脚本语言来构造验收测试,这样就可以迫使我们去让我们即将设计和开发的系统按照我们所构想的验证测试来实现代码的编写,对于设计和架构都是非常有帮助的!)
为使系统验证便于编写并易于改变。把它们放置在一个配置管理工具中,并且把它们保存起来以便于随时可以运行它们。因此,采用简单的文本文件来编写验收测试应该比较合理。

3 结论
单元测试和验收测试都是一种文档形式,那样的文档是可以编译和执行的;因此,它是准确和可靠的。此外,编写测试所使用的语言是明确的,并且它们的观看者使这些语言非常易读。程序员能够阅读单元测试,因此单元测试是使用程序员编程的语言编写的。客户能够阅读验收测试,因为验收测试是使用客户自己设计的语言编写的。
也许,测试最重要的好处就是它对架构和设计的影响(也的确如此)。为了使一个模块或者应用程序具有可测试性,就必须要对它进行解耦合。越是具有可测试性,耦合关系就越弱。全面地考虑验收测试和单元测试的行为对软件的结构具有深远的正面影响。

第5章 重构

大千世界中,惟一缺乏的就是人类的注意力。
——凯文.凯利(“新经济”的首席预言家之一),连线杂志

在Martin Fowler的名著《重构》一书中,他把重构(Refactoring)定以为:“……在不改变代码外在行为的前提下对代码做出修改,以改进代码的内部结构的过程。”
每个软件模块都有三项职责。第一个职责是它运行起来所完成的功能。这也是该模块得以完成的原因。第二个职责是它要应对变化。几乎所有的模块在它们的生命周其中都要变化。开发者有责任保证这种改变应该尽可能地简单。第三个职责是要和阅读它的人进行沟通。对该模块不熟悉的开发人员应该能够比较容易地阅读并理解它。

1 素数产生程序:一个简单的重构示例
例子略

2 结论
重构后的程序读起来比一开始要好得多,程序工作得也更好一些。程序可以变得更容易被理解,且程序结构的各部分之间互相隔离,这也使它更容易更改。
重构的目的,是为了每天清洁你的代码。我们想通过最小的努力就能够对我们的系统进行扩展和修改,要想具有这种能力,最重要的就是要保持代码的清洁。

第6章 一次编程实践

设计和编程都是人的活动,忘记了这一点,将会失去一切。
——Bjarne Stroustrup, 1991

在本章中作者给出了一次编程实践,一个保龄球的程序,用一个实例给出了结队编程的详细情景,比较经典!


第二部分 敏捷设计

在敏捷团队中,全局视图和软件一起演化。在每次迭代中,团队改进系统设计,使设计尽可能适合于当前系统。团队不会花费许多实践去预测未来的需求和需要,也不会试图在今天就构建一些基础结构去制成那些他们认为明天才会需要的特性。他们更愿意关注当前的系统结构,并使它尽可能地好。

拙劣的设计症状定义:
僵化性(Rigidity):设计难于改变
脆弱性(Fragility):设计易于遭到破坏
牢固性(Immobility):设计难于重用
粘滞性(Viscosity):难以做正确的事情
不必要的复杂性(Needless Complexity):过分设计
不必要的重复(Neddless Repetition):滥用鼠标
晦涩性(Opacity):混乱的表达

一些面向对象设计原则:
单一职责原则(The Single Responsibility Principle,简称SRP)
开放-封闭原则(The Open-Close Principle,简称OCP)
Liskov替换原则(The Liskov Substitution Principle,简称LSP)
依赖倒置原则(The Dependency Inversion Principle,简称DIP)
接口隔离原则(The Interface Segregation Interface,简称ISP)

敏捷团队应用这些原则来除去臭味。当没有臭味时,他们不会应用这些原则。仅仅因为是一个原则就无条件的去遵守它的做法是错误的。这些于原则不是可以随意在系统中到处喷洒的香水。过分遵循这些原则会导致不必要的复杂性(Needless Complexity)的设计臭味。

第7章 什么是敏捷设计

“在按照我的理解方式审查了软件开发的生命周期后,我得出一个结论:实际上满足工程设计标准的惟一软件文档,就是源代码清单。”
——Jack Reeves

1 设计的臭味——腐化软件的气味
(1)僵化性 僵化性是指难以对软件进行改动,即使简单的改动。如果单一的改动会导致有依赖关系的模块中俄连锁改动,那么设计就是僵化的。必须要改动的模块越多,设计就越僵化。
(2)脆弱性 脆弱性是指,在进行一个改动时,程序的许多地方就可能出现问题。常常是,出现新问题的地方与改动的地方并没有概念上的关联。要修正这些问题就会引出更多的问题,从而使开发团队就像一只不停追逐自己尾巴的狗。 呵呵,这个形容真的很贴切
(3)牢固性 牢固性是指,设计中包含了对其他系统有用的部分,但是要把这些部分从系统中分离出来所需要的努力和风险是巨大的。这是一件令人遗憾的事,但是确实非常常见的事情。
(4)粘滞性 粘滞性有两种表现形式:软件的粘滞性和环境的粘滞性。
当那些可以保持系统设计的方法比那些生硬手法更难应用的时候,就表明设计具有高的粘滞性。
当开发环境迟钝、低效时,就会产生环境的粘滞性。
无论项目具有哪种粘滞性,都很难保持项目中的软件设计。我们希望创建易于保持设计的系统和项目环境。
(5)不必要的复杂性 如果设计中包含有当前没有用的组成部分,它就包含不必要的复杂性。
(6)不必要的重复 剪切和粘贴也许是有用的文本编辑操作,但是它们却是灾难性的代码编辑操作。
当同样的代码以稍微不同的形式一再出现时谬表示开发人员忽视了抽象。对于它们来说,发现所有的重复并通过适当的抽象去消除它们的做法可能没有高的优先级别,但是这样做非常有助于使系统更加易于理解和维护。
(7)晦涩性 晦涩性是指模块难以理解。
为防止这种情况的发生,开发人员必须要站在代码阅读者的位置,共同努力对它们的代码进行重构,这样代码的阅读者就可以理解代码。可以被其他人进行评审。

大作数软件项目中最不稳定的东西就是需求。需求处在一个持续变动的状态之中。这是我们作为开发人员必须得接受的事实!我们生存在一个需求不断变化的世界中,我们的工作是要保证我们的软件能够经受得住那些变化。如果我们软件的设计由于需求变化而退化,那么我们就不是敏捷的。
敏捷团队不是在一开始设计该模块时就试图预测程序将如何变化。相反,他们是以最简单的方法编写的。直到需求最终确实变化时,他们才修改模块的设计,使之对该种变化保持弹性。
简单而言,敏捷开发人员知道要做什么,是因为:
(1)他们遵循敏捷实践去开发问题;
(2)他们应用设计原则去诊断问题;
(3)他们应用适当的设计模式去解决问题。
软件开发的这三个方面间的互相作用就是设计。

敏捷开发人员致力于保持设计尽可能地适当、干净。设计必须要保持干净、简单,并且由于源代码是设计最重要的表示,所以它同样要保持干净。职业特性要求我们,作为软件开发人员,不能忍受代码腐化。

2 结论
敏捷设计是一个过程,不是一个事件。它是一个持续的应用原则、模式以及实践来改进软件的结构和可读性的过程。它致力于保持系统设计在任何实践都尽可能得简单、干净以富有表现力。

第8章 单一职责原则(SRP)

只有佛自己应当担负起公布玄妙秘密的职责。
——E.Cobham Brewer, 1810-1897
《英语典故字典》,1898

这条原则曾经在Tom DeMaro和Meilir Page-Jones的著作中描述过,并称之为内聚性(cohesion)。他们把内聚性定义为:一个模块的组成元素之间的功能相关性。

1 单一职责原则
就一个类而言,应该仅有一个引起它变化的原因。
每一个职责都是变化的一个轴线(an axis of change)。当需求变化时,该变化会反映为类的职责的变化,如果一个类承担了多余一个的职责,那么引起它变化的原因就会有多个。 如果一个类承担的职责过多,就等于把这些职责耦合在了一起。一个值得的变化可能会削弱或者一直这个类完成其他职责的能力。这种耦合会导致脆弱的(fragile)设计,当变化发生时,设计会遭受到意想不到的破坏。
在SRP中,我们把职责定义为“变化的原因”(a reason for change)。如果你能够想到多余一个的动机去改变一个类,那么就具有多于一个的职责。

2 结论
SRP是所有原则中最简单的之一,也是最难正确运用的之一。我们会自然地把职责结合在一起。软件设计真正要做的许多内容,就是发现职责并把那些职责互相分离。事实上,我们将要论述的其余原则都会以这样或那样的方式回到这个问题上。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: