程序员修炼之道:从小工到专家

Andrew Hunt David Thomas

领悟程序员的哲学

  • 从程序员的个体哲学到编码过程中的各个环节,再到团队的项目管理;从程序员要如何扩充知识,如何思考问题,如何利用有效的工具打造个人的工作环境,到项目启动之前如何建立一些基本准则,如何分析、设计、编写、测试、重构,如何实现自动化,甚至是项目团队中提高实效的原则

再次阅读,感受颇多

  • 关于DRY,我想说,不但don't repeat yourself,也don't repeat others,
  • 作为一个pragmatic程序员,合理地使用工具、库,以及自己积累的开发的轮子,会让自己的productivity不断提升。
  • “牛人”其实是备有很多现成代码的,完成这个功能只是把之前积累的封装良好的模块重用就可以了。

一切阅读都是误读

  • 古人云,读书有三上,马上、枕上、厕上。

程序员升级必备

  • 如果要成为一个好程序员,其实所需要的道理也多不了多少,只不过,当水平不够的时候,永远不能认识到那些朴素道理的重要。
  • 经验这个东西,往往并不能告诉我们什么一定对,但是可以告诉我们什么一定不对。
  • 注重实效的程序员应该不断学习

程序员心底的小声音

  • 高手的风格一般是浮光掠影地概括自己领会的几个原则和教训。这些寥寥数语的珠玑,对其他高手来说一看就懂,但是对于中手来说就很难理解了。
  • 《Pragmatic Programmer》、《The Art of UNIX Programming》、《Elements of Programming Style》和《The Productive Programmer》
  • 能不能让正确的原则指导正确的行动本身,其实就是区分是否是高手的一个显著标志。
  • 认知科学认为,频繁的高强度的外部刺激和自主的有意识的反复提醒是加速内化的两个重要方法。
  • 我们须要抽象出一些简单的词句和规则,靠记忆和不断地提醒,小规模地内化这些小声音,让这些简单的小声音能够时刻从大脑里跳到耳边,提醒自己。

软件开发的变化并不大

  • 他们知道变化越多,掌握事物的基本原则就越重要。

译序

  • 编程是一种技艺,一种需要用心学习的技艺
  • “hacker”的真正含义:“Someone who loves to program and enjoys being clever about it”

前言

  • 答案是他们在做某件事情时,会把注意力投注在他们在做的事情上——然后他们会试着把它做得更好。
  • 设想你在参加一个会议。或许你在想,这个会议没完没了,你还不如去写程序。而Dave和Andy会想,他们为什么在开会,他们想知道是否可以通过另外的方式取代会议,并决定是否可使某样事情自动化,以使开会的工作推后。然后他们就会这样去做。

  • 并不存在容易的答案。也不存在最佳解决方案这样一种东西,无论它是工具,是语言,还是操作系统。能够存在的只是在某些特定情形下更为适宜的系统。
  • 你不应该局限于任何特定的技术,而是应该拥有足够广博的背景和经验基础,以让你能在特定情况下选择好的解决方案。你的背景源自对计算机科学的基本原理的理解,而你的经验来自广泛的实际项目。理论与实践的结合使你强大起来。
  • 注重实效的程序员不仅要完成工作,而且要完成得漂亮。
  • 早期的采纳者/快速的改编者
  • Care About Your Craft关心你的技艺
  • Think!About Your Work 思考!你的工作
  • 我们,采集的只是石头,却必须时刻展望未来的大教堂。
  • Kaizen也适用于个人。每天为提炼你所拥有的技能而工作,为把新的工具增加到你的技能列表中而工作。与伊顿的草坪不同,你在几天之中就将开始看到结果。几年之后,你将会惊奇你的经验得到了怎样的发展,你的技能得到了怎样的提升。

第1章 注重实效的哲学 A Pragmatic Philosophy

  • 注重实效的程序员的特征是什么?我们觉得是他们处理问题、寻求解决方案时的态度、风格、哲学。他们能够越出直接的问题去思考,总是设法把问题放在更大的语境中,总是设法注意更大的图景。
  • 大多数人发现自己很难接受变化,有时是出于好的理由,有时只是因为固有的惰性。
  • 注重实效的编程源于注重实效的思考的哲学。

1 我的源码让猫给吃了

  • 在所有弱点中,最大的弱点就是害怕暴露弱点。
  • 注重实效的程序员对他或她自己的职业生涯负责,并且不害怕承认无知或错误
  • 如果你确实同意要为某个结果负责,你就应切实负起责任。当你犯错误(就如同我们所有人都会犯错误一样)、或是判断失误时,诚实地承认它,并设法给出各种选择。不要责备别人或别的东西,或是拼凑借口。不要把所有问题都归咎于供应商、编程语言、管理部门、或是你的同事。
  • 提供各种选择,不要找蹩脚的借口
  • 要提供各种选择,而不是找借口。不要说事情做不到;要说明能够做什么来挽回局面。

2 软件的熵

  • 熵是一个来自物理学的概念,指的是某个系统中的“无序”的总量
  • “破窗户理论”启发了纽约和其他大城市的警察部门,他们对一些轻微的案件严加处理,以防止大案的发生。这起了作用:管束破窗户、乱涂乱画和其他轻微违法事件减少了严重罪案的发生。
  • Don't Live with Broken Windows不要容忍破窗户
  • 这些代码的其余部分也是垃圾,我只要照着做就行了
  • 如果你发现你所在团队和项目的代码十分漂亮——编写整洁、设计良好,并且很优雅——你就很可能会格外注意不去把它弄脏
  • 你能否说出某扇窗户是何时破的?你的反应是什么?如果它是他人的决策所致,或者是管理部门的指示,你能做些什么?

3 石头汤与煮青蛙

  • 这正是拿出石头的时候。设计出你可以合理要求的东西,好好开发它。一旦完成,就拿给大家看,让他们大吃一惊。然后说:“要是我们增加……可能就会更好。”假装那并不重要。坐回椅子上,等着他们开始要你增加你本来就想要的功能。人们发现,参与正在发生的成功要更容易。让他们瞥见未来,你就能让他们聚集在你周围[1]。
  • Remember the Big Picture 记住大图景
  • 不要像青蛙一样。留心大图景。要持续不断地观察周围发生的事情,而不只是你自己在做的事情。
  • 士兵渐进地欺骗村民,但他们所催生的变化对村民完全有利。但是,渐进地欺骗青蛙,你是在加害于它。当你设法催生变化时,你能否确定你是在做石头汤还是青蛙汤?决策是主观的还是客观的?

4 足够好的软件

  • 欲求更好,常把好事变糟。
  • 许诺不可能兑现的时间标度(time scale),为赶上最后期限而削减基本的工程内容,这些同样不是有职业素养的做法。
  • Make Quality a Requirements Issue 使质量成为需求问题
  • 如果你给用户某样东西,让他们及早使用,他们的反馈常常会把你引向更好的最终解决方案
  • 不要因为过度修饰和过于求精而毁损完好的程序。

5 你的知识资产

  • 知识上的投资总能得到最好的回报。
  • 你的知识和经验是你最重要的职业财富。
  • 管理知识资产与管理金融资产非常相似:1.严肃的投资者定期投资——作为习惯。 2.多元化是长期成功的关键。 3.聪明的投资者在保守的投资和高风险、高回报的投资之间平衡他们的资产。 4.投资者设法低买高卖,以获取最大回报。 5.应周期性地重新评估和平衡资产。
  • 在新兴的技术流行之前学习它可能就和找到被低估的股票一样困难,但所得到的就和那样的股票带来的收益一样。
  • Invest Regularly in Your Knowledge Portfolio定期为你的知识资产投资
  • 每年至少学习一种新语言。
  • 如果你自己找不到答案,就去找出能找到答案的人。不要把问题搁在那里。与他人交谈可以帮助你建立人际网络,而因为在这个过程中找到了其他不相关问题的解决方案,你也许还会让自己大吃一惊。旧有的资产也在不断增长……
  • 所有阅读和研究都需要时间,而时间已经很短缺。所以你需要预先规划。让自己在空闲的片刻时间里总有东西可读。
  • 最后一个要点是,批判地思考你读到的和听到的。你需要确保你的资产中的知识是准确的,并且没有受到供应商或媒体炒作的影响
  • 批判地分析你读到的和听到的
  • ● 确切地知道你想要问什么,并尽量明确具体。● 小心而得体地组织你的问题。记住你是在请求帮助;不要显得好像是在要求对方回答。● 组织好问题之后,停下来,再找找答案。选出一些关键字,搜索Web。查找适当的FAQ (常见问题的解答列表)。● 决定你是想公开提问还是私下提问。
  • 如果你在进行非常详细的实现和编码,就阅读关于设计和架构的书。如果你在进行高级设计,就阅读关于编码技术的书。

