读不完《程序员修炼之道》,至少可以读完这70条

文章目录


在这里插入图片描述

推荐一、领悟程序员的哲学

  • 在大学的时候,编程是我的兴趣,也是当时我给自己定位的职业方向。
  • 当我在图书馆看到这本《程序员修炼之道》的时候,直觉告诉我应该看看这本书,或许对我的成长有帮助。读完之后更加肯定了自己的直觉是对的。当时我虽然没有实际项目的开发经验,不能一时领悟其意,但我明白,这本书中总结的原则和方法对我来说是极为宝贵的,于是买了一本放在床头。
  • 参加工作后,随着编程经验的积累,我越来越能体会到这本书中的观点。每次重读书中的章节,我都会有新的收获;再结合自己的每次经历,都能与之共鸣——这是对我影响最深的一本书,也是我向朋友和同事推荐次数最多的一本书。有趣的是,书前Kevin Ruland的评论说:这是我唯一不会出借的一本书。究竟是一本什么样的书会让大师如此爱不释手?
  • 这本书所涉及的内容很广,涵盖了程序员成长过程中和软件开发过程中要注意的地方。从程序员的个体哲学到编码过程中的各个环节,再到团队的项目管理;从程序员要如何扩充知识,如何思考问题,如何利用有效的工具打造个人的工作环境,到项目启动之前如何建立一些基本准则,如何分析、设计、编写、测试、重构,如何实现自动化,甚至是项目团队中提高实效的原则。书中的内容全都来自经验的总结,倡导编程中正确的观念和良好的习惯,而这正是优秀的程序员必须拥有的良好素质。
  • 书中讲述的原则源于实践,高于实践,它们蕴涵着前辈们的智慧。随着知识的扩展、编程体验的增加,对这本书中的内容的理解也会愈加深刻。反过来,对前辈菁华的吸收,有助于我们提高编程水平,开发出更好的产品。
  • 我深信这不是一本只要读一遍的书。 这些原则看似简单,但细细品味一番,却是大哲大道,环环相扣,要理解透彻并不容易。例如,提示44告诉我们“不要靠巧合编程”,这道理看起来好像很简单,但我发现实际工作中还是很容易就犯这个错的。细想一下Bug列表中的问题,其中大多数问题不正是由于作了不正确的假设,或者是想当然造成的吗?要是一开始就有了深思熟虑,经过了合理的设计,完整有效地进行了测试,应该大部分都可以避免吧。而思考、设计、测试又紧扣书中其他章节。
  • 曾经和朋友讨论关于员工培训的事。如果给程序员做培训,我首选的材料就是这本《程序员修炼之道》。

▶LAMP程序员 赵钟秋(belltoy)

推荐二、再次阅读,感受颇多

  • 记得四年前刚开始工作时从公司拿到的第一本书,就是这本《程序员修炼之道》(英文版),作为新入职员工study group的学习材料,当时在senior engineer带领下和其他同事一起学习了这本书。虽然之前就听说这是一本好书,当时看的时候也只是觉得讲的都有道理,但这些是很自然的啊,干嘛花这么大的篇幅说来说去?所以只是囫囵吞枣地翻过也就扔在一边了。
  • 之后也看过很多类似的书籍,《程序员修炼之道》也一直是公司新人的必备学习材料,而我却一直没再重拾这本书仔细读一遍,直到最近周筠老师发给我中文电子版,才又从书架上翻出当年的英文版,对照着中文电子版仔细读了一遍。
  • 此次重读,感受颇多,也颇能理解为何公司一直选用此书作为新人教材。
  • 这本书里虽只包含了很多看似粗浅朴素的道理,实则是若干经验的心血总结。 比如谁都知道不要对自己家的破窗户置之不理,可实际中听到太多的妥协:这个代码已经这样了,只能继续在上面贴上丑陋的workaround,这其实是一种对责任的推卸和对未来的不负责。当然现实是不完美的,有时救火队员也不得不放下破窗户而迁就其他,但作为一个pragmatic程序员,保持追求完美的心态还是很有必要的,正因为这个心态,我们才会去追求代码的优美、设计、实现的正交、DRY(Don’t Repeat Yourself)原则……
  • 关于DRY,我想说,不但don’t repeat yourself,也don’t repeat others,我们看到太多重复造轮子的故事,正如书中提到“鞋匠的孩子没鞋穿”,作为一个pragmatic程序员,合理地使用工具、库,以及自己积累的开发的轮子,会让自己的productivity不断提升。这让我想起公司里一个让人崇拜的“牛人”,大家一直想把产品进程内cache做成多进程共享,正在大家讨论该怎么做的时候,“牛人”用短短几天时间已经完成了,众人再次对他又崇拜了一把。“牛人”其实是备有很多现成代码的,完成这个功能只是把之前积累的封装良好的模块重用就可以了。
  • 书中推崇的另外一个方法:曳光弹。自己之前用prototype,一直犹豫于代码是否需要重用。其实原则上prototype的代码应该是抛弃型的,但有时候前期做的一些工作是为了确定方案、构建框架,而这些也是作为后期工作的基础。事实上,在项目前期值得仔细考虑的究竟是采用prototype还是曳光弹,取决于它们的适用场景(对于产品开发,曳光弹的应用场景可能相对会更多一些)。
  • 当然,对于书中提到的对知识资产的管理(知识投资)、沟通和交流的重要性等,我想这就不单单对于程序员适用了,任何一个要想有所作为的人,这些方面的重要性都毋庸多说了。而对于自动化和文本处理等方面的经验,也是很多书中都提到的经验之谈(《UNIX编程艺术》、《卓有成效的程序员》等)。
  • 最后,说一下这本书的译者马维达,我最早是在学校时读过他翻译的ACE文档及相关资料,收益颇多,ACE可谓网络编程技术的集大成者,而这本《程序员修炼之道》则可谓编程的集大成者,从项目管理、软件架构和设计、代码编写和测试,各方面在此书中都有精到的阐述。此书的翻译质量应该说比较准确,基本真实地表达了原书的意思,但正因直译,有些语句可能在理解上会有一些难度,比如P146,“只要对于那些被耦合在一起的模块而言,这是众所周知的和可以接受的,你的设计就没有问题。”不过细读这本书,这些有所晦涩的内容还是能理解的。当然,译者还是可以适当加些“译注”,让读者更容易理解,内容更顺畅的,比如书中直接用古鲁来翻译Guru,如果加上解释可能会更好;又比如Law of Demeter,原书没有解释得太清楚,如果多加些解释可能会更便于理解。
  • 感谢周筠老师让我有机会重温这本优秀的书籍,为了完成作业,也为了让自己的认识提升。

