读书笔记之《高效程序员的45个习惯----敏捷开发之道》 摘录

 读书笔记之《高效程序员的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替换原则告诉我们:任何继承后得到的派生类对象,必须可以替换任何被使用的基类对象,而且使用者不必知道任何差异。换句话说,某段代码如果使用了基类中的方法,就必须能够使用派生类的对象,并且自己不必进行任何修改。相对基类的对应方法,派生类应该不要求更多,不承诺更少;要可以进行自由的替换。

       当使用继承是,要想想派生类是否可以替换基类。如果答案是不能,就要问问自己为什么要使用继承。如果答案是希望在编写新类的时候,还要重用基类中的代码,也许要考虑转而使用聚合。聚合是指在一个类中包含一个对象,并且该对象是其他类的实例。开发人员将责任委托给所包含的对象来完成(该技术同样被称为委托)。

       那么继承和委托分别在什么时候使用呢?

  •  如果新类可以替换已有的类,并且它们之间的关系可以通过is-a来描述,就要使用继承。
  • 如果新类只是使用已有的类,并且两者之间的关系可以描述为has-a或uses-a,就使用委托吧。

       通过替换代码来扩展系统。通过替换遵循接口契约的类,来添加并改进功能特性,要多使用委托而不是继承。  

七、敏捷调试。

        你也许会对木匠那毫无差错的工作印象深刻,但我向你保证,事实不是这样。真正的高手只是知道如何亡羊补牢。----------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提出的“信息辐射器”。信息辐射器类似与墙上的海报,提供变更的信息,以推送的方式传递信息,他们就不必再来问问题了。信息辐射器中可以展示目前的任务进度,和团队、管理层或客户可能会感兴趣的其他内容。

   及时通报进展与问题。发布进展状况、新的想法和目前正在关注的主题。不要等着别人来问项目状态如何。

   每日立会可以让每个人都能明确了解最新的进展和形势。

   别花费太多时间在进展与问题通报上面,还是应该保证开发任务的顺利完成。

   经常抬头看看四周,而不是只埋头于自己的工作。


     终于读完了这本书,本篇读书笔记摘录到此结束~~~~

猜你喜欢

转载自blog.csdn.net/eric_XJJ/article/details/8627892