6 交流

  • 我相信,被打量比被忽略要好。
  • 没有有效的交流,一个好想法就只是一个无人关心的孤儿。
  • 规划你想要说的东西。写出大纲。然后问你自己:“这是否讲清了我要说的所有内容?”提炼它,直到确实如此为止。
  • 只有当你是在传达信息时,你才是在交流。为此,你需要了解你的听众的需要、兴趣、能力。
  • 为了了解你的听众需要听到什么,你需要弄清楚他们的“轻重缓急”是什么
  • 要记住,你也是交流事务的一方。如果有人说,他们需要你用一段话进行描述,而你觉得不用若干页纸就无法做到,如实告诉他们。记住,这样的反馈也是交流的一种形式。
  • 如果你想要大家听你说话,你必须使用一种方法:听他们说话
  • 你应该总是对电子邮件和语音邮件做出回应,即使内容只是“我稍后回复你。”随时通知别人,会让他们更容易原谅你偶然的疏忽,并让他们觉得你没有忘记他们。
  • It's Both What You Say and the Way You Say It 你说什么和你怎么说同样重要
  • 知道你想要说什么。 了解你的听众。 选择时机。 选择风格。 让文档美观。 让听众参与。 做倾听者。 回复他人。

第2章 注重实效的途径 A Pragmatic Approach

  • 前者提醒你,不要在系统各处对知识进行重复,后者提醒你,不要把任何一项知识分散在多个系统组件中
  • 我们都是在一个时间和资源有限的世界上工作。如果你善于估计出事情需要多长时间完成,你就能更好地在两者都很匮乏的情况下生存下去(并让你的老板更高兴)。

7 重复的危害

  • 所有这些不稳定都意味着我们要把很大一部分时间花在维护上,重新组织和表达我们的系统中的知识。
  • 不管原因是什么,维护都不是时有时无的活动,而是整个开发过程中的例行事务。
  • 系统中的每一项知识都必须具有单一、无歧义、权威的表示。
  • DRY法则告诉我们,要把低级的知识放在代码中,它属于那里;把注释保留给其他的高级说明。否则,
  • 应该用头文件记载接口问题,用实现文件记载代码的使用者无须了解的实际细节。
  • 在可能的情况下,应该总是用访问器(accessor)函数读写对象的属性[1]。这将使未来增加功能(比如缓存)变得更容易。
  • 每个项目都有时间压力——这是能够驱使我们中间最优秀的人走捷径的力量。
  • 无耐性的重复是一种容易检测和处理的重复形式,但那需要你接受训练,并愿意为避免以后的痛苦而预先花一些时间。
  • 一定要阅读他人的源码与文档,不管是非正式的,还是进行代码复查
  • Make It Easy to Reuse 让复用变得容易

8 正交性

  • 在计算技术中,该术语用于表示某种不相依赖性或是解耦性。如果两个或更多事物中的一个发生变化,不会影响其他事物,这些事物就是正交的。
  • 当任何系统的各组件互相高度依赖时,就不再有局部修正(local fix)这样的事情。
  • Eliminate Effects Between Unrelated Things 消除无关事物之间的影响
  • 系统应该由一组相互协作的模块组成,每个模块都实现不依赖于其他模块的功能。
  • 不要依赖你无法控制的事物属性。
  • 让你的代码保持解耦。
  • 避免使用全局数据。
  • 避免编写相似的函数。
  • 养成不断地批判对待自己的代码的习惯。寻找任何重新进行组织、以改善其结构和正交性的机会。这个过程叫做重构(refactoring)
  • 运用DRY原则,你是在寻求使系统中的重复降至最小;运用正交性原则,你可降低系统的各组件间的相互依赖。