▶ 趋势科技stuff engineer邹飞

推荐三、一切阅读都是误读

一切阅读都是误读

——安伯托·艾柯

  • 上次读这本书已经是五年前的事了,中文版刚出版我就买了一本。那时候,我的工作相对比较清闲,有大量的时间阅读。恰巧我在负责公司的校园招聘及新员工培训,非常需要一些不错的教材,更早的时候听说过这本书的英文版,但是没能一读,中文版自是不能放过。另外,那年我在写书,记录一些程序员生涯中的心得,对经验的总结都颇有兴趣。

  • 爱不释手,是我第一次读完后的心境。 完整经历了人生中第一个成功的大的软件项目后,我有许多感慨。知道了不少东西怎样做对,怎样做不对,但是要一条条写下来,却不知道怎么总结。这本书说出了许多我想说的,但却不知道该怎么说的道理。

  • 接下来的日子,我在公司做过好几次技术培训,课题都是以这本书中的某个或某几个观点,再结合自己的经历展开的。对于信任我的同学,我总是将它作为第一本列在给他们开的书单中。

  • 后来,国内又引进了几本类似的好书。比如《代码大全》、《UNIX编程艺术》。古人云,读书有三上,马上、枕上、厕上。我还真把书买了好几本,分别置于床头、办公桌上,方便睡前、如厕时阅读;手机里放入电子版,上下班路上,偶尔翻阅。这些书的确是值得逐章挑选出来,反复精读的。《程序员修炼之道》却于几年前推荐给新入职的同事,从我的视野里消失了。

  • 这几天,同事把书还了我,加上周筠老师发给我电子版,我又重读了一遍。原以为那些嚼烂了的东西,不会再有新味道,但是我错了。

  • 不同的人从不同的角度用不同的方式,阐述相同的道理。其中细微的差异,是需要读者有了许多许多的经历后,才能体会的。比如,在《程序员修炼之道》中花了六页分析DRY-Don’tRepeatYourself原则;而在《UNIX编程艺术》中把它称作SPOT-Single Point of Truth,大约用了一页半的篇幅。他们真是想表达完全一致的理念吗?我看未必。所以,作为读者,同样会有许许多多的想法。随着编程经历越来越多,思考次数的增加,重新和这些前辈的思想相印证,也是一件乐事。

  • 我们以为理解了作者,其实是误解。但我们将再一次理解编程。

▶ 网易互动娱乐有限公司 杭州研究中心总监 云风

推荐四、程序员升级必备

  • 学过高中物理的人,应该会记得,原子中的电子获得能量之后,会发生能级跃迁,到达更高的能量状态。其实任何工种都是一样的,要跳出自己的水平,到达更高的级别,不是件容易的事。这个跳跃过程总需要一些东西的辅助。诚然,如果要成为一个好人,那么只要做好在幼儿园中学到的一切就足够。如果要成为一个好程序员,其实所需要的道理也多不了多少,只不过,当水平不够的时候,永远不能认识到那些朴素道理的重要。 而当水平达到的时候,这些道理自然会明白。所以一本帮助程序员进阶的书,很容易落到低手觉得是废话,高手也觉得是废话的悲惨境地。
  • 好几年前,有人向我推荐过这本《程序员修炼之道》,甚至专门买了一本送到我家。而当年的我,不知道是由于无知、自负、浮躁,或是其他,只草草翻了一下,就下了个“烂书”的定义,扔在书架一角。后来有朋友在我书架上发现,如获至宝,说已经买不到了。我当然乐得送了人情。在我心目中,最好的入门书永远是《代码大全》,那也是对我影响最深的一部书。
  • 几年后,再来谈这本书,发现很多人的评价比我高得多,自知不妙,赶紧找来重读,才知道错过了什么。在一个滥俗的译名之下,在一个看起来不知所云的目录之后,在一些读起来拗口的句子之中,隐藏的竟然是相当伟大的思想——朴素而真挚,简单而有效。这时候我突然明白,这是一本不逊于《代码大全》的伟大著作,后者一直被我誉为“新手圣经”。
  • 经验这个东西,往往并不能告诉我们什么一定对,但是可以告诉我们什么一定不对。这本书完全是经验凝成,没有大道理,没有新观念。这些朴素的道理就是创造一个合格软件和作一个好程序员所必须了解的。比如“提示44不要靠巧合编程”,这句话表达的意思是“不要预设立场”。听起来简单,但是只要随手翻翻你最新写过的一段程序,通常都会发现代码中做了大量的“假设”。书中用一道习题,假设了用户使用命令行环境,假设用户懂英语……都可能导致问题。怕了吧?幸好还有“提示30你不可能写出完美的软件”,这可不是帮你开脱责任,而是在讲如何控制需求,这正是能顺利完成一个项目的根本前提,可惜事实上往往到了项目失败的时候,人们才想起来需求出了问题。
  • 这本书涉猎的范围相当广,如何设计架构,如何思考问题,如何测试,如何编码,如何处理文档……如果细心琢磨,构建软件的所有主干和细微枝节都有所涉及。和很多人的看法不同,我不认为这是一本可以轻松读完的书。一方面,这本书涉及的内容太多,虽然已经尽量讲述,但所有话题都可以继续引申出无限的内容;如果用心,还可以配合附录中所提到的各种论文和资源继续学习。习题也要仔细思考。这绝不是一本小说。另一方面,作者用了大量的隐喻,导致读起来有一定难度。开始我认为是翻译质量有问题,不过慢慢发现美国的读者读起来也未必容易。原因还是涉及的范围过大。我特意模仿这种风格写了本文的第一段,虽然是中文,可读起来也不容易。
  • 可能以上的两点会阻挡一部分人阅读这本书,因我也是曾经受阻的人之一。不过,好书并不会随着时间的推移和平台的变化而消亡,好书只会成为经典。无论是《人月神话》,还是《代码大全》,都在时间的长河中沉淀下来,传颂至今。这本书,虽然也只有10年历史,不过现在再来翻看,不仅毫不落伍,甚至感觉穿透了时间,看到了这些年中不少自己犯过的错误,我相信这也是一本能经得起时间沉淀的书,只不过需要多点耐心。 因此,我郑重地写下这篇书评,希望能读到这本书的人再多一点耐心,越过语言的障碍,直入本质,直至跃向更高级别。这个希望,不仅是对新手所说,其实也包括我自己。如本书开头所说:注重实效的程序员应该不断学习。 我们都应该不断地学习下去。

▶银杏科技创始人 霍炬

推荐五、程序员心底的小声音

  • 编程大约有三个境界,新手、高手和高不成低不就的中手。这三个境界,大致和王国维先生划定的做学问的三个境界一一对应。一般来说,如果不经过几十万行的代码的锤炼(衣带渐宽终不悔,为伊消得人憔悴),或者长期在一个高手团队里面打磨切磋,那么无论怎么样的理论熟悉,打字熟练,考试全A,编程起来,都应该算是中手。一个中手如果机缘很好,得到高人亲自指点,则能很快成长为高手;如果没有这样的机缘,那就要在“众里寻她千百度”这个层次苦苦地求索锤炼很久,才能“蓦然回首”。
  • 读书是一种很好弥补没有高手在场的方法,因为书是最好的老师。可现实是,高手写给中手的书很少。在任何行业,适合新手入门的书很多,适合中手的书就很少。原因有两个,一来高手极少愿意耐心指点成长秘诀,即使写了,也是蜻蜓点水,因为这些经验啊结论啊,都被他们本身提炼成了珠玑,他们觉得最重要的也就是那么寥寥几句,也没有太多的废话好写。而读者如果没有类似的经历,看到这些珠玑,也只是觉得把玩颇为有趣而已,极少能有同感。鲜有高手,能把技术书写成散文集,如Brooks一样,在《人月神话》中把经验教训和经历背景等一一道来,并且从这些经历中抽出一般性的知识。因此,高手的风格一般是浮光掠影地概括自己领会的几个原则和教训。这些寥寥数语的珠玑,对其他高手来说一看就懂,但是对于中手来说就很难理解了。所以很多高手写出来的给中手看的书就曲高和寡。二来,中手其实水平差异巨大,偏好也各不一样,有的或许根本认识不到自己应该走的成长轨迹,有的认为这些书籍是片面知识,所以把不喜欢的书都扔给到垃圾堆了,光捡自己喜欢的书看;有的未必看得上高手的经验,认为高手说的那些自己也早已领悟到。因此,也不喜欢购买这些书籍。由于这两个原因,造成了高手提携中手的书在市场上很少见到。
  • 不过这样的书倒不是没有,比方说在编程领域,我至少可以推荐这四本书——《PragmaticProgrammer》、《The Art of UNIX Programming》、《Elements of Programming Style》和《The Productive Programmer》,它们都是高手所写,属于高手指导中手的典范。第二本和第三本我以前介绍过,第四本余晟同学的书评也比我写的好几百倍,所以我就以《PragmaticProgrammer》为例说说这个问题吧。
  • 我们前面说了,对于中手,特别是在“寻她千百度”这个层次的中手来说,或许本身已经捡到了一些珠玑,或许对于像《Pragmatic Programmer》里面说的那些Tip,有的是深有同感的。比如DRY(Don’t Repeat Yourself不要重复你自己),基本上大家都知道,可是在实际中(至少我自己)还是不停地一次一次地犯错误,做事情也不符合DRY原则(一次一次犯错误本身也是一个DRY错误,因为DRY原则要求你对每种错误只能犯一次)。我们读的时候深有同感,可写代码的时候却忘到Java国去了,这还真不是个案,是非常普遍的现象。
  • 能不能让正确的原则指导正确的行动本身,其实就是区分是否是高手的一个显著标志。试想,两个都了解KISS原则的程序员在一起写代码,高手的代码必然会自然流露出KISS的优雅,而中手或许需要旁人的提醒和多次重构,才能达到理想的状态。出现这个问题的原因很明显——中手没有完全内化KISS原则,因此尚且不能“运用自如”。内化是一个非常复杂的认知过程,本身涉及大脑中mind set和paradigm的切换,所以必然不是一个简单的隔夜就能完成的过程,这也就是为啥能够“消得人憔悴”,但是切换一旦完成,实践中就会自然流露出这种新的认识,也就是到了一个新的境界,发现灯火阑珊处。
  • 那么原则和知识的内化这个过程如何加速呢?也就是说,怎么才能较快地到达高手境界呢?可以肯定地说,光靠对自己说我“下次一定按照这个原则这样做”是不行的。认知科学认为,频繁的高强度的外部刺激和自主的有意识的反复提醒是加速内化的两个重要方法。第一个方法需要外部环境的支撑。试想,如果一个程序员不是天天和复杂的文本处理打交道,他必然没有足够的外部刺激来熟悉和内化正则表达式;如果一个程序员不是天天和极度复杂的大项目打交道,即使用全自动编译环境和自动单元测试,也显得无甚必要。因此,除非你正好掉进了一个天天有高强度训练的环境,否则全靠第一点是不可能的。尤其是自学一门语言和一门技术的程序员,往往在没有高强度训练之前就拿着这些技能投入工作了,因此想成为某方面的高手,只能采取第二条路,就是有意识地强化实践和反复提醒。
  • 《圣经》里有一个故事,说一个人在沙漠里,信心丧失的时候,突然听到“A Still SmallVoice”(平静的小声音),即上帝的启示。这个平静的小声音把他从绝望中拉了回来。其实对这个人来说,他本身的实践能力在“平静的小声音”出现前后并没有多大的改变,唯一的不同就是他知道该怎么做了。
  • 内化一个人知识或认识的时候所循的路径也是一样的。我们常常会“忘了”应该怎么正确地做一件事情(这个地方的“忘了”,指我们之前从书中或其他渠道读到看到了正确的原则或方法,但是在那一刻脑子里根本没考虑这个原则或方法,因为这个原则或方法根本没有亲自实践过,所以根本不是自己的一部分,不属于自己)。在这个时候,如果突然有一个平静的小声音跳出来,说,“嘿,你是不是该遵循这个原则,用这个方法?”无须说,我们对问题的思考就能顿时全面起来,也会更加深刻理解原先读到看到的不属于自己的原则和方法。当然,我们更加感兴趣的是,如何能够在身边没有高手和上帝发出这样的平静的小声音的时候,自己发出这样的小声音?
  • 怎么靠自己呢,记得鲁迅小朋友破坏公物在课桌上刻的“早”么?是的,我们须要抽象出一些简单的词句和规则,靠记忆和不断地提醒,小规模地内化这些小声音,让这些简单的小声音能够时刻从大脑里跳到耳边,提醒自己。具体来说,在阅读上面几本书,尤其是阅读《Pragmatic Programmer》的时候,如果仅仅以普通的浏览的方式阅读,就会很简单地陷入“啊,这个我知道了,啊,那个我了解了,嗯,这个以后要注意”的套路中。这样的阅读方式,只会强化原有的自己已经知道的部分,而不大可能把“以后要注意”这部分全部内化。所以,自负的读者读完之后必然觉得“哈哈,高手不过如此,大部分我也知道嘛”,而不是“是的,我还有不少要注意”。这两种态度,就把高手和易于满足的中手永恒地隔开了。我觉得,想要内化这些小声音,还是要靠实践,如果不实践,即使你把这些小声音写在100块钱的高档笔记本上也没有用。我个人觉得,理想的阅读状态应该是先大致理解和记住里面的Tip,然后每周争取实践2~3个Tip。其实这样做完一圈也就是半年,在这一圈后就会记住所有的Tip的内容,这时候,小声音就成了自己的一部分了。然后在剩下的几年里,只要时时有这些小声音跳出来,告诉你,“要自动频繁地测试”,或者“别手动做繁琐的工作”,你会很快被强迫转换到高效而优雅的工作状态中来。到了那个时候,这些小声音就再也不会跳出来了,因为你早就自然地遵守这些小声音的要求了。
  • 《Pragmatic Programmer》和《The Elements of Programming Style》书里面的Tip都不是来自上帝的话语,但都是值得随身带着的小声音。其实只要处理过实际问题,编过几万行程序,大多程序员都会有或深刻或浅显的对各个Tip的感悟,而且我相信或许有程序员对有些Tip的认识能比原书的作者还要深刻,这是很正常的。事实上,每一个Tip只是一句话而已,对这一句话的理解层次,则完全不是这一句话能够覆盖的。比如说,一天写了两个Hello Word的程序员能领悟到DRY,一位刚刚重构扔掉几千行重复代码的程序员也能领悟到DRY,而这两个DRY所在的认识层面,必然是不一样的。再好比说我在“编程珠玑番外篇”这个系列里面写的有些文字,看上去很有道理,但笔者本人对这些文字的认识可能比我的读者要浅。即使有些牛人觉得上面这几本书的作者在某些原则上的认识不够深刻,或者觉得作者只是在罗列一些小碎片,但只要读这些书,特别是《Pragmatic Programmer》这本书的那些小Tip,依然是有益的,因为他或许能触发你高于作者的思考,然后在你的脑中形成更加圆润的珠玑。而对于像我这样属于中手下游平时又没有大项目训练的人,《Pragmatic Programmer》这本书,和其他几本书一起,实在是很好的“小声音汇编”。

