一灯能除千年暗,一智能灭万年愚。 —— 慧能,中国禅宗第6代祖师
第1章 敏捷 —— 高效软件开发之道
不管是预料之外的波浪冲击,还是预想不到的设计失败,在这两种情况下敏捷都意味着可以快速地适应变化
敏捷开发就是在一个高度协作的环境中,不断地使用反馈进行自我调整和完善
第2章 态度决定一切
专业的态度应该着眼于项目和团队的积极结果,关注个人和团队的成长,围绕最后成功开展工作
习惯1:做事
指责不能该修复Bug(Blame doesn't fix bugs)
过程符合标准并不意味着结果是正确的,敏捷团队重结果胜于过程
清晰地表明你的目的是解决问题,而不是指责他人或者进行争辩
把矛头对准问题的解决办法,而不是人。这是真正有用处的正面效应
“这不是我的错”这句话不对,“这都是你的错”这句话更不对
习惯2:欲速则不达
防微杜渐(Beware of land mines)
不要孤立地编码(Don't code in isolation)
使用单元测试(Use unit tests)
不要坠入快速的简单修复之中,要投入时间和精力保持代码的整洁、敞亮
不要急于修复一段没能真正理解的代码。这种+1/-1的病症始于无形,但是很快就会让代码一团糟。要解决真正的问题,不要治标不治本
习惯3:对事不对人
消极扼杀创新(Negativity kills innovation)
负面的评论和态度扼杀了创新
你不需要很出色才能起步,但是你必须起步才能变得很出色
能容纳自己并不接受的想法,表明你的头脑足够有学识
没有最好的答案,只有更合适的方案
设定期限能够 帮你在为难的时候果断作出决策,让工作可以继续进行
设计充满了妥协(生活本身也是如此),成功属于意识到这一点的团队
对事不对人。让我们骄傲的应该是解决了问题,而不是比较出谁的主意更好
只有更好,没有最好。尽管“最佳实践”这个术语到处在用,但实际上不存在“最佳”,只有在某个特定条件下更好的实践
习惯4:排除万难,奋勇前进
做正确的事。要诚实,要有勇气去说出实情。有时,这样做很困难,所以我们要有足够的勇气
如果涉及或代码中出现了奇怪的问题,花实践去理解为什么代码会是这样的。如果你找到了解决办法,但代码仍然令人费解,唯一的解决办法是重构代码,让它可读性更强。如果你没有马上理解那段代码,不要轻易地否定和重写它们。那不是勇气,而是鲁莽
第3章 学无止境
在一个企业化的社会中,只有一个人会为你负责 —— 你自己。是否能跟上变化,完全取决于你自己
如果你跟踪技术变化,那么学习这些新东西对你来说就是了解这些增量变化
学习新的技术和新的开发方法和重要,同时你也要能摒弃陈旧和过时的开发方法
习惯5:跟踪变化
迭代和增量式的学习、了解最新行情、参加本地的用户组活动、参加研讨会议、如饥似渴地阅读
跟踪技术变化。你不需要精通所有技术,但需要清楚知道行业的动向,从而规划你的项目和职业生涯
你不可能精通每一项技术,没有必要去做这样的尝试。只要你在某些方面成为专家,就能使用同样的方法,很容易成为新领域的专家
习惯6:对团队投资
一个学习型的团队才是较好的团队
坚持有计划有规律地举行讲座。持续、小步前进才是敏捷。稀少、间隔时间长的马拉松式会议非敏捷也
习惯7:懂得丢弃
在学习一门新技术的时候,多问问自己,是否把太多旧的态度和方法用在了新技术上
根深蒂固的习惯不可能轻易地就丢弃掉(Expensive mental models aren't discarded lightly)
丢弃的第一步,就是要意识到你还在使用过时的方法,做到真正丢弃旧习惯
不是完全忘记旧的习惯,而是只在适当的技术时才使用它
习惯8:打破沙锅问到底
为了解决问题,你需要很好地了解系统的全局。你需要查看所有你认为和问题相关的部分 —— 即便其他人觉得这并不想干
“这个,我不知道”是一个好的起点,应该由此进行更进一步的调查,而不应该在此戛然而止
习惯9:把握开发节奏
让你的工作有一个节奏,在每天下班的时候,提交所有的工作,开心地收工。这样,明天就能开始新的内容,解决下一系列难题
项目开发需要有一致和稳定的节奏。编辑,运行测试,代码复审,一致的迭代,然后发布
第4章 交付用户想要的软件
你不可能战胜变化,敏捷 —— 取决于你识别和适应变化的能力
习惯10:让客户做决定
决定什么不该决定(Decide what you shouldn't decide)
开发者能做的一个最重要的决定就是:判断是哪些是自己决定不了的,应该让企业主做决定
当你和客户讨论问题的时候,准备好几种方案。不是从技术的角度,而是从业务的角度,介绍每种方案的优缺点,以及潜在的成本和利益
不要随意假设低级别的问题不会影响他们的业务,如果能影响他们的业务,就是有价值的问题
习惯11:让设计指导而不是操纵开发
设计满足实现即可,不必过于详细(Design should be only as detailed as needed to implement)
设计可以分为两层:战略和战术
冯诺依曼:“如果你自己都不清楚所谈论的东西,就根本不可能精确地描述它”
战略级别的设计不应该具体说明程序方法、参数、字段和对象交互精确顺序的细节
好的设计应该是正确的,而不是精确的
“不要在前期做大量的设计”并不是说不要设计。只是说在没有经过真正的代码验证之前,不要陷入太多的设计任务。当对设计一无所知的时候,投入编码也是一件危险的事。如果深入编码只是为了学习或创造原型,只要你随后能把这些代码扔掉,那也是一个不错的办法
习惯12:合理地使用技术
盲目地为项目选择技术框架,就好比是为了少交税而生孩子(Blindly picking a framework is like having kids to save taxes)
这个技术框架真能解决这个问题吗?如果需要,先做一个小的原型
也许为了迎合你发现的给你,你正在为它们找问题
不要开发你能下载到的东西(Don't build what you can download)
虽然有时需要从最基础开发所有你需要的东西,但那是相当危险和昂贵的
习惯13:保持可以发布
任何时候只要你没有准备好,那就是敌人进攻你的最佳时机
已提交的代码应该随时可以行动(Checked-in code is always ready for action)
如果你不得不让系统长期不可以发布,那就做一个(代码和架构的)分支版本,你可以继续进行自己的实验,如果不行,还可以撤销,从头再来。千万不能让系统既不可以发布,又不可以撤销
习惯14:提早集成,频繁集成
在产品的开发过程中,集成是一个主要的风险区域
绝不要做大爆炸式的集成(Never accept big-bang integration)
成功的集成就意味着所有的单元测试不停地通过。正如医学界希波克拉底的誓言:首先,不要造成伤害
习惯15:提早实现自动化部署
不幸的是,大部分开发者只会在项目的尾期才开始考虑部署问题
质量保证人员应该测试部署过程(QA should test deployment)
如果你打算把持续部署系统和产品CD或者DVD刻录机连接到一起,你就可以自动地为每个构建制作出一个完整且有标签的光盘。任何人想要最新的构建,只要从架子上拿最上面的一张光盘安装即可
习惯16:使用演示获得频繁反馈
需求就像是流动着的油墨(Requirements are as fluid as ink)
你生产出了他们曾经要求过的软件,但却不是他们现在真正想要的。那最后的结果就是:惊讶、震惊和失望,而不是满意
清晰可见的开发。每隔一两周,邀请所有的客户,给他们演示最新完成的功能,积极获得他们的反馈
演示是用来让客户提出反馈的,有助于驾驭项目的方向。如果缺少功能或者稳定性的时候,不应该拿来演示,那只能让人生气
可以及早说明期望的功能:让客户知道,他们看到的是一个正在开发中的应用,而不是一个最终已经完成的产品
习惯17:使用短迭代,增量发布
给我一份详细的长期计划,我就会给你一个注定完蛋的项目(Show me a detailed long-term plan, and I'll show you a project that's doomed)
对付大项目,最理想的办法就是小步前进
大部分用户都是希望现在就有一个够用的软件,而不是在一年之后得到一个超级好的软件
增量的发布必须是可用的,并且能为用户提供价值。你怎么知道用户会觉得有价值呢?这当然要去问用户。
习惯18:固定的价格就意味着背叛承诺
固定的价格就是保证要背叛承诺(A fixed price guarantees a broken promise)
敏捷不是意味着“开始编码,我们最终会知道何时可以完成”。你仍然需要根据当前的知识和猜想,做一个大致的评估,解释如何才能到达这个目标,并给出误差范围
第5章 敏捷反馈
习惯19:守护天使
编写能产生反馈的代码(Coding feedback)
人们不编写单元测试的很多借口都是因为代码中的设计缺陷。通常,抗议越强烈,就说明设计越糟糕
习惯20:先用它再实现它
编程之前,先写测试(Write tests before writing code)
好的设计并不意味着需要更多的类(Good design doesn't mean more classes)
不要把测试优先和提交代码之前的测试等同起来。测试先行可以帮助你改进设计,但是你还是需要在提交代码之前做测试。
习惯21:不同环境,就有不同问题
使用自动化会节省时间(Automate to save time)
硬件比开发人员的时间便宜。但如果你有很多配置,要支持大量的平台,可以选择哪些平台需要内部测试
习惯22:自动化测试
为核心的业务逻辑创建测试。让你的客户单独验证这些测试,要让它们像一般的测试一样可以自动运行
习惯23:度量真实的进度
专注于你的方向(Focus on where you're going)
一周工作40个小时,不是说你就有40个小时的编码时间。你需要减去会议、电话、电子邮件以及其他相关活动的时间
习惯24:倾听用户的声音
这是一个bug(It is a bug)
每一个抱怨的背后都隐藏了一个事实。找出真相,修复真正的问题
没有愚蠢的用户,只有愚蠢、自大的开发人员
第6章 敏捷编码
习惯25:代码要清晰地表达意图
C.A.R Hoare:“设计软件有两种方式,一种是设计得尽量简单,并且明显没有缺陷。另一种方式是设计得尽量复杂,并且没有明显的缺陷。”
代码清晰程度的优先级应该排在执行效率之前
应该让自己或团队的其他任何人,可以读懂自己一年前写的代码,而且只读一遍就知道它的运行机制
习惯26:用代码沟通
不要用注释来包裹你的代码(Don't comment to cover up)
源代码可以被读懂,不是因为其中的注释,而应该是由于它本身优雅而清晰
代码能够自解释,而不用依赖注释
良好的命名可以向读者传递大量的正确信息,不好的命名不会传递任何信息,糟糕的命名则会传递错误的信息
不必费尽新机去用繁冗的名字替换大家已习惯的名称
解释代码做了什么的注释用处不那么大。相反,注释要说明为什么会这样写代码
习惯27:动态评估取舍
问题的关键是要多长个心眼儿,而不是总按照习惯的思路去解决问题
没有最佳解决方案(No best solution)
过去用过的解决方案对当前的问题可能适用,也可能不适用。不要事先预设结论,先看看现在是什么状况
习惯28:增量式编程
在写了几行代码之后,你会迫切地希望进行一次构建/测试循环。在没有得到反馈时,你不想走得太远
习惯29:保持简单
简单不是简陋(Simple is not simplistic)
代码几乎总是可以得到进一步精炼,但是到了某个点之后,再做改进就不会带来任何实质性的好处了。这是开发人员就该停下来,去做其他方面的工作了
习惯30:编写内聚的代码
根据单一职责原则,一个模块应该只有一个发生变化的原因
感觉类和组件的功能都很集中:每个类或组件只做一件事,而且做得很好。bug很容易跟踪,代码也易于修改,因为类和组件的责任都很清晰
习惯31:告知,不要询问
面向过程的代码取得信息,然后做出决策。面向对象的代码让别的对象去做事情
将命令与查询分离开来(Keep commands separate from queries)
不要抢别的对象或组件的工作,告诉它做什么,然后盯着你自己的职责就好了
习惯32:根据契约进行替换
针对is-a关系使用继承,针对has-a或uses-a关系使用委托(Use inheritance for is-a, use delegation for has-a or uses-a)
相对继承来说,委托更加灵活,适应力更强
第7章敏捷调试
习惯33:记录问题解决日志
不要在同一处跌倒两次(Don't get burned twice)
维护一个问题及其解决方案的日志
习惯34:警告就是错误
将警告视为错误。签入带有警告的代码,就跟签入有错误或者没有通过测试的代码一样,都是极差的做法
习惯35:对问题各个击破
用原型进行分离(Prototype to isolate)
以二分查找的方式来定位问题是很有用的。也就是说,将问题空间分为两半,看看哪一半包含问题,再将问题的一半进行二分,并不断重复这个过程
习惯36:报告所有的异常
处理或是向上传播所有的异常。不要将它们压制不管,就算是临时这样做也不行。在写代码时要估计到会发生问题
习惯37:提供有用的错误信息
提供给用户的信息可以包含一个主键,以便于在日志文件或是审核记录中定位相关内容
第8章 敏捷协作
习惯38:定期安排会面时间
站会每个人要回答三个问题:昨天有什么收获?今天计划要做哪些工作?面临哪些障碍?
迅速地开始可以保证会议短小,不要浪费时间等着会议开始
习惯39:架构师必须写代码
不可能在PowerPoint中进行编程(You can't code in PowerPoint)
Donald E. Knuth:“新系统的设计者必须要亲自投入到实现中去。”
真正的架构师,如果不允许参与编码的话,他们会提出强烈的抗议
不要允许任何人单独进行设计,特别是你自己
习惯40:实行代码集体所有制
在团队中实行任务轮换制,让每个成员都可以接触到不同部分的代码,可以提升团队整体的知识和专业技能
要强调代码的集体所有制。让开发人员轮换完成系统不同领域中不同模块的不同任务
习惯41:成为指导者
教学相长(Knowledge grows when given)
努力爬到高处,再以蔑视的眼神轻视其他人,这似乎是人类本性
为团队成员在寻求帮助之前陷入某个问题的时间设定一个时限,一个小时应该是不错的选择
习惯42:允许大家自己想办法
感觉不是以填鸭式的方式给予别人帮助。不是有意掩饰,更非讳莫如深,而是带领大家找到自己的解决方案
习惯43:准备好后再共享代码
绝不要提交尚未完成的代码,故意签入编译未通过或是没有通过单元测试的代码,对项目来说,应被视为玩忽职守的犯罪行为
习惯44:做代码复查
Capers Jones《估算软件成本》:“要寻找深藏不露的程序bug,正式地进行代码检查,其效果是任何已知形式测试的两倍,而且是移除80%缺陷的唯一已知办法。”
要确保代码复查参与人员得到每次复查活动的反馈。作为结果,要让每个人知道复查完成后所采取的行动
习惯45:及时通报与问题
接受一个任务,也就意味着做出了要准时交付的承诺
经常抬头看看四周,而不是只埋头于自己的工作
也许你会喜欢: