读书笔记之《高效程序员的45个习惯----敏捷开发之道》摘录
此次原创的意思是指这个文章中的内容是由笔者从《高效程序员的45个习惯----敏捷开发之道》书中摘录,而不是别人摘录的,但是内容并非笔者原创,所摘录的内容的版权均为《高效程序员的45个习惯-----敏捷开发之道》一书的作者以及翻译者所有,特此申明。
《高效程序员的45个习惯-敏捷开发之道》真是一本好书,程序员必读的著作之一。该文章会在笔者读书过程中慢慢更新,这是一个摘录,将该书中的45个习惯以及一些细节摘抄出来,希望可以帮到没时间读这本书的人,同时提醒自己时刻注意。
一、敏捷----高效软件开发之道
一句话精辟概括敏捷:敏捷开发就是在一个高度协作的环境中,不断地使用反馈进行自我调整和完善。
先难后易。我们首先要解决困难的问题,把简单的问题留到最后。
二、态度决定一切
1.做事。
解释清楚你想要什么,并清晰地表明你的目的是解决问题,而不是指责他人或者进行争辩。指责不会修复bug。把矛头对准问题的解决办法,而不是人。这是真正有用处的正面效应。勇于承认自己不知道答案,这会让人感觉放心。一个重大的错误应该被当作是一次学习而不是指责他人的机会。团队成员在一起工作,应该互相帮助,而不是互相指责。
2.欲速则不达。
防微杜渐。不要急于修复一段没有真正理解的代码。这种+1、-1的病症始于无形,但是很快就会让代码一团糟。要解决真正的问题,不要治标不治本。
不要孤立低编码。实行代码复审,花些时间去阅读他人的代码,确保代码是可读的和可理解的,并且不会随意加入一些“+1、-1”的代码。这也是发现bug的最有效的方法之一。
使用单元测试。测试驱动开发,单元测试帮你很自然地把代码分层,分成很多可管理的小块,这样你会得到设计更好、更清晰的代码。
不要坠入快速的简单修复之中。要投入时间和精力保持代码的整洁、敞亮。
3.对事不对人。
团队交流中,没有谴责,没有批判,不带情绪,只是简单地表达自己的观点。工作中不感情用事是需要克制力的,若你能展现出成熟大度来,大家一定不会视而不见。这需要有人带头,身体力行,去感染另一部分人。
在一个需要紧密合作的开发团队忠,如果能稍加注意礼貌对待他人,将会有益于整个团队关注真正有价值的问题,而不是勾心斗角,误入歧途。我们每个人都有一些极好的创新想法,同样也会萌生一些很愚蠢的想法。如果 你准备提出一个想法,却担心有可能被嘲笑,或你要提出一个建议,却担心自己丢面子,那么你就不会主动提出自己的建议了。
集体决策确实非常有效,但也有一些最好的创新源于很有见地的个人的独立思考。如果你是一个很有远见的人,就一定要特别尊重别人的意见。如果你是一个掌舵者,一定要把握方向,深思熟虑,吸取各方的意见。但是另一个极端是缺乏生气的委员会,每个设计方案都需要全票通过。这样的委员会总是小题大作,如果让他们造一匹木马,很可能最后造出的是骆驼。我们并不是建议你限制会议决策,只是你不应该成为一意孤行的首席架构师的傀儡。这里建议你牢记亚里士多德的一句格言:“能欣赏自己并不接受的想法,表明你的头脑足够有学识。”
支持已经做出的决定。一旦方案被确定了(不管是什么样的方案),每个团队成员都必须通力合作,努力实现这个方案。
让我们骄傲的应该是解决了问题,而不是比较出谁的主意更好。
4.排除万难,奋勇前进。
当发现问题是,不要试图掩盖这些问题。而是要有勇气站起来,说:“我现在知道了,我过去使用的方法不对。我想到了一些办法,可以解决这个问题-如果你有更好的想法,我也很乐意听一听-----但可能会多花些时间。”你已经把所有对问题的负面情绪抛诸脑后,你的意图很清楚,就是寻找解决方案。既然你提出大家一起努力来解决问题,那就不会有任何争辩的余地。这样会促进大家去解决问题。你深知怎样做才是正确的,或者至少知道目前的做法是错误的。要有勇气向其他项目成员、老板或者客户解释你的不同观点。也许会冒犯他们,但是你都要不顾一切,向着正确的方向奋力前进。要诚实,要有勇气去说出实情。有时,这样做很困难,所以我们要有足够的勇气。
三、学无止境
5.跟踪变化。
赫拉克利特说过:“唯有变化是永恒的。”当XML出现的时候,你花时间学习它。你深入研究ASP,熟知如何用它来开发Web应用。你虽然不是这些技术的专家,但也不是对它们一无所知。好奇心促使你去了解MVC是什么,设计模式是什么。你会使用一点Java,去试试那些让人兴奋的功能。
跟踪技术变化,你不需要精通所有技术,但需要清楚知道行业的动向,从而规划你的项目和职业生涯。
你能嗅到将要流行的新技术,知道它们已经发布或投入使用。如果必须要把工作切换到一种新的技术领域,你能做到。
在做决策前,你必须评估新技术的优势。开发一个小的原型系统,是对付技术狂热者的一剂良药。
如何跟上技术变化的步伐呢?下面是一些建议:
迭代和增量式的学习。每天计划用一段时间来学习新技术,它不需要很长时间,但需要经常进行。记下那些你想学习的东西-当你听到一些不熟悉的术语或者短语时,简要地把它记录下来。然后在计划的时间中深入研究它。
了解最新行情。互联网上有大量关于学习新技术的资源。阅读社区讨论和邮件列表,可以了解其他人遇到的问题,以及他们发现的很酷的解决方案。选择一些公认的优秀技术博客,经常去读一读,了解那些顶尖的博客作者们正在关注什么。
参加本地的用户组活动。听讲座,然后积极加入到问答环节中。
参加研讨会。这些会议是向专家学习的最直接的好机会。
如饥似渴的阅读。找一些关于软件开发喝非技术主题的好书,也可以是一些专业的期刊和商业杂志,甚至是一些大众媒体新闻。
6.对团队投资。
一个学习型的团队才是较好的团队。
午餐会议是在团队中分享知识非常好的方式。每周,要求团队中的一个人主持讲座。他会给大家介绍一些概念,演示工具,或者做团队感兴趣的任何一件事情。你可以挑一本书,给大家说说其中一些特别内容、项目或者实践。无论什么主题都可以。先让主持人讲15分钟,然后进行开放式讨论。通过午餐会议可以增进每个人的知识和技能,并帮助大家聚集在一起进行沟通交流。唤起人们对技术和技巧的激情,将会对项目大有裨益。坚持有计划有规律地举行讲座,不要局限于纯技术的图书和主题,相关的非技术主题(项目估算、沟通技巧等)也会对团队有帮助。
7。懂得丢弃。
学会丢弃旧习惯、旧技术,力求尽可能完全转入新的开发环境。学习新的东西,丢弃旧的东西。在学习一门新技术的时候,要丢弃会阻止你前进的就习惯。毕竟,汽车要比马车车厢强得多。
8.打破砂锅问到底.
为了解决问题,你需要知道许多可能的影响因素。当找人询问任何相关的问题时,让他们耐心地回答你的问题,这是你的职责。
不停地问为什么。不能只满足于别人告诉你的表面现象。要不停地提问直到你明白问题的根源。
9.把握开发节奏。
解决任务,在事情变得一团糟之前。保持事件之间稳定重复的间隔,更容易解决常见的重复任务。
项目开发需要有一致和稳定的节奏。编辑,运行测试,代码复审,一致的迭代,然后发布。如果知道什么时候开始下一个节拍,跳舞就会更加容易。
每天结束的时候,测试代码,提交代码,没有残留代码。不要搞得经常加班。以固定、有规律的长度运行迭代,找到团队最舒服可行的时间值,然后坚持。如果开发节奏过于密集,你会精疲力尽。就像是减肥一样,一点点的成功也是一个很大的激励。小而可达到的目标会让每个人全速前进。庆祝每一次难忘的成功:共享美食和啤酒或者团队聚餐。
四、交付用户想要的软件
10.让客户做决定。
开发者或者项目经理能做的一个最重要决定就是:判断哪些是自己决定不了的,应该让企业主做决定。你不需要自己给业务上的关键问题做决定。如果遇到一些问题,会影响到系统的行为或如何使用系统,把这个问题告诉业务负责人。开发者、经理或者业务分析师不应该做业务方面的决定。用业务负责人能够理解的语言,向他们详细解释遇到的问题,并让他们做决定。
11.让设计指导开发而不是操纵开发
敏捷开发建议你早在设计初期就开始编码:先画关键工作图,然后才考虑开始编码。
设计可以分为两层:战略和战术。前期的设计应该是只描述总体战略,不应该深入到具体的细节。不要一开始就进行战术设计,它的重点是集中在单个的方法或数据类型上。这时更适合讨论如何设计类的职责。因为这仍然是一个高层次、面向目标的设计。事实上,CRC(类-职责-协作)卡片的设计方法就是用来做这个事情的。每个类按照下面的术语描述。
类名。
职责:它应该做什么?
协作者:要完成工作它要与其他什么对象一起工作?
好设计是一张地图,它也会进化。设计指引你向正确的方向前进,它不是殖民地,它不应该标识具体的路线。你不要被设计(或设计师)操纵。
白板、草图、便利贴都是非常好的设计工具。复杂的建模工具只会让你分散精力,而不是启发你的工作。
12.合理地使用技术。
在考虑引入新技术或框架之前,先把你需要解决的问题找出来。接下来考虑如下几方面。
这个技术框架真能解决这个问题吗?确保它能解决你的问题,并没有任何的毒副作用。如果需要,先做一个小的原型。
你将会被它套住吗?
维护的成本是多少?
不要开发你能下载到的东西。代码写得越少,需要维护的东西就越少。
根据需要选择技术。首先决定什么是你需要的,接着为这些具体的问题评估使用技术。对任何要使用的技术,多问一些挑剔的问题,并真实地作出回答。
13.保持可以发布。
保证你的系统随时可以编译、运行、测试并立即部署。下面是一个简单的工作流程,可以防止你提交破坏系统的代码。
在本地运行测试。先保证你完成的代码可以编译,并且能通过所有的单元测试。接着确保系统中的其他测试都可以通过。
更新到最新的代码。从SVN中更新代码到最新的版本,再编译和运行测试。这时你往往发现冲突了,解决冲突,并编译测试。
提交代码。现在是最新代码并通过编译和测试,你可以提交它们了。
创建分支。如果你不得不让系统长期不可以发布,那就做一个分支版本。你可以继续自己的实验,如果不行,还可以撤销重来。
14,提早集成,频繁集成。
敏捷开发的一个主要特点就是持续开发,而不是三天打鱼两天晒网似地工作。特别是在几个人一起开发同一个功能的时候,更应该频繁地集成代码。
代码集成是主要的风险来源。要想规避这个风险,只有提早集成,持续而有规律的集成。
15.提早实现自动化部署。
质量保证人员 应该测试部署过程。
16.使用演示获得频繁反馈。
需求就像是流动这的油墨。如果你期望在项目开始之前,就能给你可靠和明确的需求,那就大错特错了,赶快醒醒吧!
在开发的时候,要保持应用可见(而且客户心中也要了解)。每隔一周或两周,邀请所有的客户,给他们演示最新完成的功能,积极获得他们的反馈。
17.使用短迭代,增量发布。
敏捷方法使用迭代和增量开发。使用增量开发一次开发应用功能的几个小组。每一轮开发都是基于前一次的功能,增加为产品增值的新功能。这时,你就可以发布或者演示产品。发布带有最小却可用功能块的产品。每个增量开发中,使用1~4周左右迭代周期。
迭代开发是,在小且重复的周期里,你完成各种开发任务:分析、设计、实现、测试和获得反馈,所以叫做迭代。迭代的结束就标记一个里程碑。
对付大项目,最理想的办法是小步前进,这也是敏捷方法的核心。大步跳跃大大地增加了风险,小步前进才可以帮助你很好地把握平衡。
询问用户,哪些是使产品可用且不可缺少的核心功能。不要为所有可能需要的华丽功能而分心,不要沉迷于你的想象,去做那些华而不实的用户界面。
有一堆理由值得你尽快把软件交到用户手中:只要交到用户手中,你就有了收入,这样就有更好的理由继续为产品投资了。从用户那里得到的反馈,会让我们进一步理解什么是用户真正想要的,以及下一步该实现哪些功能。也许你会发现,一些过去认为重要的功能,现在已经不再重要了--------我们都知道市场的变化有多快。尽快发布你的应用,迟了也许它就没有用了。
18.固定的价格就意味着背叛承诺。
固定价格的合同会是敏捷团队的一大难题。我们一直在谈论如何用持续、迭代和增量的方式工作。但现在却有些人跑过来,想提早知道它会花费多少时间以及多少成本。
软件项目天生就是变化无常的,不可重复。如果要提前给出一个固定的价格,就几乎肯定不能遵守开发上的承诺。
一些解决矛盾的建议:
主动提议先构建系统最初的、小的和有用的部分,这时候还不是要完成所有的功能,而是要足够一次交付,并能让用户真正使用。
每一个迭代结束时客户有两个选择:可以选择一系列新的功能,继续进入下一个迭代;或者取消合同。
让团队和客户一起,真正地在当前项目中工作,做具体实际的评估,由客户控制他们要的功能和预算。
五、敏捷反馈
一步行动,胜过千万专家的意见。在敏捷项目中,我们小步前进,不停地收集反馈,时刻矫正自己。实践是绝对必须的,确保你明确知道项目的正确状态,而不是主观臆测。
19.守护天使。
敏捷就是管理变化的,而且,代码可能是变化最频繁的东西。为了应对代码的变化,你需要持续获得代码健康状态的反馈:这时你就需要自动化测试。
只要有了单元测试,就要让它们自动运行。也就是每次编译或者构建代码的时候,就运行一次测试。把单元测试的结果看作是和编译器一样,如果测试没通过,就像编译没通过一样糟糕。这样你就有了一个守护天使。如果出现了问题,你会立刻知道,并且这是最容易修复(也是成本最低)的时候。
好的单元测试能够为你的代码问题提供及时的警报。如果没有到位的单元测试,不要进行任何设计和代码修改。
不是测试越多质量就会越高,测试必须要有效。
20.先用它再实现它
编码之前,先写测试。使用被称为TTD(测试驱动开发)的技术,你总是在有一个失败的单元测试之后才开始编码。先写测试有助于消除过度复杂的设计,让你可以真正专注于需要完成的工作。消除那些还没有编写的类,这会很容易地简化代码。只在有具体理由的时候才开始编码。你可以专注于设计接口,而不会被很多实现的细节干扰。
21.不同环境,就有不同问题
使用自动化会节省时间。使用一个持续集成工具,周期性地从源代码控制系统中取得代码,并运行代码。如果有任何测试失败了,它会通知相关的开发者。通知方式可能是电子邮件、页面、RSS Feed,或者其他一些新颖的方式。
要在多个平台上测试,你只要为每个平台设置持续集成系统就行了。当你或者你同事提交了代码,测试会在每个平台上自动运行。要积极地寻找问题,而不是等问题来找你。
22.自动验收测试。
FIT,即集成测试框架,它很实用;可以更容易地使用HTML表格定义测试用例,并比较测试结果数据。你应该让用户可以在不必学习编码的情况下,根据自己的需要进行添加、更新和修改数据。 为核心的业务逻辑创建测试。让你的客户单独验证这些测试,要让它们像一般的测试一样可以自动运行。
23.度量真实的进度
时间的消逝(通常很快)可以证明:判断工作进度最好是看实际花费的时间而不是估计的时间。不幸的是,几乎所有公司的时间表都是为工资会计准备的,不是用来度量软件项目的开发进度的。
你曾经听到开发人员报告一个任务完成了80%吗?然而过了一天又一天,一周又一周,那个任务仍然是完成了80%?在你真正完成一项任务时,要清楚知道完成这个任务真正花费的时间。奇怪的是,它花费的时间很可能要比最初估计时间长。没有关系,我们希望这能作为下一次的参考。随着时间的推移,你的评估会与事实接近,你也会对任务所花费的时间有更清楚的认识。
如果能一直让下一步工作是可见的,会有助于进度度量。最好的做法就是使用待办事项。待办事项就是等待完成的任务列表。
度量剩下的工作量。不要用不恰当的度量来欺骗自己或团队。要评估那些需要完成的待办事项。关注功能,而不是日程表。
24.倾听用户的声音。
当出了错误,你要尽可能地提供详细信息。黑屏和含义不明的“退出”按钮是很不友好的行为。更糟糕的是,在得到用户反馈的时候,你还嘲笑用户愚蠢,而不去真正地解决问题。
不管它是否产品的bug,还是文档的bug,或者是对用户社区理解的bug,它都是团队的问题,而不是用户的问题。每一个抱怨的背后都隐藏了一个事实。找出真相,修复真正的问题。对客户的那些愚蠢抱怨,你既不会生气,也不会轻视。你会查看一下,找出背后真正的问题。“它就是这样的。”这不是一个好的答案。
25.代码要清晰地表达意图。
开发代码是,应该更注重可读性,而不是只图自己方便。代码阅读的次数要远远超过编写的次数,所以在编写的时候值得花点功夫让它读起来更加简单。实际上,从衡量标准上来看,代码清晰程度的优先级应该排在执行效率之前。
在改动代码修复bug或者添加新功能时,应该有条不紊地进行。首先,应该理解代码做了什么,它是如何做的。接下来,搞清楚将要改变哪些部分,然后着手修改并进行测试。作为一个开发者,应该时常提醒自己是否有办法让写出的代码更容易理解。要编写清晰而不是讨巧的代码。向代码阅读者明确表明你的意图,可读性差的代码一点都不聪明。
PIE原则:代码必须明确说出你的意图,而且必须富有表达力。这样可以让代码更易于被别人阅读和理解。代码不让人疑惑,也就减少了发生潜在错误的可能。一言以蔽之,代码应意图清晰,表达明确。
在编写代码时,应该使用语言特性来提升表现力。使用方法名来传达意向,对方法参数的命名要帮助读者理解背后的想法。异常传达的信息是哪些可能会出问题,以及如何进行防御式编程,要正确地使用和命名异常。好的编码规范可以让代码变得易于理解,同时减少不必要的注释和文档。
26.用代码沟通。
建立代码文档无非两种方式:利用代码本身;利用注释来沟通代码之外的问题。注释可以让其他开发人员快速了解方法的意图、期待结果,以及应该注意之处。但是不要用注释来包裹你的代码。源代码可以被读懂,不是因为其中的注释,而应该是由于它本身优雅而清晰------变量名运用正确、空格使用得当、逻辑分离清晰,以及表达式非常简洁。
如何命名很重要。程序元素的命名是代码读者必读的部分。通过使用细心挑选的名称,可以向阅读者传递大量的意图和信息。反过来讲,使用人造的命名范式(比如现在已经无人问津的匈牙利表示法)会让代码难以阅读和理解。这些范式中包括的底层数据类型信息,会硬编码在变量名和方法名中,形成脆弱、僵硬的代码,并会在将来造成麻烦。
使用细心挑选的名称和清晰的执行路径,代码几乎不需要注释。如何界定一个良好的命名?良好的命名可以向读者传递大量的正确的信息。不好的命名不会传递任何信息,糟糕的命名则会传递错误的信息。尽量避免使用神秘的变量名,但是也不必费尽心思去用繁复冗长的名字来替换大家已习惯的名称。
对于显而易见的代码增加注释,最好的状况不过是为代码添加了“噪音”。最坏的状况下,随着时间推进,这些注释会过时。许多注释没哟传递任何有意义的信息,只会分散注意力,而且容易失去时效性。
注释可用来为读者指定一条正确的代码访问路线图。为代码中的每个类或模块添加一个短小的描述,说明其目的以及是否有任何特别需求。对于类中的每个方法,可能要说明下列信息。
感谢如RDoc、javadoc和ndoc这样的工具,使用它们可以很方便地直接从代码注释创建有用的、格式优美的文档。这些工具抽取注释,并生成样式漂亮且呆有超链接的HTML输出。代码被阅读的次数要远超过被编写的次数,所以在编程时多付出一点努力来做好文档,会让你在将来受益匪浅。
用注释沟通。使用细心选择的、有意义的命名。用注释描述代码意图和约束。注释不能替代优秀的代码。解释代码做了什么的注释用处不那么大。相反,注释要说明为什么会这样写代码。在代码可以传递意图的地方不要使用注释。
27、动态评估取舍。
对任何单个因素如此独断地强调,而不考虑它是否是项目成功的必要因素,必然导致灾难的发生。强调性能的重要性情有可原,因为恶劣的性能表现会让一个应用在市场上铩羽而归。然而,如果应用的性能已经足够好了,还有必要继续投入精力让其运行得更加快一点吗?大概不用了吧。一个应用还有很多其他方面的因素同样重要。与其花费时间去提升千分之一的性能表现,也许减少开发投入,降低成本,并尽快让应用程序上市销售更有价值。总而言之,要想让应用成功,降低开发成本与缩短上市时间,二者的影响同样重要。由于计算机硬件价格日益便宜,处理速度日益加快,所以可在硬件上多投入以换取性能的提升,并将节省下来的时间放在应用的其他方面。
但是谁来最终判定性能表现已经足够好,或是应用的展现已经足够“炫”了呢?客户或是利益相关者必须进行评估,并做出相关决定。没有适宜所有状况的最佳解决方案。你必须对受伤的问题进行评估,并选出最合适的解决方案。每个设计都是针对特定问题的-------只有明确地进行评估和权衡,才能得出更好的解决方案。
动态评估权衡。考虑性能、便利性、生产力、成本和上市时间。如果性能表现足够了,就将注意力放在其他因素上。不要为了感觉上的性能提升或者设计的优雅,而将设计复杂化。如果现在投入额外的资源和精力,是为了将来可能得到的好处,要确认投入一定要得到回报(大部分情况下,是不会有回报的)。
28、增量式编程。
增量式编程可以精炼并结构化你的代码。代码被复杂化、变成一团乱麻的几率减少了。所开发的代码基于即时的反馈,这些反馈来自以小步幅方式编写代码和测试的过程。你会倾向于创建更小的方法和更具内聚性的类。你不是在盲目地一次性编写一大堆代码。相反,你会经常评估代码质量,并不时地进行许多小调整,而不是一次修改许多东西。编写代码的时候,经常留心可以改进的微小方面。这可能会改善代码的可读性。也许你会发现可以把一个方法拆成几个更小的方法,使其变得更易于测试。可以使用测试优先开发方式,作为强制进行增量式编程的方式。关键在于持续做一些细小而有用的事情,而不是做一段长时间的编程或者重构。
在很短的编辑、构建、测试循环中编写代码。这要比花费长时间仅仅做编写代码的工作好得多。可以创建更加清晰、简单、易于维护的代码。
29.保持简单。
优雅的代码第一眼看上去,就知道它的用处,而且很简洁。评价设计质量的最佳方式之一,就是听从直觉。直觉不是魔术,它是经验和技能的厚积薄发之产物。在查看一个设计时,听从头脑中的声音。如果觉得有什么地方不对,那就好好想想,是哪里出了问题。一个好的设计会让人觉得很舒服。当你觉得所编写的代码中没有一行是多余的,并且仍能交付全部的功能时,这种感觉就对了。这样的代码容易理解和改正。
开发可以工作的、最简单的解决方案。除非有不可辩驳的原因,否则不要使用模式、原则和高难度技术之类的东西。
30.编写内聚的代码。
内聚性用来评估一个组件(包、模块或配件)中成员的功能相关性。内聚程度高,表明各个成员共同完成了一个功能特性或一组功能特性。内聚程度低的话,表明各个成员提供的功能是互不相干的。
在决定创建一个类时,问问自己,这个类的功能是不是与组件中其他某个类的功能类似,而且功能紧密相关。这就是组件级的内聚性。类也要遵循内聚性。如果一个类的方法和属性共同完成了一个功能(或是一系列紧密相关的功能),这个类就是内聚的。感觉类和组件的功能都很集中:每个类或组件只做一件事,而且做得很好。bug很容易跟踪,代码也易于修改,因为类和组件的责任都很清晰。
根据单一职责原则,一个模块应该只有一个发生变化的原因。
让类的功能尽量集中,让组件尽量小。要避免创建很大的类或组件,也不要创建无所不包的大杂烩类。
31.告知,不要询问。
面向过程的代码取得信息,然后做出决策。面向对象的代码则让别的对象去做事情。作为某段代码的调用者,开发人员绝对不应该基于被调用对象的状态来做出任何决策,更不能去改变该对象的状态。这样的逻辑应该是被调用对象的责任,而不是你的。在该对象之外替它做决策,就违反了它的封装原则,而且为bug提供了滋生的土壤。
将命令与查询分离开来。就是将功能和方法分为“命令”和"查询"两类,并在源码中记录下来(这样做可以帮助将所有的“命令”代码放在一起,并将所有的“查询”代码放在一起)。一个常规的“命令”可能会改变对象的状态,而且有可能返回一些有用的值,以方便使用。一个“查询”仅仅提供给开发人员对象的状态,并不会对其外部的可见状态进行修改。从外部将“查询”和“命令”隔离,让开发者有机会询问自己为什么要暴露某些特定的数据。
告知,不要询问。不要抢别的对象或是组件的工作。告诉它做什么,然后盯着你自己的职责就好了。
32.根据契约进行替换。
保持系统灵活性的关键方式,是当新代码取代原有代码之后,其他已有的代码不会意识到任何差别。Liskov替换原则告诉我们:任何继承后得到的派生类对象,必须可以替换任何被使用的基类对象,而且使用者不必知道任何差异。换句话说,某段代码如果使用了基类中的方法,就必须能够使用派生类的对象,并且自己不必进行任何修改。相对基类的对应方法,派生类应该不要求更多,不承诺更少;要可以进行自由的替换。
当使用继承是,要想想派生类是否可以替换基类。如果答案是不能,就要问问自己为什么要使用继承。如果答案是希望在编写新类的时候,还要重用基类中的代码,也许要考虑转而使用聚合。聚合是指在一个类中包含一个对象,并且该对象是其他类的实例。开发人员将责任委托给所包含的对象来完成(该技术同样被称为委托)。
那么继承和委托分别在什么时候使用呢?
通过替换代码来扩展系统。通过替换遵循接口契约的类,来添加并改进功能特性,要多使用委托而不是继承。
七、敏捷调试。
你也许会对木匠那毫无差错的工作印象深刻,但我向你保证,事实不是这样。真正的高手只是知道如何亡羊补牢。----------Jeff Miller。
33.记录问题解决日志。
面对问题并解决它们是开发人员的一种生活方式。维护一个保存曾遇到的问题以及对应解决方案的日志,称之为每日日志。可以选择符合需求的任何格式。下面这些条目可能会用的上:
要共享日志给其他人,而不仅仅是靠一个人维护。可以创建一个Wiki,并鼓励其他开发人员使用和更新其内容。
维护一个问题及其解决方案的日志。保留解决方案是修复问题过程的一部分,以后发生相同或类似问题时,就可以很快找到并使用了。
34.警告就是错误。
要找到一种方式让编译器将警告作为错误提示出来。如果编译器允许调整警告的报告级别,那就把级别调到最高,让任何警告不能被忽略。
将警告视为错误,签入带有警告的代码,就跟签入有错误或没有通过测试的代码一样,都是极差的做法。签入构建工具中的代码不应该产生任何警告信息。
由于编译器的bug或是第三方工具或代码的原因,有些警告无法消除。如果确实没有应对之策的话,就不要再浪费更多时间了。但是类似的状况很少发生。
35.对问题各个击破。
对问题各个击破,这样做有很多好处;通过将问题与应用其他部分隔离开来,可以将关注点直接放在与问题相关的议题上;可以通过多种改变,来接近问题发生的核心-----你不可能针对正在运行的系统来这样做。可以更快地发现问题的根源所在,因为只与所需最小数量的相关代码发生关系。
对问题各个击破。在解决问题时,要将问题域与其周边隔离开,特别是在大型应用中。
36.报告所有的异常。
从事任何编程工作,都要考虑事物正常状况下是如何运作的。不过更应该想一想,当出现问题-------也就是事情没有按计划进行时,会发生什么。
处理或是向上传播所有的异常。不要将它们压制不管,就算是临时这样做也不行。在写代码时要估计到会发生的问题。
37.提供有用的错误信息。
当应用发布并在真实世界中得到使用之后,仍然会发生这样那样的问题。针对这个问题,常用的解决方案是记录日志:当发生问题时,让应用详细记录错误的相关数据。错误日志最起码应该以文本文件的形式维护。不过也许可以发布到一个系统级别的事件日志中,可以使用RSS Feed等工具来浏览日志。
一方面要提供给用户清晰、易于理解的问题描述和解释,使他们有可能寻求变通之法。另一方面,还要提供具备关于错误的详细技术细节给用户,这样方便开发人员寻找代码中真正的问题所在。
展示有用的错误信息。提供更易于查找错误细节的方式。发生问题时,要展示出尽量多的支持细节,不过别让用户陷入其中。
区分错误类型:
程序缺陷。这些是真正的bug,用户或系统管理员对此束手无策。
环境问题。包括数据库链接失败,或无法链接远程Web Service、磁盘空间满、权限不足,以及类似的问题。程序员对此没有应对之策,但是用户也许可以找到变通的方法,如果提供足够详细的信息,系统管理员应该可以解决这些问题。
用户错误。程序员与系统管理员不必担心这些问题。在告知是哪里操作的问题后,用户可以重新来过。
八、敏捷协作。
我不仅发挥了自己的全部能力,还将我所仰仗的人的能力发挥到极致。 ---------伍德罗.威尔逊,美国第28任总统(1856----1924)
38.定期安排会面时间。
也许你个人很讨厌开会,但是沟通是项目成功的关键。我们不只要跟客户谈话,还应该与开发人员进行良好的沟通。
立会是将团队召集在一起,并让每个人了解当下进展状况的好办法。顾名思义,参与者们不允许在立会中就坐,这可以保证会议快速进行。要保证会议不会发散,每个人都应该只回答下述三个问题:
通常,立会都是在每个工作日的早些时候,且大家都在上班时举行。但是不要把它安排为上班后的第一件事。要让大家有机会从刚才混乱的交通状况中恢复状态,喝点咖啡,删除一些垃圾邮件什么的。要保证会议结束后有足够的时间,让大家在午餐之前做不少工作,同时也不要开始得过早,让每个人都巴不得赶紧结束会议,去喝点东西。一般来说,在大家到公司之后的半个小时到一个小时之内举行,是个不错的选择。
每日立会有诸多好处:
使用立会。立会可以让团队达成共识。保证会议短小精悍不跑题。
39.架构师必须写代码。
You can't code in PowerPoint . 你不可能在PPT中进行编程。
许多架构师通常在项目开始时介入,绘制各种各样的设计图,然后在重要的代码实现开始之前离开。由于得不到反馈,他们的架构设计工作也不会有很好的收效。一个设计要解决的是眼前的面临的特定问题,随着设计的实现,对问题的理解也会发生改变。最为设计人员,如果不能理解系统的具体细节,就不可能做出有效的设计。只通过一些高度概括的、粗略的设计图是无法很好地理解系统。
好的设计者必须能够卷起袖子,加入开发队伍,毫不犹豫地参与实际编程。真正的架构师,如果不允许参与编码的话,他们会提出强烈的抗议。应该根据设计开发出原型,经过测试,当然还有验证----它是要演化的。实现可用的设计,这是设计者或说架构师的责任。
要鼓励程序员参与设计。主力程序员应该试着担任架构师的角色,而且可以从事多种不同的角色。他会负责解决设计上的问题,同时也不会放弃编码的工作。如果开发人员不愿意承担设计的责任,要给他们配备一个有良好设计能力的人。程序员在拒绝设计的同时,也就放弃了思考。
优秀的设计从积极的程序员那里开始演化。积极的编程可以带来深入的理解。不要使用不愿意编程的架构师------不知道系统的真实情况,是无法展开设计的。
架构、设计、编码和测试,这些工作给人的感觉就像是同一个活动-----开发的不同方面。感觉它们彼此之间应该是不可分割的。
如果有一位首席架构师,他可能没有足够的时间来参与编码工作。还是要让他参与,但是别让他开发在项目关键路径上的、工作量最大的代码。
40.实行代码集体所有制
任何具备一定规模的应用,都需要多人协作进行开发。在这种状况下,不应该像国家宣称对领土的所有权一样,声明个人对代码的所有权。任何一位团队成员,只要理解某段代码的来龙去脉,就应该可以对其进行处理。如果某一段代码只有一位开发人员能够处理,项目的风险无形中也就增加了。
相比找出谁的主意最好、谁的的代码实现很烂而言,解决问题,并让应用满足用户的期望要更为重要。
当多人同时开发时,代码会被频繁地检查、重构以及维护。如果需要修复bug,任何一名开发人员都可以完成这项工作。同时有两个或两个以上的人,可以处理应用中不同部分的代码,可以让项目的日程安排也变得更为容易。
在团队中实行任务轮换制,让每个成员都可以接触到不同部分的代码,可以提升团队整体的知识和专业技能。当Joe接过Sally的代码,他可以对其进行重构,消除待处理的问题。在试图理解代码的时候,他会问些有用的问题,尽早开始对问题领域的深入理解。
另一方面,知道别人将会接过自己的代码,就意味着自己要更守规矩。当知道别人在注意时,一定会更加小心。
可能会有人会说,如果一个开发者专门应对某一个领域中的任务,他就可以精通该领域,并让后续的开发任务更加高效。这没错,但是眼光放长远一点,有好几双眼睛盯着某一段代码,是一定可以带来好处的。这样可以提升代码的整体质量,使其易于维护和理解,并降低出错率。
要强调代码的集体所有制。让开发人员轮换完成系统不同领域中不同模块的不同任务。
不要无意间丧失了团队的专家技能。如果某个开发人员在某个领域中极其精通,不妨让他作为这方面的驻留专家,而且系统的其他部分代码也对他开放,这样对团队和项目都很有帮助。
在大型项目中,如果每个人都可以随意改变任何代码,一定会把项目弄得一团糟。代码集体所有制并不意味着可以随心所欲、到处破坏。
开发人员不必了解项目每一部分的每个细节,但是也不能因为要处理某个模块的代码而感到惊恐。
有些场合是不能采用代码集体所有制的,也许代码需要某些特定的知识、对特定问题的了解,比如一个高难度的实时控制系统。这些时候,人多了反而容易误事。
任何人都可能遭遇到诸如车祸等突发的灾难事故,或者可能被竞争对手雇佣。如果不向整个团队分享知识,反而增加了丧失知识的风险。
41.成为指导者。
Knowledge grows when given!与团队其他人一起共事是很好的学习机会。知识有一些很独特的属性;假设你给别人钱的话,最后你钱会变少,而他们的财富会增多。但如果是去教育别人,那双方都可以得到更多的知识。通过详细解释自己知道的东西,可以使自己的理解更深入。当别人提出问题时,也可以发现不同的角度。也许可以发现一些新技巧-------听到一个声音这样告诉自己:“我以前还没有这样思考过这个问题。”
多数时候,成为指导者,是指在帮助团队成员提升水平的同时也提高自己。这个过程不必局限于自己的团队。可以开设个人博客,贴一些代码和技术在上面。不一定是多么伟大的项目,即使是一小段代码和解释,对别人也可能是有帮助的。成为指导者意味着要分享----而不是固守------自己的知识、经验和体会。
成为指导者。分享自己的知识很有趣--------付出的同时便有收获。还可以激励别人获得更好的成果,而且提升了整个团队的实力。
42.允许大家自己想办法
“授人以鱼,三餐之需;授人以渔,终生之用。”告诉团队成员解决问题的方法,也要让他们指导如何解决问题的思路,这也是成为指导者的一部分。
给别人解决问题的机会。指给他们正确的方向,而不是直接提供解决方案。每个人都能从中学到不少东西。
用问题来回答问题,可以引导提问的人走上正确的道路。
43.准备好后再共享代码。
完成一项任务后,应该马上提交代码,不应该让代码在开发机器上多停留一分钟。如果代码不能被别人集成使用,那又有什么用处呢?应该赶紧发布出去,并开始收集反馈。
通常情况下,提交的文件应该与一个特定的任务或是一个bug的解决相关。而且应该是同时提交相关的文件,并注有日志信息,将来也能够知道修改了哪些地方,以及为什么要做修改。一旦需要对变更采取回滚操作,这种“原子”提交也是有帮助的。 要保证在提交代码之前,所有的单元测试都是可以通过的。
代码不执行提交操作的其他安全选择:1.使用远程访问。 2.随身携带。将代码复制到U盘、CD或DVD中。3、使用带有底座扩展的笔记本电脑。4、使用源代码控制系统的特性。在CVS和Subversion中,可以将尚未允许合并到主干的代码,设定为开发者的分支。
准备好后在共享代码。绝不要提交尚未完成的代码。故意签入编译未通过或是没有单元测试的代码,对项目来说,应被视作玩忽职守的犯罪行为。
44.做代码复查。
如何进行代码复查:1.通宵复查,每个月进行一次恐怖的代码复查之夜。不建议这方式。 2.捡拾游戏。代码完成编译、测试,提交之前由其他开发人员“捡拾”起这些代码开始复查。并且最好进行轮换复查。3.结对编程。
代码复查的一些基本问题检查列表:
还可考虑使用诸如Similarity Analyzer或Jester这样代码分析工具。
复查所有的代码。对于提升代码质量和降低错误率来说,代码复查是无价之宝。如果以正确的方式进行,复查可以产生非常使用而高效的成果。要让不同的开发人员在每个任务完成后复查代码。
代码复查需要积极评估代码的设计和清晰程度,而不只是考量变量名和代码格式是否符合组织的标准。
同样的功能,不同开发人员的代码实现可能不同。差异并不意味着不好。除非你可以让某段代码明确变得更好,否则不要随意批评别人的代码。
45.及时通报进展与问题。
接受一个任务,也就意味着做出了要准时交付的承诺。不过,遇到各种问题从而导致延迟,这种情形并不少见。截止日期来临,大家都等着你在演示会议上展示工作成果。如果你到会后通知大家工作还没有完成,会有什么后果?除了感到窘迫,这对你的事业发展也没有什么好处。
如果等到截止时间才发布坏消息,就等于是为经理和技术主管提供了对你进行微观管理的机会。他们会担心你再次让他们失望,并开始每天多次检查你的工作进度。你的生活就开始变得像呆伯特的漫画一样了。
及时通报进展与问题,有情况发生时,就不会让别人感到突然,而且他们也很愿意了解目前的进展状况。他们会知道何时应提供帮助,而且你也获得了他们的信任。
发送电子邮件,用即时贴传递信息,或快速电话通知,这都是通报大家的传统方式。还可以使用Alistair Cockburn提出的“信息辐射器”。信息辐射器类似与墙上的海报,提供变更的信息,以推送的方式传递信息,他们就不必再来问问题了。信息辐射器中可以展示目前的任务进度,和团队、管理层或客户可能会感兴趣的其他内容。
及时通报进展与问题。发布进展状况、新的想法和目前正在关注的主题。不要等着别人来问项目状态如何。
每日立会可以让每个人都能明确了解最新的进展和形势。
别花费太多时间在进展与问题通报上面,还是应该保证开发任务的顺利完成。
经常抬头看看四周,而不是只埋头于自己的工作。
终于读完了这本书,本篇读书笔记摘录到此结束~~~~