▶Washington University Ph.D. candidate徐宥

推荐六、专业人士对《程序员修炼之道》的赞誉

  • “关于这本书,最棒的是它能使编程过程保持新鲜。(本书)能帮助你持续成长,而且显然,它出自到过那里的人之手。”
    ——Kent Beck,Extreme Programming Explained:Embrace Change的作者
  • “我发现这本书出色地混合了坚实的建议和美妙的类比!”
    ——Martin Fowler,Refactoring与UML Distilled的作者
  • “我会买上一本,读上两遍,然后让我的所有同事都冲出去买一本。这是一本我决不会出借的书,因为我担心丢失。”
    ——Kevin Ruland, Management Science, MSG-Logistics
  • “作者的才智和实践经验显而易见。讨论的话题既切身又有益……迄今为止,对我而言它最大的力量在于那些出色的类比——曳光弹、破窗户,还有以直升机为基础、对为何需要正交性所做的惊人解释——特别是在紧急情况下。我几乎毫不怀疑:无论是编程“小工”,是专家级的顾问,还是其他专业人员,这本书最终都将成为有用信息的极好来源。”
    ——John Lakos, Large-Scale C++Software Design
  • “这是那种我会在其出版时买上一打、送给我的客户的书。”
    ——Eric Vought,软件工程师
  • “现在的大多数关于软件开发的书都没能说清一个杰出的软件开发者究竟应该具备哪些能力,而是把时间花在介绍语法和技术上——在现实生活中,拥有有才华的、真正精通其技艺的开发者,对任何软件团队而言都是其可能具有的最大优势。一本出色的书。”
    ——Pete McBreen,独立顾问
  • “自从读了这本书以后,我实施了书中提出的许多实用建议和提示。所有这些建议和提示都为我的公司节省了时间和金钱,同时还帮助我更快地完成了我的工作!每一个以编码为生的人,都应该在桌面上放一本做参考。”
    ——Jared Richardson,高级软件开发员,iRenaissance,Inc.
  • “我想看到这本书被发给我的公司的每一个新员工……”
    ——Chris Cleeland,高级软件工程师,Object Computing,Inc.

Things Really Haven’t Changed That Much

  • It’s been just over 10 years since we wrote The Pragmatic Programmer. In those tenyears, the industry has changed drastically. Many developers have moved away fromrandom hacking to embrace methodologies that make their development more reliable,and many of those methodologies are based on agile techniques. On the language front,we’ve seen a move away from static languages such as Java and C++to more dynamiclanguages such as Python and Ruby. We’re even seeing a resurgence of interest infunctional programming and Lisp-like languages.
  • In terms of architecture, applications have moved from the datacenter out onto thedesktop, and then just as rapidly moved from the desktop out into the cloud. Developersare having to learn new architectural principles, new communications techniques, and newways of deploying functionality. And, of course, applications are now becoming parallel.
    In a way, it seems as if the world has gone crazy.
  • But if you peel away all the surface differences, we think that underneath it all, thingsreally haven’t changed that much. The same common-sense principles that worked fordevelopment in 1999 still work in 2009 (and will likely still work in 2019). And we’d like tothink that many of those principles are captured in this book.
  • If we were writing The Pragmatic Programmer today, would it be different?Superficially, yes it would. We’d probably have different examples using different languages andtechnologies. We’d probably have to evangelize less about testing, as the software worldnow recognizes the benefits. We’d probably talk more about the web and social andcollaborative technologies.
  • But we think the essence of this book would be the same. Because software is writtenby people, and the best software developers recognize that they have to take a pragmatic,practical approach to their work. They know that the more things change, the moreimportant it is to know the underlying principles.
  • Enjoy this book. And remember to make software development fun!

