敏捷开发(Agile Development) 是一种面临迅速变化的需求快速开发软件的能力。我们需要:
纪律和反馈的时间
保持软件灵活、可维护的设计原则
平衡这些原则的设计模式
1. 敏捷开发
人与人之间的交互是复杂的,并且其效果从来都难以预期,但确实工作中最为重要的方面。 –《人件》
原则(principle)、模式(parttern)、实践(practice)是重要的,但是人更重要。如果想要项目取得成功,就必须构建起具有合作精神的、自组织的团队。
1.1. 敏捷实践
缺乏有效的实践会导致不可预测、重复的错误。
1.1.1. 敏捷联盟
以下观点不是认为后面的不重要,而是前者重要性更高。
个体和交互 > 过程和工具 (先构建团队,再让团队基于需求配置环境。)
可工作的软件 > 面面俱到的文档
客户合作 > 合同谈判
响应变化 > 遵循计划
当我们构建计划时,应该确保计划是灵活的并且易于适应商务和技术方面的变化。
较好的策略:为下两周做详细的计划,为下三个月做粗率的计划,再以后就做极为粗糙的计划。
1.1.2. 原则
- 围绕被激励起来的人构建项目,提供需要的环境和支持
- 工作的软件是首要的进度度量标准
- 最优先的是通过尽早的、持续的交互有价值的软件来是客户满意,间隔时间可以是几周到几个月
- 即使在开发后期,也欢迎改变需求。敏捷过程利用变化来为客户创造竞争优势
- 开发周期,业务人员和开发人员天天在一起工作
- 面对面的交谈是最有效的传递信息方法
- 最后的构架、需求和设计出自于自组织的团队
- 不断关注优秀的技能和好的设计增强敏捷能力
- 周期性的在提高效率上反思,并做出调整
1.2. 极限编程概述
极限编程(eXtreme Programming, 简称XP)
1.2.1. 客户成为团队成员
以便知晓对方面临的问题,并共同去解决这些问题。
1.2.2. 用户素材
做计划只需要了解到能估算它的程度就可以了,需求的特定细节会随时间而改变,在新版本之后是关注新需求的好时机。
在XP 中,重要的是对需求细节的理解,而不是捕获细节。
1.2.3. 短交互周期
用户素材
用户会一直编写新的真正重要的用户元素到项目中
迭代计划
客户
:选择不超过开发人员本次迭代周期的用户素材,并在迭代开始后,不在修改当次迭代用户素材的定义和优先级别。
开发人员
:根据之前的迭代工作量预算本次迭代,在迭代期间自由分解用户素材为任务,并根据最具技术和商务意义的顺序开发任务。
发布计划
XP 团队通常会创建一个计划来规划随后大约6次迭代的内容。
验收测试
验收测试使用能够让他们自动并且反复运行的某种脚本语言编写,这些测试共同来验证系统是否按照用户指定行为运行。
集体所有权
如果你是专业领域有关GUI的,那么你最有可能去从事GUI 方面的任务,但是你将会被邀请去和别人结对从事有关中间件和数据库方面的任务。如果你决定学习另一们专业知识,你可以承担相关任务,并和能传授你这方面知识的专家一起工作,不会被限制在自己的专业领域。(个人认为有点偏重于理想化。)
持续集成
每个模块都可以在完成单元测试之后,合并到主线中。因而,XP 团队每天会进行多次系统构建。
可持续的开发速度
软件项目是马拉松长跑,而不是全速的短跑。团队必须要以一种可持续的速度前进,有意识的保持稳定、始终的速度。
团队位于开放的空间,充满交谈的环境下。每个人都可以获知Partner 遇到的麻烦,工作状态。
简单的设计
考虑能够工作的最简单的事情(如选择平面文件而不是数据库,选择简单的socket 而不是ORB(对象请求代理),RMI(远程方法调用)),只有在有证据情况下,才去引入这些。
代码的重构,消除退化腐朽的代码
使用简单的比喻,来说明指导整个脉络流程
2. 敏捷设计
敏捷团队,全局视图与软件一起演化。每次迭代中,系统设计都尽可能适用于当前系统,不会过多的预测未来的需求,更加关注于当前的系统结构。
较好的原则设计:
- 单一职责原则(The Single Responsibility Principle, 简称SRP)
- 开放-封闭原则(The Open-Close Principle, 简称OCP)
- Liskov 替换原则( The Liskov Substitution Principle, 简称LSP)
- 依赖倒置原则( The Dependency Inversion Principle, 简称DIP)
- 接口隔离原则(The Interface Segregation Principle 简称ISP)
2.1. 什么是敏捷设计
敏捷设计师一个过程,是一个持续应用原则、模式以及实践来改进软件的结构和可读性的过程。保证系统设计在任何时间都尽可能简单、干净,杜绝代码的腐化。
- 遵循敏捷实践去发现问题
- 应用设计原则去诊断问题
- 应用适当的设计模式解决问题
2.2. 单一职责原则(SRP)
就一个类而言,应该仅有一个引起他变化的原因。
如果一个类承担的职责太多,就等于把这些职责耦合在一起,进而导致脆弱的设计。
1 | interface Modem |
接口中有两个职责:连接, 数据通信。如果应用程序的变化会影响连接函数的签名,那么这个设计就具有僵化性的臭味。在这情况下,我们分离两个职责。
1 | interface Data_Channel |
但是,如果程序的变化总是导致这两个职责同事变化,就不必分离他们。
2.3. 开放-封闭原则(OCP)
主要特征:
- “对于扩展是开放的(Open for extension )”: 对模块进行扩张,使其满足新行为。
- “对于更改是封闭的(Closed for modification)”: 对模块行为扩张时,不必改动模块的源代码,模块的二进制执行版本(库、DLL,.jar文件)都无需改变。
这两点看似是矛盾的,请看如下解释。
抽象
模块依赖于某一抽象体,所以对它的更改是关闭的,通过这个抽象体的派生,扩展此模块的行为。
遵循OCP 代价是昂贵的,增加设计的复杂性,开发人员处理抽象数量有限。我们希望OCP 的应用限定在可能发生变化的上。
吊钩(hook)
在认为可能发生变化的地方放置吊钩(hook),会使软件更灵活些。
OCP 主要机制是抽象(abstraction) 和多态 (polymorphism)。
2.4. Liskov 替换原则(LSP)
LSP 提供了继承层次保持OCP 的指导, 只有保持了OCP 才会保证我们软件的灵活性,可重用性。
LSP: 子类型(subtype)必须能够替换掉他们的基类型(base type)。
Barbara Liskov 在1988年写下这个原则:
若对每隔类型S 的对象s, 都存在一个类型T 的对象t ,使得在所有针对T 编写的程序P 中,用s 替换t 后,程序P 的行为功能保持不变,则S 是T 的子类型。
2.5. 依赖倒置原则 (DIP)
依赖倒置原则:
- 高层模块不应该依赖于低层模块,二者都应该依赖于抽象
- 抽象不应该依赖于细节,细节应该依赖于抽象
如果高层模块依赖于低层模块,那么低层模块的修改将会影响并作用于高层模块。
2.6. 接口隔离原则(ISP)
不应该强迫客户依赖于他们不用的方法。
如果强迫客户程序依赖于他们不使用的方法,那么这些客户程序就面临着由于这些未使用的方法的改变所带来的变更。
更多的策略是: 使用多重继承分离接口