按照 What-Why-How 结构重新组织
第一部分:WHAT(是什么)
一、敏捷开发是什么
1.1 敏捷宣言(2001年)
1.2 敏捷十二条原则
最优先的是通过尽早、持续交付有价值的软件满足客户 欢迎需求变化,即使在开发后期 经常交付可工作的软件,间隔越短越好 业务人员和开发人员必须天天在一起工作 围绕被激励的个人构建项目,提供环境和支持,信任他们 面对面交谈是最高效的团队信息传递方式 可工作的软件是进度的主要度量标准 敏捷过程倡导可持续的开发速度 追求技术卓越和良好设计 简洁:最大化工作量的艺术是减少工作量 自组织团队产生最好的架构和设计 团队定期反思如何更高效,调整行为
1.3 极限编程(XP)四大价值观
沟通(Communication) - 团队成员、项目与客户间的紧密沟通 简单性(Simplicity) - 只做当前需要的事,不过度设计 反馈(Feedback) - 持续获取反馈,快速调整 勇气(Courage) - 勇于重构、勇于接受变化
1.4 XP十二项核心实践
二、设计原则是什么
2.1 SOLID五大原则
| S | |||
| O | |||
| L | |||
| I | |||
| D |
2.2 包的设计原则
2.3 设计的臭味(腐化症状)
三、设计模式是什么
3.1 创建型模式
3.2 结构型模式
3.3 行为型模式
第二部分:WHY(为什么)
一、为什么需要敏捷开发
1.1 传统开发的困境
1.2 敏捷开发要解决的问题
┌─────────────────────────────────────────┐│ 敏捷开发的核心目标 │├─────────────────────────────────────────┤│ 1. 更快交付可工作的软件 ││ 2. 更好地响应需求变化 ││ 3. 让客户真正参与到开发中 ││ 4. 保持可持续的开发速度 │└─────────────────────────────────────────┘二、为什么需要设计原则
2.1 代码为什么会腐化
"软件项目中需求是持续变化的,如果软件设计由于需求变化而退化,那我们就不是敏捷的。"
两大原因:
需求没有按照设计预见的方式进行变化 改动急迫且违反了原来的设计
2.2 设计原则的作用
| 诊断 | |
| 治疗 | |
| 预防 |
2.3 核心洞见
"唯一能够加快进度的方法便是缩减范围。不要经受不住诱惑盲目冲刺。"
"在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误。"
"只承担一次变化造成的改动代价,但不允许下一次变化带来更多的代价。"
三、为什么需要设计模式
3.1 什么是设计模式
"通过对设计概念的封装,解除了系统与逻辑、互联关系、设备之间的耦合。" —— COMMAND模式定义
设计模式是经过验证的最佳实践解决方案。
3.2 为什么要用设计模式
| 避免重复造轮子 | |
| 沟通便利 | |
| 代码更健康 | |
| 易于维护 |
3.3 模式不是万能药
"没有遇到变化的时候,就用模式,当然会变得臃肿了。" —— YAGNI
"术语'IS-A'的含义过于宽泛以至于不能作为子类型的定义。子类型的正确定义是'可替换性的'。"
四、三者的关系(核心串联)
4.1 敏捷开发的核心公式
敏捷开发人员知道要做什么,是因为:1. 遵循敏捷实践去发现问题 ← HOW(怎么做)2. 应用设计原则去诊断问题 ← WHY(为什么有问题)3. 应用适当的设计模式去解决问题 ← WHAT(具体用什么)软件开发的这三个方面的相互作用就是设计。4.2 三者关系图
┌─────────────────────────────────────────────────────────────┐│ 软件开发 │├─────────────────────────────────────────────────────────────┤│ ││ ┌─────────────────────────────────────────────────────┐ ││ │ 敏捷实践(HOW) │ ││ │ 测试驱动开发 → 发现问题 │ ││ │ 持续重构 → 保持代码健康 │ ││ │ 结对编程 → 代码审查 │ ││ └─────────────────────────────────────────────────────┘ ││ ↓ 诊断 ││ ┌─────────────────────────────────────────────────────┐ ││ │ 设计原则(WHY) │ ││ │ SOLID → 判断代码哪里不对 │ ││ │ SRP/OCP/LSP/DIP/ISP → 具体原则 │ ││ └─────────────────────────────────────────────────────┘ ││ ↓ 治疗 ││ ┌─────────────────────────────────────────────────────┐ ││ │ 设计模式(WHAT) │ ││ │ 具体的、可复用的解决方案 │ ││ │ Strategy/Observer/Factory/Command/... │ ││ └─────────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────┘4.3 类比理解
| 体检 | |
| 验血报告 | |
| 处方药 |
第三部分:HOW(怎么用)
一、敏捷实践怎么用
1.1 测试驱动开发(TDD)
红-绿-重构循环:
编写失败测试 (红) ↓编写刚好通过的代码 (绿) ↓ 运行测试 ↓ ├── 失败 → 修复代码 │ └── 通过 → 重构? │ ├── 否 → 编写下一个测试 │ └── 是 → 重构代码 │ ▼ 运行测试 → 继续TDD的三大好处:
功能验证 - 每一项功能都有测试验证 设计思考 - 从调用者角度思考接口 解耦 - 迫使我们把程序设计为可测试的
1.2 重构
定义: 在不改变软件可观察行为的前提下,改善其内部结构
时机: 持续重构,而非等到代码"太烂"才重构
常见重构手法:
1.3 简单设计
YAGNI原则: You Aren't Gonna Need It - 你不需要它
DRY原则: Don't Repeat Yourself - 不要重复
二、设计原则怎么用
2.1 应用场景速查
2.2 SOLID原则速记口诀
S - 单一职责:一个类做一件事O - 开放封闭:扩展不难,修改不行L - 里氏替换:子类能顶替父类I - 接口隔离:接口要小而专D - 依赖倒置:依赖抽象不依赖具体2.3 设计检查清单
三、设计模式怎么用
3.1 模式选择指南
需要封装请求? → COMMAND需要异步执行? → ACTIVE OBJECT需要算法骨架不变,步骤变化? → TEMPLATE METHOD需要算法需要切换? → STRATEGY需要简化复杂接口? → FACADE需要对象解耦? → MEDIATOR需要控制实例数量? → SINGLETON需要替代null? → NULL OBJECT需要统一单个和组合对象? → COMPOSITE需要一对多通知? → OBSERVER需要接口转换? → ADAPTER需要分离抽象与实现? → BRIDGE需要控制访问? → PROXY需要数据结构稳定,添加新操作? → VISITOR需要状态影响行为? → STATE3.2 模式对比
3.3 模式应用决策树
需要模式吗? │ ├── 变化还没有发生? → YAGNI,不要用模式 │ └── 确实需要模式? │ ├── 封装请求? → COMMAND ├── 异步执行? → ACTIVE OBJECT ├── 算法骨架固定,步骤变化? → TEMPLATE METHOD ├── 算法需要切换? → STRATEGY ├── 简化复杂接口? → FACADE ├── 对象耦合严重? → MEDIATOR ├── 控制实例数量? → SINGLETON ├── 替代null? → NULL OBJECT ├── 树形结构? → COMPOSITE ├── 一对多通知? → OBSERVER ├── 接口转换? → ADAPTER ├── 分离抽象与实现? → BRIDGE ├── 控制访问? → PROXY ├── 数据结构稳定,添加新操作? → VISITOR └── 状态影响行为? → STATE四、三者如何串联使用(完整示例)
4.1 典型开发流程
需求来了 ↓【敏捷实践 - HOW】 用TDD先写测试 ↓ 写最简单的代码让测试通过 ↓ 发现代码有问题(测试变得难写/代码僵硬) ↓【设计原则 - WHY】 诊断:违反了什么原则? - 代码僵化 → 违反SRP - 需要扩展就改代码 → 违反OCP - 依赖了具体类 → 违反DIP ↓【设计模式 - WHAT】 应用合适的模式解决问题 - 需要动态算法 → Strategy模式 - 需要对象创建分离 → Factory模式 - 需要一对多通知 → Observer模式 ↓【敏捷实践 - HOW】 重构代码应用模式 运行测试保证行为不变 ↓ 继续下一个功能4.2 案例:薪水支付系统
问题: 需要支持不同类型的员工(钟点工、月薪、销售)和不同的支付方式
应用SOLID原则:
应用设计模式:
第四部分:知识全景图
一、敏捷开发知识体系
┌─────────────────────────────────────────────────────────────┐│ 敏捷开发知识体系 │├─────────────────────────────────────────────────────────────┤│ ││ ┌───────────────────────────────────────────────────────┐ ││ │ 价值观层 │ ││ │ 敏捷宣言四条核心价值观 │ ││ └───────────────────────────────────────────────────────┘ ││ ↓ ││ ┌───────────────────────────────────────────────────────┐ ││ │ 原则层 │ ││ │ 敏捷十二条原则 + SOLID五大原则 │ ││ └───────────────────────────────────────────────────────┘ ││ ↓ ││ ┌───────────────────────────────────────────────────────┐ ││ │ 实践层 │ ││ │ XP实践 + 设计模式 + 重构 + 测试 │ ││ └───────────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────┘二、设计原则关系图
SRP △ ╱ ╲ ╱ ╲ ╱ ╲ LSP ─────┤ ├──── OCP ╲ ╱ ╲ ╱ ╲ ╱ ▼ DIP │ │ ISP关系说明:
SRP 和 OCP 是其他原则的基础 LSP 是 OCP 得以实现的主要手段 DIP 告诉我们如何依赖抽象 ISP 是接口级别的 SRP
三、GoF 23种模式分类
附录
附录一:关键洞见汇总
"唯一能够加快进度的方法便是缩减范围。不要经受不住诱惑盲目冲刺。"
"敏捷开发人员知道要做什么,是因为:遵循敏捷实践去发现问题,应用设计原则去诊断问题,应用适当的设计模式去解决问题。"
"软件项目中需求是持续变化的,如果软件设计由于需求变化而退化,那我们就不是敏捷的。"
"不存在完美的结构。只存在那些试图去平衡当前的代价和收益的结构。"
"最好的架构、需求和设计出自于自组织的团队。"
"没有遇到变化的时候,就用模式,当然会变得臃肿了。"
"模式不是万能药。"
附录二:知识起源
附录三:推荐学习路径
第一阶段:理解概念 ↓ 敏捷价值观和原则 → 什么是敏捷,为什么需要敏捷 ↓第二阶段:掌握实践 ↓ TDD → 重构 → 简单设计 → 如何做 ↓第三阶段:学习原则 ↓ SOLID五大原则 → 如何诊断代码问题 ↓第四阶段:学习模式 ↓ GoF 23种模式 → 如何解决具体设计问题 ↓第五阶段:串联使用 ↓ 在实际项目中体会三者的结合作者:哀的代码实验室
夜雨聆风