▶Dave Thomas&Andy Hunt, The Pragmatic Programmers 2009.8

程序员修炼之道

1、关心你的技艺 Care About Your Craft

  • 除非你在乎能否漂亮地开发出软件,否则其它事情都是没有意义的。

2、思考!你的工作 Think! About Your Work

  • 在你做某件事情的时候思考你在做什么。不间断地思考,实时地批判你的工作。这将占据你的一些宝贵时间,酬劳则是更为活跃地参与你喜爱的工作、感觉到自己在掌握范围日增的各种主题以及因感受到持续的进步而欢愉。从长远来说,你在时间上的投入将会随着你和你的团队变得更为高效、编写出更易于维护的代码以及开会时间的减少而得到回报。

3、提供各种选择,不要找蹩脚的借口 Provide Options, Don’t Make Lame Excuses

  • 不要说事情做不到;要说明能够做什么来挽回局面。不要害怕提出要求,也不要害怕承认你需要帮助。

4、不要容忍破窗户 Don’t Live With Broken Windows

  • 不要留着“破窗户”(低劣的设计、错误的决策、或者糟糕的代码)不修。发现一个就修一个。如果没有足够的时间进行适当的修理,采取某种行动防止进一步的破坏,并说明情势处在你的控制之下。
    如果你发现你所在团队和项目的代码十分漂亮——编写整洁、设计良好,并且很优雅,你不会想成为第一个弄脏东西的人。

5、做变化的催化剂 Be a Catalyst for Change

  • 你不能强迫人们改变。相反,要向他们展示未来可能会怎样,并帮助他们参与对未来的创造。
  • 设计出你可以合理要求的东西,好好开发它。一旦完成,就拿给大家看,让他们大吃一惊。然后说:“要是我们增加…可能就会更好。”假装那并不重要。坐回椅子上,等着他们开始要你增加你本来就想要的功能。人们发现,参与正在发生的成功要更容易。让他们瞥见未来,你就能让他们聚集在你周围。

6、记住大图景 Remember the Big Picture

  • 如果你抓一只青蛙放进沸水里,它会一下子跳出来。但是,如果你把青蛙放进冷水里,然后慢慢加热,青蛙不会注意到温度的缓慢变化,会呆在锅里,直到被煮熟。
  • 不要像青蛙一样。留心大图景。要持续不断地观察周围发生的事情,而不只是你自己在做的事情。

7、使质量成为需求问题 Make Quality a Requirements Issue

  • 你所制作的系统的范围和质量应该作为系统需求的一部分规定下来。让你的用户参与权衡,知道何时止步,提供足够好的软件。

8、定期为你的知识资产投资 Invest Regularly in Your Knowledge Portfolio

  • 让学习成为习惯。
  • 持续投入十分重要。一旦你熟悉了某种新语言或新技术,继续前进,学习另一种。
  • 是否在某个项目中使用这些技术,或者是否把它们放入你的简历,这并不重要。学习的过程将扩展你的思维,使你向着新的可能性和新的做事方式拓展。思维的“异花授粉”十分重要;设法把你学到的东西应用到你当前的项目中。即使你的项目没有使用该技术,你或许也能借鉴一些想法。例如,熟悉了面向对象,你就会用不同的方式编写纯C程序。
    如果你自己找不到答案,就去找出能找到答案的人。不要把问题搁在那里。

9、批判地分析你读到的和听到的 Critically Analyze What You Read and Hear

  • 不要被供应商、媒体炒作、或教条左右。要依照你自己的看法和你的项目的情况去对信息进行分析。

10、你说什么和你怎么说同样重要 It’s Both What You Say and the Way You Say It

  • 作为开发者,我们必须在许多层面上进行交流。我们的时间有很大部分都花在交流上,所以我们需要把它做好。
    如果你不能有效地向他人传达你的了不起的想法,这些想法就毫无用处。
  • 知道你想要说什么;了解你的听众;选择时机;选择风格;让文档美观;让听众参与;做倾听者;回复他人。
    交流越有效,你就越有影响力。

11、DRY原则——不要重复你自己 DRY - Don’t Repeat Yourself

  • 系统中的每一项知识都必须具有单一、无歧义、权威的表示。与此不同的做法是在两个或更多地方表达同一事物。如果你改变其中一处,你必须记得改变其它各处。这不是你能否记住的问题,而是你何时忘记的问题。

12、让复用变得容易 Make it Easy to Reuse

  • 你要做的是营造一种环境,在其中要找到并复用已有的东西,比自己编写更容易。如果复用很容易,人们就会去复用。而如果不复用,你们就会有重复知识的风险。

13、消除无关事物之间的影响 Eliminate Effects Between Unrelated Things

  • 我们想要设计自足(self-contained)的组件:独立,具有单一、良好定义的目的。如果组件是相互隔离的,你就知道你能够改变其中一个,而不用担心其余组件。只要你不改变组件的外部接口,你就可以放心:你不会造成波及整个系统的问题。
    你得到两个主要好处:提高生产率与降低风险。

14、不存在最终决策 There Are No Final Decisions

  • 没有什么永远不变——而如果你严重依赖某一事实,你几乎可以确定它将会变化。与我们开发软件的速度相比,需求、用以及硬件变得更快。通过DRY原则、解耦以及元数据的使用,我们不必做出许多关键的、不可逆转的决策。有许多人会设法保持代码的灵活性,而你还需要考虑维持架、部署及供应商集成等领域的灵活性。

15、用曳光弹找到目标 Use Tracer Bullets to Find the Target

  • 曳光弹能通过试验各种事物并检查它们离目标有多远来让你追踪目标。
  • 曳光弹代码含有任何一段产品代码都拥有的完整的错误检查、结构、文档、以及自查。它只不过功能不全而已。但是,一旦你在系统的各组件之间实现了端到端(end-to-end)的连接,你就可以检查你离目标还有多远,并在必要的情况下进行调整。一旦你完全瞄准,增加功能将是一件容易的事情。

