《敏捷软件开发》读书笔记

《敏捷软件开发:原则、模式与实践》读书笔记

面向对象设计的原则:

SRP:单一职责原则
OCP:开放-封闭原则
LSP:Liskov替换原则
DIP:依赖倒置原则
ISP:接口隔离原则
REP:重用发布等价原则
CCP:共同封闭原则
CRP:共同重用原则
ADP:无环依赖原则
SDP:稳定依赖原则
SAP:稳定抽象原则

第 Ⅰ 部分 敏捷开发

人与人之间的交互是复杂的,并且其效果从来都难以预期,但却是工作中最为重要的方面。

——Tom Demacro 和 Timothy Lister。《人件》,第5页

原则、模式和实践都是重要的,但是使它们发挥作用的是人。

第1章 敏捷实战

敏捷联盟宣言:

1. 个体和交互胜过过程和工具
2. 可以工作的软件胜过面面俱到的文档
3. 客户合作胜过合同谈判
4. 响应变化胜过遵循计划

原则:

1. 我们最优先要做的是通过尽早的、持续的交付有价值的软件来使客户满意。
2. 即使到了开发的后期,也欢迎改变需求。敏捷过程利用变化来为客户创造竞争优势。
3. 经常性地交付可以工作的软件,交付的间隔可以从几周到几个月,交付的时间间隔越短越好。
4. 在整个项目开发期间,业务人员和开发人员必须天天都在一个工作。
5. 围绕被激励起来的个人来构建项目。给他们提供所需要的环境和支持,并且信任他们能够完成工作。
6. 在团队内部,最具有效果并且富有效率的传递信息的方式,就是面对面的交谈。
7. 工作的软件是首要的进度度量标准。
8. 敏捷过程提倡可持续的开发速度。责任人、开发者和用户应该能够保持一个长期的、恒定的开发速度。
9. 不断地关注优秀的技能和好的设计会增强敏捷能力。
10.简单————是未完成的工作最大化的艺术————是根本。
11. 最好的结构、需求和设计出自于自组织的团队。
12.  每隔一定时间,团队会在如何才能更好有效地工作方面进行反省,然后相应地对自己的行为进行调整。

结论:

职业目标:给雇主和客户交付最大可能的价值。
虽然在项目中采用过程方法是出于好意的,但是膨胀的过程方法对于我们的失败至少是应该负一些责任的。
敏捷软件开发的原则和价值观构成了一个可以帮助团队打破膨胀循环的方法。

可选择的敏捷过程:SCRUM,Crystal,特征取得软件开发(Feature Driven Development,简称 FDD),自适应软件开发(Adaptive Software Development,简称 ADP),以及最重要的极限编程(eXtreme Programming,简称XP)。

第2章 极限编程概述

极限编程(eXtreme Programming,简称 XP)是敏捷方法中最著名的一个。它由一系列简单却相互以来的实践组成。这些实践结合在一个形成了一个胜于部分结合的整体。

  1. 客户作为团队成员 > 客户和开发人员应该在一起工作。
  2. 用户素材 > 用户素材就是正在进行的关于需求谈话的助记符。
  3. 短交付周期 > 迭代计划 >> 每次迭代通常耗时两周,这是一次较小的交付,由客户根据开发人员确定的预算二选择的一些用户素材组成。 >> >> 一旦迭代开始,客户就同意不再修改当次迭代中用户素材的定义和优先级别。 > > 发布计划 >> 一般6次迭代执行一次发布计划,它表示一次较大的交付。 >> >> 发布计划不是一成不变的,客户可以随时改变计划的内容。
  4. 验收测试 > 用户素材的验收测试实在就要实现该用户素材之前或实现该用户素材的同时进行编写的。 >> > 一旦通过一项验收测试,九江该测试加入到已经通过的验收测试集合中,并决不允许该测试再次失败。验收测试集合将不断增长,并每天会被多次运行。一旦验收测试失败了,那么系统的创建就宣告失败,就可以防止有错误的系统被创建。
  5. 结对编程 > 两个开发人员使用同一台电脑共同完成产品代码。结对的关系每天至少改变一次,即跟团队中的每一个其他成员一起工作。这将加快专业知识在团队中传播。这样,在紧要关头,其他团队成员就能够代替所需要的专家。 >> > 研究表明,结对非但不会降低开发团队的效率,而且会大大减少缺陷率。
  6. 测试开发的开发方法 > 先编写单元测试,再编写功能代码,让相应地单元测试通过。 >> > 当为了使测试用例通过而编写代码时,会激发你去解除各个模块间的耦合,这样能够独立地对它们进行测试。
  7. 集体所有权 > 结对编程中的每一对开发人员都具有拆出(check out)任何模块并对它进行改进的权利。即开发人员不是对一个特定的模块或技术单独负责,而可以参加其他方面的任务。
  8. 持续集成 > 开发人员每天会多次拆入(check in)他们的代码进行集成,所有的其他人负责代码的合并工作。 >> > XP 团队每天会进行多次系统构建,他们会重新创建整个系统。最终的结果是一个可以访问的 Web 站点。
  9. 可持续的开发速度 > XP 的规则是不允许团队加班工作。在版本发布前的一个向前是该规则的唯一例外。
  10. 开放的工作空间 > 密歇根大学的一项研究表明,在 “充满积极讨论的屋子” 里面工作,生成率非但不会降低,反而会成倍地提高。
  11. 计划游戏 > 计划游戏的本质是划分业务人员和开发人员之间的职责。业务人员决定特性的重要性,开发人员决定实现一个特性所花费的代价。
  12. 简单的设计 > 仅仅关注于计划在本次迭代中要完成的用户素材,不考虑那些未来的用户素材。 > > — > 考虑能够工作的最简单的事情 >> 总是尽可能寻找能实现当前用户素材的最简单的设计 > > 你讲不需要它 >> 不要提前引用不需要的基础结构,除非有十分明显的迹象表明现在引用这些基础结构比继续等待更加合算。 > > 一次,并且只有一次 >> 不能容忍重复的代码。 >> >> 消除重复最好的方法就是抽象。消除重复的行为会迫使团队提炼出许多的抽象,并进一步减少了代码间的耦合。
  13. 重构 > 重构是持续进行的,而不是在项目结束时、发布版本时、迭代结束时、甚至每天快下班时才进行的。重构是我们每隔一个小时或者半个小时就要去做的事情。通过重构,我们可以持续地保持尽可能干净、简单并且具有表现力的代码。
  14. 隐喻 > 它是将整个系统联系在一起的全局视图;它是系统的未来景象,是它使得所有单独模块的位置和外观变得明显直观。 >> > 隐喻通常可以归结为一个名字系统。这些名字提供了一个系统组成元素的词汇表,并且有助于定义它们之间的关系。例如:将一个文字输入输出系统比喻成一个装卸卡车拖运垃圾,然后将每个关键部件进行类比,就可以对整个系统有一个直观的了解。

结论:

极限编程是一种优良的、通用的软件开发方法。项目团队可以拿来直接采用,也可以增加一些时间,或者对其中的一些实践进行修改后再采用。

第3章 计划

下面内容是对极限编程中计划游戏部分的描述。

结论:

通过一次次的迭代和发布,项目进入了一种可以预测的、舒适的开发节奏。
这听起来好像是美好轻松的,其实并不是这样。涉众对过程产生的数据并不总是满意的,特别是在刚刚开始时。使用敏捷方法并不意味着涉众就可以得到他们想要的。它只不过意味着他们将能够控制者团队以最小的代价获取最大的商业价值。

第4章 测试

测试驱动的开发方法 > 首先编写测试,我们就迫使自己把程序设计为可测试的,这样程序就必须和它的周边环境解耦。这样,首先编写测试迫使我们接触软件中的耦合。 >> > 首先编写测试的另一个重要效果,是测试可以作为一种无价的文档形式。

验收测试 > 单元测试是用来验证系统中个别机制的白盒测试。 >> > 验收测试是用来验证系统满足客户需求的黑盒测试 >> > 验收测试是关于一项特性的最终文档。 >> > 此外,首先编写验收测试的行为对于系统的架构方面具有深远的影响。为了使系统具有可测试性,就必须要在很高的系统架构层面对系统进行解耦合。 >> > 在项目迭代的初期,虽然手工进行验收测试很方便,但是这样做使得在迭代的初期就丧失了由自动化验收测试的需要带来的对系统进行解耦合的促进力。

结论:

如果能够一天多次地运行所有的测试。那么系统失效的时间就绝不会超过几分钟。

也许,测试最重要的好处就是它对于架构和设计的影响。为了使一个模块或者应用程序具有可测试性,必须要对它进行解耦合。越是具有可测试性,耦合关系就越弱。全面地考虑验收测试和单元测试的行为对于软件的结构具有深远的正面影响。