9 可撤消性

  • 如果某个想法是你唯一的想法,再没有什么比这更危险的事情了。
  • 要实现某种东西,总有不止一种方式,而且通常有不止一家供应商可以提供第三方产品。如果你参与的项目被短视的、认为只有一种实现方式的观念所牵绊,你也许就会遇到让人不悦的意外之事。许多项目团队会被迫在未来展现之时睁开眼睛
  • 但如果你真的已经把数据库的概念抽象出来——抽象到数据库只是把持久(persistence)作为服务提供出来的程度——你就会拥有“中流换马(change horses in midstream)”的灵活性。
  • 要把决策视为是写在沙滩上的,而不要把它们刻在石头上。大浪随时可能到来,把它们抹去。
  • There Are No Final Decisions 不存在最终决策

10 曳光弹

  • 曳光代码并非用过就扔的代码:你编写它,是为了保留它。它含有任何一段产品代码都拥有的完整的错误检查、结构、文档、以及自查。它只不过功能不全而已
  • 总有改动需要完成,总有功能需要增加。这是一个渐进的过程。
  • 开发者构建了一个他们能在其中工作的结构。

11 原型与便笺

  • 原型的设计目的就是回答一些问题,所以与投入使用的产品应用相比,它们的开发要便宜得多、快捷得多。

12 领域语言

  • 语言的界限就是一个人的世界的界限。

13 估算

  • 所以当有人要你进行估算时,你要问自己的第一个问题就是,你解答问题的语境是什么?他们是需要高度的准确性,还是在考虑棒球场的大小?
  • 去问已经做过这件事情的人。在你一头钻进建模之前,仔细在周围找找也曾处在类似情况下的人。

14 纯文本的威力

  • Keep Knowledge in Plain Text 用纯文本保存知识
  • 保证不过时杠杆作用更易于测试
  • 提供“锋利”的小工具、其中每一样都意在把一件事情做好——Unix因围绕这样的哲学进行设计而著称。

15 shell游戏

  • GUI的好处是WYSIWYG——所见即所得(what you see is what you get)。缺点是WYSIAYG——所见即全部所得(what you see is all you get)。

16 强力编辑

  • 我们认为你最好是精通一种编辑器,并将其用于所有编辑任务:代码、文档、备忘录、系统管理,等等。

17 源码控制

  • 进步远非由变化组成,而是取决于好记性。不能记住过去的人,被判重复过去。

18 调试

  • Fix the Problem,Not the Blame要修正问题,而不是发出指责
  • 在调试时小心“近视”。要抵制只修正你看到的症状的急迫愿望:更有可能的情况是,实际的故障离你正在观察的地方可能还有几步远,并且可能涉及许多其他的相关事物。要总是设法找出问题的根源,而不只是问题的特定表现。

第4章 注重实效的偏执 Pragmatic Paranoia

  • 但注重实效的程序员会更进一步。他们连自己也不信任。知道没有人能编写完美的代码,包括自己,所以注重实效的程序员针对自己的错误进行防卫性的编码。

23 断言式编程

  • 在自责中有一种满足感。当我们责备自己时,会觉得再没人有权责备我们。
  • If It Can't Happen,Use Assertions to Ensure That It Won't如果它不可能发生,用断言确保它不会发生
  • 不要用断言代替真正的错误处理。断言检查的是决不应该发生的事情

27 元程序设计

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

31 靠巧合编程

  • 不要只是测试你的代码,还要测试你的假定。

33 重构

  • 随着程序的演化,我们有必要重新思考早先的决策,并重写部分代码。这一过程非常自然。代码需要演化;它不是静态的事物。
  • Refactor Early,Refactor Often 早重构,常重构
  • 1.不要试图在重构的同时增加功能。2.在开始重构之前,确保你拥有良好的测试。尽可能经常运行这些测试。这样,如果你的改动破坏了任何东西,你就能很快知道。

36 需求之坑

  • 完美,不是在没有什么需要增加、而是在没有什么需要去掉时达到的。
  • 找出用户为何要做特定事情的原因、而不只是他们目前做这件事情的方式,这很重要。

41 注重实效的团队

  • 质量只可能源于全体团队成员都做出自己的贡献。

43 无情的测试

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

44 全都是写

  • 一般而言,注释应该讨论为何要做某事、它的目的和目标。代码已经说明了它是怎样完成的,所以再为此加上注释是多余的——而且违反了DRY原则。