16、为了学习而制作原型 Prototype to Learn

  • 任何带有风险的事物。以前没有试过的事物,或是对于最终系统极其关键的事物。任何未被证明的、试验性的、或有疑问的事物。任何让你觉得不舒服的东西。都可以通过制作原型来研究。比如:架构;已有系统中的新功能;外部数据的结构或内容;第三方工具或组件;性能问题;用户界面设计等等。
  • 原型制作是一种学习经验,其价值并不在于所产生的代码,而在于所学到的经验教训。

17、靠近问题领域编程 Program Close to The Problem domain

  • 计算机语言会影响你思考问题的方式,以及你看待交流的方式。用你的用户的语言进行设计和编码。

18、估算,以避免发生意外 Estimate to Avoid Surprises

  • 在着手之前先进行估算。你将提前发现潜在的问题。
    1)要选择能反映你想要传达的精确度的单位;
    2)基本的估算诀窍:去问已经做过这件事情的人;
    3)理解提问内容;
    4)根据对问题的理解,建立粗略、就绪的思维模型骨架;
    5)把模型分解为组件,找出描述这些组件怎样交互的数学规则,确定每个组件的参数;
    6)给每个参数指定值,找出哪些参数对结果的影响最大,并致力于让它们大致正确;
    7)进行多次计算,改变关键参数的值,然后根据那些参数表达你的答案;
    8)在被要求进行估算时说的话:“我等会回答你”。

19、通过代码对进度表进行迭代 Iterate the Schedule with the Code

  • 实行增量开发。追踪你的估算能力,提炼对迭代次数、以及在每次迭代中可以包含的内容的猜想。提炼会变得一次比一次好,对进度表的信心也将随之增长。你将给予管理部门你所能给予的最精确的进度估算。

20、用纯文本保存知识 Keep Knowledge in Plain Text

  • 保证不过时;
  • 杠杆作用:每一样工具,都能够在纯文本上进行操作;
  • 更易于测试;
  • 你需要确保所有各方能够使用公共标准进行通信。纯文本就是那个标准。

21、利用命令shell的力量 Use the Power of Command Shells

  • GUI环境通常受限于它们的设计者想要提供的能力。当你想要快速地组合一些命令,以完成一次查询或某种其他的任务时,命令行要更为适宜。多使用你的命令shell,你会惊讶它能使你的生产率得到怎样的提高。

22、用好一种编辑器 Use a Single Editor Well

  • 选一种编辑器,彻底了解它,并将其用于所有的编辑任务。如果你用一种编辑器进行所有的文本编辑活动,你就不必停下来思考怎样完成文本操纵:必需的键击将成为本能反应。编辑器将成为你双手的延伸;键会在滑过文本和思想时歌唱起来。这就是我们的目标。

23、总是使用源码控制 Always Use Source Code Control

  • 总是。即使你的团队只有你一个人,你的项目只有一周时间;确保每样东西都处在源码控制之下。
    源码控制是你的工作的时间机器——你能够回到过去。
  • 把整个项目置于源码控制系统的保护之下具有一项很大的、隐蔽的好处:你可以进行自动的和可重复的产品构建。

24、要修正问题,而不是发出指责 Fix the Problem,Not the Blame

  • 要接受事实:调试就是解决问题,要据此发起进攻。Bug是你的过错还是别人的过错,并不是真的很有关系。它仍然是你的问题。

25、不要恐慌 Don’t Panic

  • 做一次深呼吸,思考什么可能是bug的原因。
  • 要总是设法找出问题的根源,而不只是问题的特定表现;
  • 搜集所有的相关数据;
  • 开始修正bug的最佳途径是让其可再现;
  • 使你的数据可视化;
  • 跟踪:观察程序或数据结构随时间变化的状态;
  • 找到问题的原因的一种非常简单、却又特别有用的技术是向别人解释它。你只是一步步解释代码要做什么,常常就能让问题从屏幕上跳出来,宣布自己的存在。

26、“Select”没有问题 “Select” Isn’t Broken

  • Bug有可能存在于OS、编译器、或是第三方产品中——但这不应该是你的第一想法。有大得多的可能性的是,bug存在于正在开发的应用代码中。与假定库本身出了问题相比,假定应用代码对库的调用不正确通常更有好处。即使问题确实应归于第三方,在提交bug报告之前,你也必须先消除你的代码中的bug。

27、不要假定,要证明 Don’t Assume it - Prove It

  • 不要因为你“知道”它能工作而轻易放过与bug有牵连的例程或代码。证明它。在实际环境中——使用真正的数据和边界条件——证明你的假定。

28、学习一种文本操作语言 Learn a Text Manipulation Language

  • 你用每天的很大一部分时间处理文本,为什么不让计算机替你完成部分工作呢?
  • 应用示例:
    数据库schema维护;
    Java、C#属性(Property)访问;
    测试数据生成。

29、编写能编写代码的代码 Write Code That Writes Code

  • 代码生成器能提高你的生产率,并有助于避免重复。

30、你不可能写出完美的软件 You Can’t Write Perfect Software

  • 这刺痛了你?不应该。把它视为生活的公理,接受它,拥抱它,庆祝它。因为完美的软件不存在。在计算机简短的历史中,没有一个人曾经写出过一个完美的软件。你也不大可能成为第一个。除非你把这作为事实接受下来,否则你最终会把时间和精力浪费在追逐不可能实现的梦想上。

31、通过合约进行设计 Design with Contracts

  • 什么是正确的程序?不多不少,做它声明要做的事情的程序。用文档记载这样的声明,并进行校验,是按合约设计(简称DBC)的核心所在。
  • 这里,强调的重点是在“懒惰”的代码上:对在开始之前接受的东西要严格,而允诺返回的东西要尽可能少。
    使用DBC的最大好处也许是它迫使需求与保证的问题走到前台来。在设计时简单地列举输入域的范围是什么、边界条件是什么、例程允诺交付什么——或者,更重要的,它不允诺交付什么——是向着编写更好的软件的一次飞跃。不对这些事项作出陈述,你就回到了靠巧合编程,那是许多项目开始、结束、失败的地方。

32、早崩溃 Crash Early

  • 死程序不说谎。
  • 当你的代码发现,某件被认为不可能发生的事情已经发生时,你的程序就不再有存活能力。从此时开始,它所做的任何事情都会变得可疑,所以要尽快终止它。死程序带来的危害通常比有问题的程序要小得多。