第5章 重构

结论:

重构就好比用餐后对厨房的清理工作。第一次你没有清理它,你用餐是会快一点。但由于没有做清洁,第二天做准备工作的时间就更长一点。的确如果跳过清洁工作,你今天总是能够很快用完餐,但是最终你得花大量的时间去更换烹饪器具。如果是代码,那么这是致命的。

第6章 一次编程实践

保龄球比赛

首先要熟悉业务,熟悉规则。
然后大概划分类图,编写测试代码,并根据实际场景,完善测试代码和功能代码。
在这个过程中不断重构。

结论:

有些类并不需要,所以也不是说所有的东西都要用一个对象来封装。

第 Ⅱ 部分 敏捷设计

拙劣设计的特征: > - 僵化性:很难对系统进行改动。 > - 脆弱性:对系统的改动会导致系统中和改动的地方在概念上无关的地方出现问题。 > - 牢固性:很难解开系统的纠结,使之成为一些可在其他系统中重用的组件。 > - 粘滞性:做正确的事情比做错误的事情要困难。 > - 不必要的复杂性:设计中包含不具有任何直接好处的基础结构。 > - 不必要的重复:设计中包含有重复的结构,而该重复的结构本可以使用单一的抽象进行统一。 > - 晦涩性:很难阅读、理解。没有很好地表现出意图。

原则: > - 单一职责原则:SRP > - 开放——封闭原则:OCP > - Liskov 替换原则:LSP > - 依赖倒置原则:DIP > - 接口隔离原则:ISP

第7章 什么是敏捷设计

设计不是一组和代码分离的的UML图。最后,源代码就是设计。

如果我们的设计由于持续、大量的需求变化而失败,那就表明我们的设计和实践本身是有缺陷的。

保持尽可能好的设计:

从来不说“稍后我们会回来修正它”,他们决不让腐化出现。

结论:

请记住,敏捷开发人员不会对一个庞大的系统预先设计应用那些原则和模式。相反,这些原则和模式被应用在一次次的迭代中,力图使代码以及代码所表达的设计保持干净。

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

对于一个类而言,应该仅有一个引起它变化的原因。

Retangele 类具有两个方法,一个方法把矩形绘制在屏幕上,另一个方法计算矩形的面积。

这个设计违反了单一职责原则(SRP)。它有两个职责,第一个职责提供了一个矩形几何形状的数学模型;第二个职责是把矩形在一个图形用户界面上绘制出来。

由图可以看出,其中 draw() 方法需要依赖GUI库,而用户图形应用程序也需要引用GUI库,就导致了模块的重复引用。

一个较好的设计是把两个职责分离到两个完全不同的类中。
把 Rectangle 类中进行计算的部分移到 GeometryRactangle 类中。然后 Rectangle 类通过单向关联的关系,

什么是职责: > 我们把职责定义为“变化的原因”。如果你能够想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责。

程序8.1:
该接口所声明的 4 个函数是调制解调器所具有的的功能。
然而,该接口中却显示出两个职责:连接管理(dial、hangup)和数据通信(send、revc)

如果连接函数的经常变化,就需要经常被重新编译,而影响到通信函数,所以这两个职责应该被分离。如图 8.3 中所示。

另一方面,如果应用程序的变化总是导致这两个职责同时变化,那就不必分离它们。

分离耦合的职责 > 我们可以吧 ModemImplementation 类看作是一个杂凑物,或者一个瑕疵。然而,请注意所有的依赖关系都和它无关。谁也不需要依赖于它。除了 main 外,谁也不需要知道它的存在。

持久化

第9章 开放——封闭原则(OCP)

第10章 Liskov 替换原则(LSP)

第11章 依赖倒置原则(DIP)

第12章 接口隔离原则(ISP)


第 Ⅲ 部分 薪水支付案例研究


第 Ⅳ 部分 打包薪水支付系统


第 Ⅴ 部分 气象站案例研究


第 Ⅵ 部分 EST案例研究


附录A UML表示法 Ⅰ:CGI 示例

A.1 课程登记系统:问题描述

参与者 > 参与者是那些和系统进行交互,但是又位于系统之外的实体。系统的用户通常担任这些角色。 > - 登记者 > - 登记处工作人员 > - 学生

用例 > 参与者与系统之间的交互,称为用例。 >> > 用例从参与者的视角描述了参与者和系统之间的交互。 >> > 其中不涉及任何系统内部的工作方式,也没有用户界面的任何细节描述。