敏捷开发修炼之道
大神的读书笔记
1. 敏捷——高效软件开发之道
-
敏捷开发宣言
- 个体和交互胜过于过程和工具
- 可工作的软件胜过面面俱到的文档
- 客户协作胜过合同谈判
- 响应变化胜过遵循计划
-
敏捷的精神
- 开发要持续不断,切勿时断时续
- 持续注入能量
-
敏捷的修炼之道
- 敏捷开发就是在一个高度协作的环境中,不断地使用反馈进行自我调整和完善。
- 在功能不变的情况下,重新设计部分代码,改善代码质量,这就是所谓的重构。
-
敏捷工具箱
- Wiki
- 版本控制
- 单元测试
- 自动构建
2. 态度决定一切
-
做事
- 指责不能修复bug
把矛头对准解决问题的办法,而不是人。这是真正有用处的正面效应。 - 切身感受
勇于承认自己不知道的答案,这会让人感到放心。
- 指责不能修复bug
-
欲速则不达
- 防微杜渐
- 不要孤立地编码
实行代码复查,不仅有助于代码更好理解,而且是发现bug最有效的方法之一。 - 使用单元测试
单元测试帮助你很自然地把代码分层,分成很多可管理的小块,这样就会得到设计更好、更清晰地代码。 - 不要坠入快速的简单修复之中。
要投入时间和精力保持代码的整洁、敞亮。
-
对事不对人
- 引导性的提出一个疑问,让他们自己意思到问题。
- 要专业而不是自我。
- 消极扼杀创新。
- 能欣赏自己并不接受的想法,表明你的头脑足够有学识。
- 有效的特殊技术:
- 设定最终期限
没有最好的答案,只有更合适的方案。 - 逆向思维
团队中的每个成员都应该意思到权衡的必要性。 - 设定仲裁人
仲裁人的责任就是确保每个人都有发言的机会,并维持会议的正常进行。 - 支持已经做出的决定
我们的目标是让项目成功满足用户需求。结果最重要。
- 设定最终期限
- 让我们骄傲的应该是解决了问题,而不是比较出谁的主意更好。
-
排除万难,奋勇前行
- 当发现问题时,不要试图掩盖这些问题。
- 践行良好习惯。
- 要诚实,要有勇气去说出实情。有时,这样做很困难,所以我们需要有足够的勇气。
- 如果受到了缺乏背景知识的决策者的抵制,你需要用他们能够听懂的话语表达。
3. 学无止境
敏捷需要不断的学习和充电
-
跟踪变化
- 迭代和增量式的学习
每天计划用一段时间来学习新技术,它不需要很长时间,但需要经常进行 - 了解最新行情
互联网上有大量关于学习新技术的资源 - 参加本地的用户组活动
- 参加研讨会议
计算机大会在世界各地举行,许多知名的顾问或作者主持研讨会或课程。这些聚会是向专家学习的最直接的好机会 - 如饥似渴地阅读
- 你不需要精通所有技术,但需清楚的知道行业的动向,从而规划你的项目和职业生涯。
- 迭代和增量式的学习
-
对团队投资
- 提供你和团队学习的更好平台
通过午餐会议可以增进每个人的知识和技能,并帮助大家聚集在一起进行沟通交流。唤起人们对技术和技巧的激情,将会对项目大有裨益。
- 提供你和团队学习的更好平台
-
懂得丢弃
- 根深蒂固的习惯不可能轻易地就丢弃掉
- 学习新的东西,丢弃旧的东西
在学习一门新技术的时候,要丢弃会阻止你前行的旧习惯。毕竟,汽车要比马车车厢强得多。
-
打破砂锅问到底
- 不停地问为什么
不能只满足别人告诉你的表面现象。要不停地提问知道你明白问题的根源。
- 不停地问为什么
-
把握开发节奏
- 敏捷项目会有一个节奏和循环,让开发更加轻松。
- 当你遇上艰难抉择的时候,固定的时候期限会促使你做决定。
- 解决问题,在事情变得一团糟之前
保持事件之间稳定重复的间隔,更容易解决常见的重复任务 - 项目开发需要有一致的稳定的节奏
4. 支付用户想要的软件
没有任何计划在遇敌后还能继续执行。
- 让客户做决定
- 在设计方面,做决定的时候必须有开发者参与。
- 决定什么不该决定
判断哪些是自己决定不了的,应该让企业主决定 - 让你的客户做决定
开发者、经理或者业务分析师不应该做业务方面的决定。用业务负责人能够理解的语言,向他们详细解释遇到的问题,并让他们做决定。 - 记录客户做出的决定,并注明原因。
- 不要用过于具体和没有价值的原因打扰繁忙的业务人员。如果问题没有影响,就应该是没有价值的。
- 让设计指导而不是操作开发
- 设计满足实现即可,不必过于详细
- 设计可以分为两层:
- 战略
只描述总体战略,不应深入到具体的细节,扮演的是地图的角色,指引你向正确的方向前进。 - 战术
战术设计的重点是集中在单个的方法或数据类型上。这时适合讨论如何设计类的职责。
- 战略
- 好设计是一张地图,它也会进化。
设计指引你向正确的方向前进,它不是殖民地,他不应该标识具体的路线。你不要被设计操纵。
-
合理地使用技术
- 盲目地为项目选择技术框架,就好比是为了少交税而生孩子。
- 找到了需要解决的问题,接下来需要考虑:
- 这个技术框架真的能解决这个问题吗?
如果需要,先做一个小的原型。 - 你将会被它拴住吗?
一些技术缺乏可取消性,一旦你使用了它,就会被它套牢,再也不可能回头了。 - 维护成本是多少?
- 这个技术框架真的能解决这个问题吗?
- 不要开发你容易下载到的东西
- 根据需要选择技术
首先决定什么是你需要的,接着为这些具体的问题评估使用技术。对任何要使用的技术,多问一些挑剔的问题,并真实地作出回答。
-
保持可以发布
- 已提交的代码应该随时可以行动
- 防止你提交破坏系统代码的简单工作流程:
- 在本地运行测试
- 检出最新的代码
- 提交代码
- 持续集成系统
在后台不停地检出、构建和测试代码的应用 - 保持你的项目时刻可以发布
保证你的系统随时可以编译、运行、测试并立即部署
-
提早集成,频繁集成
- 集成和独立不是相互矛盾的,你可以一边进行集成,一边进行独立开发。
- 决不要做大爆炸式的集成
- 代码集成是主要的风险来源。要想规避这个风险,只有提早集成,持续而有规律地进行集成
-
提早实现自动化部署
- 质量保证人员(QA)应该测试部署过程
- 一开始就实现自动化部署应用
使用部署系统安装你的应用,在不同的机器上用不同的配置文件测试依赖的问题。质量保证人员要像测试应用一样测试部署。
-
使用演示获得频繁反馈
- 需求就像是流动着的油墨
- 清晰可见的开发
在开发的时候,要保持应用可见(而且客户心中也要了解)。每隔一周或者两周,邀请所有的客户,给他们演示最新完成的功能,积极获得他们的反馈。
-
使用短迭代,增量发布
- 统一过程和敏捷方法都使用迭代和增量开发。
- 迭代开发: 你在小且重复的周期里完成各种开发任务:分析、设计、实现、测试和获得反馈。
- 给我一个详细的长期计划,我就会给你一个注定完蛋的项目
- 增量开发: 发布带有最小却可用功能块的产品。每个增量开发中,使用1~4周左右迭代周期。
-
固定的价格就意味着背叛承诺
- 基于真实工作的评估
让团队和客户一起,真正地在当前项目中工作,做具体实际的评估。由客户控制他们想要的功能和预算。
- 基于真实工作的评估
5. 敏捷反馈
-
守护天使
- 编写能产生反馈的代码
- 自动化单元测试
- 确保测试是可重复的
- 测试你的边界条件
- 不要放过任何一个失败的测试
- 单元测试能及时提供反馈
- 单元测试让你的代码更加健壮
- 单元测试是有用的设计工具
- 单元测试是让你自信的后台
- 单元测试是解决问题时的探测器
- 单元测试是可信的文档
- 单元测试是学习工具
- 使用自动化的单元测试
好的单元测试能够为你的代码问题提供及时的警报。如果没有到位的单元测试,不要进行任何设计和代码修改。
-
先用他再实现它
- 编码之前,先写测试
- 好的设计并不意味着需要更多的类。
- 将TDD(Test Driven Development)作为设计工具,它会为你带来更简单更有效用的设计。
-
不同环境,就有不同问题
- 使用自动化会节省时间
- 使用持续集成工具,在每一种支持的平台和环境中运行单元测试。要积极地寻求问题,而不是等问题来找你。
-
自动验收测试
- 为核心的业务逻辑创建测试
让你的客户单独验证这些测试,要让它们像一般的测试一样可以自动运行。
- 为核心的业务逻辑创建测试
-
度量真实的进度
- 专注于你的方向
- 不要用不恰当的度量来欺骗自己或者团队。要评估那些需要完成的待办事项。
-
倾听用户的声音
- 这是一个bug
- 每一个抱怨的背后都隐藏了一个事实
找出真相,修复真正的问题
6. 敏捷编码
-
代码要清楚的表达意图
- 设计软件有两种方式。
一种是设计得尽量简单,并且明显没有缺陷。另外一种方式是设计的尽量复杂,并且没有明显的缺陷。 - PIE(Program Intently and Expressively)原则
代码必须明确说明你的意图,而且必须富有表达力。这样可以让代码更易于被别人阅读和理解。代码不让人感到迷惑,也就减少了发生潜在错误的可能。一言以蔽之,代码应意图清晰,表达明确。 - 要编写清晰的而不是讨巧的代码
向代码阅读者明确表明你的意图。可读性差的代码一点都不聪明。
- 设计软件有两种方式。
-
用代码沟通
- 不要用注释来包裹你的代码
- 注释可用来为读者指定一条正确的代码访问路线图。为代码中的每个类或模块添加一个短小的描述,说明其目的以及是否有特别的需求。对于类中的每个方法可能要说明以下信息:
- 目的: 为什么需要这个方法
- 需求(前置条件): 方法需要什么样的输入,对象必须处于何种状态,才能让这个方法工作
- 承诺(后置条件) :方法成功执行后,对象处于什么样的状态,有那些返回值。
- 异常:可能会发生什么样的问题, 会抛出什么样的异常。
- 用注释沟通
使用细心选择的、有意义的命名。用注释描述代码意图和约束。注释不能代替优秀代码。
-
动态评估取舍
- 没有最佳解决方案
- 动态评估权衡
考虑性能、便利性、生产力、成本和上市时间。如果性能表现足够了,就将注意力方法其他因素上。不要为了感觉上的性能提升或者设计上的优雅,而将设计复杂化。
-
增量式编程
- 关键在于持续做一些细小而有用的事情,而不是做一段长时间的编程或重构。
- 在很短的编辑/构建/测试循环中编写代码
这要比花费长时间仅仅做编写代码的工作好得多。可以创建更加清晰、简单、易于维护的代码。
-
保持简单
- 简单不是简陋
- 开发可以工作的、最简单的解决方案
除非·有不可辩驳的原因,否则不要使用模式、原则和高难度技术之类的东西。
-
编写内聚的代码
- 内聚性用来评估一个组件(包、模块或配件)中成员的功能相关性。
- 让类的功能尽量集中,让组件尽量小。
要避免创建很大的类或组件,也不要创建无所不包的大杂烩类。
-
告知, 不要询问
- 面向过程的代码取得信息,然后做出决策。面向对象的代码让别的对象去做事情。
- 将命令与查询分离开来
- 不要抢别的对象或是组件的工作。告诉它做什么,然后盯着你自己的职责就好了。
-
根据契约进行替换
- Liskov替换原则:任何继承后得到的派生类对象,必须可以替换任何被使用的基类对象,而且使用者不必知道任何差异。
- 针对is-a关系使用继承;针对has-a或uses-a关系使用委托
- 通过替换代码来扩展系统:通过替换遵循接口契约的类,来添加并改进功能特性。要多使用委托而不是继承。
7. 敏捷调试
-
记录解决问题的日志
- 不要在同一个地方跌倒两次
每日日志 - 维护一个问题及其解决方案的日志
保留解决方案是修复问题过程的一部分,以后发生相同或类似问题时,就可以很快找到并使用了。 - 要记录团队做出一个重要决策的原因
- 不要在同一个地方跌倒两次
-
警告就是错误
- 将警告视为错误
签入带有警告的代码,就跟签入有错误或者没有通过测试的代码一样,都是极差的做法。签入构建工具中的代码不应该产生任何警告信息。
- 将警告视为错误
-
对问题各个击破
- 用原型进行分离
- 对问题进行各个击破
在解决问题时,要将问题域与其周边隔离开,特别是在大型应用中。
-
报告所有的异常
- 处理或是向上传播所有的异常
不要将它们压制不管,就算是临时的也不行。在写代码时要估计到会发生的问题。
- 处理或是向上传播所有的异常
-
提供有用的错误信息
- 展示有用的错误信息
提供更易于查找错误细节的方式。发生问题时,要展示出尽量多的支持细节,不过别让用户陷入其中。 -
区分错误类型
- 程序缺陷
- 环境问题
- 用户错误
-
通过跟踪记录报告的错误类型,可以为受众提供更加合适的建议。
- 展示有用的错误信息
8. 敏捷协作
-
定期安排会面时间
- 要保证会议议题不会发散,每个人都应该只回答下述三个问题:
- 昨天有什么收获?
- 今天计划要做哪些工作?
- 面临着哪些障碍?
-
每日立会有诸多好处:
- 让大家尽快投入到一天的工作中来
- 如果某个开发人员在某一点上有问题,他可以称此机会将问题公开,并积极寻求帮助
- 帮助团队带头人或管理层了解哪些领域需要更多的帮助,并重新分配人手
- 让团队成员知道项目其他部分的进展情况
- 帮助团队识别是都在某些东西上有重复劳动而耗费了精力,或者是不是某个问题有人已有现成的解决方案
- 通过促进代码和思路的共享,来提升开发速度
- 鼓励向前的动力: 看到别人报告的进度都在前进,会对彼此形成激励
-
使用立会
立会可以让团队达成共识。保证会议短小精悍不跑题。
- 要保证会议议题不会发散,每个人都应该只回答下述三个问题:
-
架构师必须写代码
- 不可能在PowerPoint幻灯片中进行编程
- 新系统的设计者必须要亲自投入到实现中去
- 架构师最主要的任务是通过找到移动软件设计不可逆的方式,从而去除所谓架构的概念
- 增加可逆性是注重时效的软件实现方式的关键构成部分
- 优秀的设计从积极的程序员那里开始演化
积极的编程可以带来深入的理解。不要使用不愿意编程的架构师——不知道系统的真实情况,是无法展开设计的。
-
实行代码集体所有制
- 要强调代码的集体所有制
让开发人员轮换完成系统不同领域中不同模块的不同任务。
- 要强调代码的集体所有制
-
成为指导者
- 教学相长(knowledge grows when given)
- 分享自己的知识很有趣——付出的同时便有收获。还可以鼓励别人获得更好的成果,而且提升了整个团队的实力。
- 结对编程是一种进行高效指导的、很自然的环境
-
允许大家自己想办法
- 能欣赏自己并不接受的想法,表明你的头脑足够有学识
- 给别人解决问题的机会
指给他们正确的方向,而不是直接提供解决方案。每个人都能从中学到不少东西
-
准备好后再共享代码
-
代码不执行提交操作的其他安全选择
- 使用远程访问
- 随身携带
- 使用带有底座扩展的笔记本电脑
- 使用源代码控制系统的特性
-
绝不要提交尚未完成的代码。故意签入编译未通过或没有经过单元测试的代码,对项目而言,应被视为玩忽职守的犯罪行为
-
-
做代码复查
- 代码复查和缺陷移除
要寻找深藏不露的程序bug, 正式的进行代码检查,其效果是任何已知形式测试的两倍,而且是移除80%缺陷的唯一已知方法 - 对于提升代码质量和降低错误率来说,代码复查是无价之宝。如果以正确的方式进行,复查可以产生非常实用而高效的成果。要让不同的开发人员在每个任务后复查代码
- 除非你可以让某段代码明确变得更好,否则不要随便批评别人的代码
- 代码复查和缺陷移除
-
及时通报进展与问题
- 发布进展状况,新的想法和目前正在关注的主题。不要等着别人来问项目状态如何
9. 尾声: 走向敏捷
- 一灯能除千年暗,一智能灭万能愚
- 只要一个新的习惯,就让团队发生了巨大的变化
- 拯救频临失败的项目
如果事态没有那么糟糕,可以采取更加全面、整齐的方式来引入敏捷习惯
- 引入敏捷:管理员指南
- 引入敏捷:程序员指南
nothing but……