33、如果它不可能发生,用断言确保它不会发生 If It Can’t Happen,Use Assertions to Ensure That It Won’t

  • 断言验证你的各种假定。在一个不确定的世界里,用断言保护你的代码。
  • 不要用断言代替真正的错误处理。断言检查的是决不应该发生的事情。

34、将异常用于异常的问题 Use Exceptions for Exceptional Problems

  • 异常表示即使的、非局部的控制转移——这是一种级联的(cascading)goto。异常应保留给意外事件。那些把异常用作其正常处理的一部分的程序,将遭受所有可读性和可维护性问题的折磨。这些程序破坏了封装:通过异常处理,例程和它们的调用者被更紧密地耦合在一起。

35、要有始有终 Finish What You Start

  • 只要可能,分配某资源的例程或对象也应该负责解除其分配。

36、使模块之间的耦合减至最少 Minimize Coupling Between Modules

  • 编写“羞怯”的代码;
  • 函数的得墨忒耳(Demeter)法则规定,某个对象的任何方法都应该只调用属于以下情形的方法:
    1)它自身;
    2)传入该方法的任何参数;
    3)它创建的任何对象;
    4)任何直接持有的组件对象。
  • 物理解耦。

37、要配置,不要集成 Configure,Don’t Integrate

  • 细节会弄乱我们整洁的代码——特别是如果它们经常变化。把它们赶出代码。当我们在与它作斗争时,我们可以让我们的代码变得高度可配置和“软和”——也就是,容易适应变化。
    要用元数据(metadata)描述应用的配置选项:调谐参数、用户偏好(user preference)、安装目录,等等。

38、将抽象放进代码,细节放进元数据 Put Abstractions in Code,Details in Metadata

  • 但我们不只是想把元数据用于简单的偏好。我们想要尽可能多地通过元数据配置和驱动应用。我们的目标是以声明方式思考(规定要做什么,而不是怎么做),并创建高度灵活和可适应的应用。我们通过采用一条一般准则来做到这一点:为一般情况编写程序,把具体情况放在别处——在编译的代码库之外。
  • 也许你在编写一个具有可怕的工作流需求的系统。动作会根据复杂的(和变化的)商业规则启动和停止。考虑在某种基于规则的系统(即专家系统)中对它们进行编码,并嵌入到你的应用中。这样,你将通过编写规则、而不是修改代码来配置它。

39、分析工作流,以改善并发性 Analyze Workflow to Improve Concurrency

  • 时间是软件架构的一个常常被忽视的方面。时间有两个方面对我们很重要:并发(事情在同一时间发生)和次序(事情在时间中的相对位置)。
  • 我们在编写程序时,通常并没有把这两个方面放在心上。当人们最初坐下来开始设计架构,或是编写代码时,事情往往是线性的。那是大多数人的思考方式——总是先做这个,然后再做那个。但这样思考会带来时间耦合:方法A必须总是在方法B之前调用;同时只能运行一个报告;在接收到按钮点击之前,你必须等待屏幕重画。“嘀”必须在“嗒”之前发生。
    这样的方法不那么灵活,也不那么符合实际。
  • 我们需要容许并发,并考虑解除任何时间或者次序上的依赖。

40、用服务进行设计 Design Using Services

  • 实际上我们创建的并不是组件,而是服务——位于定义良好的、一致的接口之后的独立、并发的对象。
  • 通过把你的系统架构成多个独立的服务,你可以让配置成为动态的。

41、总是为并发进行设计 Always Design for Concurrency

  • 首先,必须对任何全局或静态变量加以保护,使其免于并发访问,现在也许是问问你自己、你最初为何需要全局变量的好时候。此外,不管调用的次序是什么,你都需要确保你给出的是一致的状态信息。
  • 在被调用时,对象必须总是处在有效的状态中,而且它们可能会在最尴尬的时候被调用。你必须确保,在任何可能被调用的时刻,对象都处在有效的状态中。这一问题常常出现在构造器与初始化例程分开定义的类中(构造器没有使对象进入已初始化状态)。
  • 一旦你设计了具有并发要素的架构,你可以灵活地处理应用的部署方式:单机、客户-服务器、或是n层。

42、使视图与模型分离 Separate Views from Models

  • 也就是常说的MVC模式(Model-View-Controller)。
    – 模型:表示目标对象的抽象数据模型。模型对任何视图或控制器都没有直接的了解。
    – 视图:解释模型的方式。它订阅模型中的变化和来自控制器的逻辑事件。
    – 控制器:控制视图、并向模型提供新数据的途径。
  • 通过松解模型与视图/控制器之间的耦合,你用低廉的代价为自己换来了许多灵活性。

43、用黑板协调工作流 Use Blackboards to Coordinate Workflow

  • 用黑板协调完全不同的事实和因素,同时又使各参与方保持独立和隔离。
  • 现代的分布式类黑板(blackboard-like)系统,比如JavaSpaces和T Spaces。

44、不要靠巧合编程 Don’t Program by Coincidence

  • 总是意识到你在做什么。
  • 不要盲目地编程。试图构建你不完全理解的应用,或是使用你不熟悉的技术,就是希望自己被巧合误导。
    按照计划行事。
  • 依靠可靠的事物。如果你无法说出各种特定情形的区别,就假定是最坏的。
  • 为你的假定建立文档。“按合约编程”有助于澄清你头脑中的假定,并且有助于把它们传达给别人。
  • 不要只是测试你的代码,还要测试你的假定。
  • 为你的工作划分优先级。
  • 不要做历史的奴隶。不要让已有的代码支配将来的代码。
  • 所以下次有什么东西看起来能工作,而你却不知道为什么,要确定它不是巧合。

45、估算你的算法的阶 Estimate the Order of Your Algorithms

  • 在你编写代码之前,先大致估算事情需要多长时间。

46、测试你的估算 Test Your Estimates

  • 对算法的数学分析并不会告诉你每一件事情。在你的代码的目标环境中测定它的速度。

47、早重构,常重构 Refactor Early,Refactor Often

  • 在需要时对代码进行重写、重做和重新架构。要铲除问题的根源。不要容忍破窗户。
  • 关于重构,详见Martin Fowler的《重构》一书。

48、为测试而设计 Design to Test

  • 在你还没有编写代码时就开始思考测试问题。测试驱动开发?

49、测试你的软件,否则你的用户就得测试 Test Your Software,or Your Users Will

  • 测试是技术,但更是文化。一点预先的准备可以大大降低维护费用、减少客户服务电话。

50、不要使用你不理解的向导代码 Don’t Use Wizard Code You Don’t Understand

  • 向导很了不起。只需要点击一个按钮,回答一些简单的问题,向导就会自动为你生成骨架代码(skeleton code)。但如果你使用向导,却不理解它制作出的所有代码,你就无法控制你自己的应用。你没有能力维护它,而且在调试时会遇到很大的困难。

51、不要搜集需求——挖掘它们 Don’t Gather Requirements - Dig for Them

  • 需求很少存在于表面上。它们深深地埋藏在层层假定、误解和政治手段的下面。

52、与用户一同工作,以像用户一样思考 Work with a User to Think Like a User

  • 要了解系统实际上将如何被使用,这是最好的方法。开采需求的过程也是开始与用户群建立和谐的关系、了解他们对你正在构建的系统的期许和希望的时候。

53、抽象比细节活得更长久 Abstractions Live Longer than Details

  • “投资”于抽象,而不是实现。抽象能在来自不同的实现和新技术的变化的“攻击”之下存活下去。

54、使用项目词汇表 Use a Project Glossary

  • 如果用户和开发者用不同的名称指称同一事物,或是更糟,用同一名称指称不同事物,这样的项目很难取得成功。

55、不要在盒子外面思考——要找到盒子 Don’t Think Outside the Box - Find the Box

  • 在遇到不可能解决的问题时,问问自己以下问题:
    – 有更容易的方法吗?
    – 你是在设法解决真正的问题,还是被外围的技术问题转移了注意力?
    – 这件事情为什么是一个问题?
    – 是什么使它如此难以解决?
    – 它必须以这种方式完成吗?
    – 它真的必须完成吗?
  • 很多时候,当你设法回答这些问题时,你会有让自己吃惊的发现。很多时候,对需求的重新诠释能让整个问题全部消失。
    你所需要的只是真正的约束、令人误解的约束、还有区分它们的智慧。

56、倾听反复出现的疑虑——等你准备好再开始 Listen to Nagging Doubts - Start When You’re Ready

  • 你的一生都在积累经验与智慧。当你面对一件任务时,如果你反复感觉到疑虑,或是体验到某种勉强,要注意它。你可能无法准确地指出问题所在,但给它时间,你的疑虑很可能就会结晶成某种更坚实的东西,某种你可以处理的东西。软件开发仍然不是科学。让你的直觉为你的表演做出贡献。

57、对有些事情“做”胜于“描述” Some Things Are Better Done Than Described

  • 你应该倾向于把需求搜集、设计、以及实现视为同一个过程——交付高质量的系统——的不同方面。不要掉进规范的螺旋,在某个时刻,你需要开始编码。

58、不要做形式方法的奴隶 Don’t Be a Slave to Formal Methods

  • 如果你没有把某项技术放进你的开发实践和能力的语境中,不要盲目地采用它。

59、昂贵的工具不一定能制作出更好的设计 Expensive Tools Do Not Produce Better Designs

  • 小心供应商的炒作、行业教条、以及价格标签的诱惑。在考察工具的产出时,试着不要考虑它值多少钱。

60、围绕功能、而不是工作职务进行组织 Organize Around Functionality,Not Job Functions

  • 把你的人划分成小团队,分别负责最终系统的特定方面的功能。让团队按照个人的能力,在内部自行进行组织。
  • 但是,只有在项目拥有负责的开发者、以及强有力的项目管理时,这种途径才有效。创立一组自行其是的团队并放任自流,是一种灾难性的处方。
  • 要记住,团队是由个体组成的。让每个成员都能以他们自己的方式闪亮。

61、不要使用手工流程 Don’t Use Manual Procedures

  • shell脚本或批处理文件会一次次地以同一顺序执行同样的指令。我们可以自动安排备份、夜间构建、网站维护、以及其他任何可以无人照管地完成的事情。让计算机去做重复、庸常的事情——它会做得比我们更好。我们有更重要、更困难的事情要做。

62、早测试,常测试,自动测试。Test Early.Test Often.Test Automatically.

  • 与呆在书架上的测试计划相比,每次构建时运行的测试要有效得多。

63、要等到通过全部测试,编码才算完成 Coding Ain’t Done 'Til All the Tests Run

  • 就是这样。

64、通过“蓄意破坏”测试你的测试 Use Saboteurs to Test Your Testing

  • 在单独的软件副本上故意引人bug,以检验测试能够抓住它们。

65、测试状态覆盖,而不是代码覆盖 Test State Coverage,Not Code Coverage

  • 确定并测试重要的程序状态。只是测试代码行是不够的。即时具有良好的代码覆盖,你用于测试的数据仍然会有巨大的影响,而且,更为重要的是,你遍历代码的次序的影响可能是最大的。

66、一个bug只抓一次 Find Bugs Once

  • 一旦测试员找到一个bug,这应该是测试员最后一次找到它。此后自动测试应该对其进行检查。

67、把英语当作又一种编程语言 Treat English as Just Another Programming Language

  • 像你编写代码一样编写文档:遵守DRY原则、使用元数据、MVC、自动生成,等等。

68、把文档建在里面,不要拴在外面 Build Documentation In, Don’t Bolt It On

  • 与代码分离的文档不太可能被修正和更新。使用像JavaDoc和NDoc这样的工具,我们可以根据源码生成API级的文档。
  • 文档和代码是同一底层模型的不同视图,但视图是唯一应该不同的东西。

69、温和地超出用户的期望 Gently Exceed Your Users’ Expectations

  • 要设法让你的用户惊讶。请注意,不是惊吓他们,而是要让他们高兴。要理解用户的期望,然后给他们的东西要多那么一点。给系统增加某种面向用户的特性所需的一点额外努力将一次又一次在商誉上带来回报。

70、在你的作品上签名 Sign Your Work

  • 我们想要看到对所有权的自豪。“这是我编写的,我对自己的工作负责。”你的签名应该被视为质量的保证。当人们在一段代码上看到你的名字时,应该期望它是可靠的、用心编写的、测试过的和有文档的,一个真正的专业作品,由真正的专业人员编写。一个注重实效的程序员。

猜你喜欢

转载自blog.csdn.net/howard2005/article/details/125120591
今日推荐