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

提示汇总:

  1. Care About Your Craft. 关心你的技艺。
  2. Think! About Your Work. 思考!你的工作。
  3. 提供各种选择,不要找蹩脚的借口。
  4. 不要容忍破窗户。
  5. 做变化的催化剂。Be the Catalyst for Change!
  6. 记住大图景。Remember the Big Picture!
  7. 使质量成为需求问题。
  8. 定期为你的知识资产投资
  9. 批判地分析你读到的和听到的。
  10. 你说什么和你怎么说同样重要!
  11. DRY - Don’t Repeat Yourself. 不要重复你自己。
  12. Make It Easy To Reuse。 让复用变得容易。
  13. 消除无关事物之间的影响。
  14. 不存在最终决策。There Are No Final Decisions.
  15. 用曳光弹找到目标。Use Tracer Bullets to Find the Target.
  16. 为了学习而制作原型。Prototype to Learn.
  17. 靠近问题领域编程。Program Close to the Problem domain.
  18. 估算,以避免发生意外。Estimate to Avoid Surprises.
  19. 通过代码对进度表进行迭代。Iterate the Schedule with the Code.
  20. 用纯文本保存知识。Keep Knowledge in Plain Text.
  21. 利用命令Shell的力量。Use the Power of Command Shells.
  22. 用好一种编辑器。Use a Single Editor Well.
  23. 总是使用源码控制。Always Use Source Code Control
  24. 要修正问题,而不是发出指责。 Fix the Problem, not the Blame.
  25. 调试第一准则:不要恐慌。Don’t Panic.
  26. “Select”没有问题。不要先怀疑是第三方产品的问题
  27. 不要假定,要证明。
  28. 学习一种文本操纵语言,如Python,Tcl, Perl
  29. 编写能编写代码的代码。Write Code That Writes Code。
  30. 你不可能写出完美的软件
  31. 通过合约进行设计。Design with Contracts.
  32. 早崩溃。Crash Early.
  33. 如果它不可能发生,用断言确保它不会发生。If it can’t Happen, Use Assertions to Ensure That It won’t.
  34. 将异常用于异常的问题。Use Exceptions For Exceptional Problems.
  35. 要有始有终。Finish What You Start.

  1. Care About Your Craft. 关心你的技艺。
  2. Think! About Your Work. 思考!你的工作。

我们采集的只是石头,却必须时刻展望未来的大教堂。

它是一个持续的过程!

第1章 注重实效的哲学

  1. 我的源码让猫给吃了

在所有的弱点中,最大的弱点就是害怕暴露弱点。

提供各种选择,不要找蹩脚的借口。不要说事情做不到,要说明能够做什么来挽回局面。

  1. 软件的熵

不要容忍破窗户。不要留着“破窗户”(低劣的设计,错误决策,或是糟糕的代码)不修,发现一个就修一个。

  1. 石头汤与煮青蛙

参与正在发生的成功要更容易,让他们瞥见未来,你就能让他们聚集在你周围。

做变化的催化剂。Be the Catalyst for Change!

记住大图景。Remember the Big Picture!

请求原谅比获取许可更容易。

  1. 足够好的软件

使质量成为需求问题。许多用户宁愿在今天用上有一些“毛边”的软件,也不愿等待一年后的多媒体版本。

不要因为过度修饰和过于求精而毁损完好的程序。

  1. 你的知识资产

知识上的投资总能得到最好的回报。遗憾的是,它们是有时效的资产。随着新技术、语言及环境的出现,你的知识会变得过时,不断变化的市场驱动力也许会使你的经验变得陈旧或无关紧要。

我们喜欢把程序员所知道的关于计算技术和他们所工作的应用领域的全部事实、以及他们的所有经验视为他们的知识资产,管理知识资产与管理金融资产非常相似:

(1) 严肃的投资者定期投资–作为习惯

(2) 多元化是长期成功的关键:你知道的不同的事情越多,你就越有价值,今天的热门技术明天就可能变得近乎无用,你掌握的技术越多,你就能更好地进行调整,干山

(3) 管理风险:聪明的投资者在保守的投资和高风险、高回报的投资之间平衡他们的资产:不要把你所有的技术鸡蛋放在一个篮子里。

(4) 投资者设法低买高卖,以获取最大回报:在新兴的技术流行之前学习它可能就和找到被低估的股票一样困难,但所得到的就和那样的股票带来的收益一样。

(5) 应周期性地重新评估和平衡资产。IT是一个非常动荡的行业。

最重要的也是最简单的:定期为你的知识资产投资

(1) 每年至少学习一种新语言:不同语言以不同方式解决相同的问题,学习若干不同的方法,可以帮助你拓宽你的思维,并避免墨守成规。

(2) 每季度阅读一本技术书籍:讨论与你项目有关的有趣话题,一旦你养成习惯,就一个月读一本书,在你掌握了你正在使用的技术之后,扩宽范围,阅读一些与你的项目无关的书籍。如果你在进行非常详细的实现和编码,就阅读关于设计和架构的书,如果你在进行高级设计,就阅读关于编码技术的书。

(3) 也要阅读非技术书籍:记住计算机是由人——你在设法满足其需要的人——使用的,这十分重要,不要忘了等式中人这一边。出去与你的当前项目无关的人或者是其他公司的人谈谈技术。

(4) 上课:在本地的学院或大学,或是将要来临的下一次会展上寻找有趣的课程

(5) 参加本地用户组织:不要只是去听讲,而要主动参与,与世隔绝对你的职业生涯来说可能是致命的;打听一下你们公司以外的人都在做什么

(6) 实验不同的环境:如果你只在windows上工作,就在家玩一玩unix,如果你只用过makefile和编辑器,就试一试IDE,反之亦然。

(7) 跟上潮流:订阅商务杂志和其他期刊(),选择所涵盖的技术与你当前项目不同的刊物

(8) 上网:了解新语言特性,了解其他人的相关经验

持续投入十分重要。一旦你熟悉了某种新语言或新技术,继续前进,学习另一种。

是否在某个项目中使用这些技术,或者是否把它们放入你的简历,这并不重要,学习的过程将扩展你的思维,使你向着新的可能性和新的做事方式拓展。思想的“异花授粉”十分重要,设法把你学到的东西应用到你当前的项目中。即使你的项目没有使用该技术,你或许也能借鉴一些想法。

遇到一个问题,如果你自己找不到答案,就去找出能找到答案的人,不要把问题搁在那里。所有阅读和研究都需要时间,所以你需要预先规划,让自己在空闲的片刻总有东西可读。

批判地分析你读到的和听到的。你需要确保你的资产中的知识是准确的,并且没有受到供应商或媒体炒作的影响。

与“古鲁”打交道的礼节与教养:

(1) 确切地知道你想要问什么,并尽量明确具体

(2) 小心而得体地组织你的问题。记住你是在请求帮助;不要显得好像是在要求对方回答。

(3) 组织好问题之后,停下来,再找找答案。选出一些关键字,搜索Web,查找适当的FAQ.

(4) 决定你是想公开提问还是私下提问。要使用有意义的主题

(5) 坐回椅子,耐心等候。

(6) 表达感谢

  1. 交流

我相信,被打量比被忽略要好。

你说什么和你怎么说同样重要!

(1) 知道你想要说什么。规划你想要说的东西,写出大纲,然后问你自己:这是否讲清了我要说的所有内容?提炼它,直到确实如此为止。

(2) 了解你的听众。只有当你是在传达信息时,你才是在交流。为此,你需要了解你的听众的需要、兴趣、能力。

(3) 选择时机。要让你所说的适得其时,在内容上切实相关。

(4) 选择风格,适应听众。

(5) 让文档美观。

(6) 让听众参与。让读者参与文档的早期草稿的制作,获取他们的反馈,并汲取他们的智慧,你将建立良好的工作关系,并制作出更好的文档。

(7) 做倾听者。鼓励大家通过提问来交谈,或是让他们总结你告诉他们的东西。

(8) 回复他人。

WISDOM离合诗:了解听众:

你想让他们学到什么?

他们对你讲的什么感兴趣?

他们有多富有经验?

他们想要多少细节?

你想要让谁拥有这些信息?

你如何促使他们听你说话?

第2章 注重实效的途径

不要在系统各处对知识进行重复

不要把任何一项知识分散在多个系统组件中

  1. 重复的危害

    可靠的开发软件,并让我们的开发更易于理解和维护的唯一途径,是遵循我们称之为DRY的原则:

    系统中每一项知识都必须具有单一,无歧义、权威的表示。

    提示11:DRY - Don’t Repeat Yourself. 不要重复你自己。

    (1) 强加的重复:

    ​ 信息的多种表示:可以通过编写过滤器/代码生成器

    ​ 代码中的文档:糟糕的代码才需要很多注释。要把低级的知识放在代码中,它属于那里;把注释保留给其他的高级说明。

    ​ 文档与代码:使用程序方式,根据文档本身生成测试,当客户修订他们的规范时,测试套件会自动改变。

    ​ 语言问题:应该在引用处记载接口问题,用实现文件记载代码的使用者无须了解的实际细节

    (2) 无意的重复:

    ​ 在开发过程中,你可以因为性能而选择违反DRY原则,其诀窍是使影响局部化,对DRY原则的违反没有暴露给外界:只有类中的方法需要注意“保持行为良好”。

    ​ 像Java和C++这样的面向对象语言,在可能的情况下,应该总是用访问器函数读写对象的属性,这使未来增加功能变得更容易。

    (3) 无耐性的重复:

    ​ 欲速则不达。

    (4) 开发者之间的重复:

    ​ 鼓励开发者相互进行主动的交流,设置论坛,用以讨论常见问题。

    提示12:Make It Easy To Reuse。 让复用变得容易。

  2. 正交性

    某种不相互依赖性或是解耦性,如果两个或更多事物中的一个发生变化,不会影响其他事物,这些事物就是正交的。

    提示13:消除无关事物之间的影响。

    如果你编写正交系统,你会得到:提高生产率与降低风险

    提高生产率:

    ​ 改动局部,所以开发和测试时间得以降低。

    ​ 促进复用:假定某个组件做M件事情,另一个组件做N件事情,如果它们的正交的,你把他们组合在一起就可以做M*N件事情

    降低风险:

    ​ 有问题的代码区域被隔离开来

    ​ 系统更加稳健

    ​ 正交系统很可能能得到更好的测试

    ​ 不会与特定的供应商、产品或是平台紧绑在一起

    应用正交原则的几种方式:

    ​ 项目团队:把团队划分为责任得到良好定义的小组,并使得重叠降到最低。我们的偏好是从使基础设施与应用分离开始,每个主要的基础设施组件(数据库,通信接口,中间件层,等等)有自己的子团队,如果应用功能的划分显而易见,那就照此划分。

    ​ 设计:模块化、基于组件、分层等。系统应该由一组相互协作的模块组成,每个模块都实现不依赖其他模块的功能,有时,这些组件被组织为多个层次,每层提供一级抽象。不要依赖你无法控制的事物属性。

    ​ 工具箱与库:在引入第三方工具箱和库时,要注意保持系统的正交性,明智地选择技术。在引入某个工具箱时,考虑一下它是否迫使你对代码进行不必要的改动。EJB,面向方面编程(AOP)都是正交性比较好的例子。

    ​ 编码:可以用若干技术维持正交性:(1) 让你的代码保持解耦:如果你需要改变对象的状态,让这个对象替你去做;(2) 避免使用全局数据:每当你的代码引用全局数据时,它都把自己与共享该数据的其他组件绑在了一起。一般而言,如果你把所需的任何语境显式地传入模块,你的代码就会更易于理解和维护。

    ​ 避免编写相似的函数:例如使用Strategy策略模式。养成不断地批判对待自己的代码的习惯,寻找任何重新进行组织,以改善其结构和正交性的机会,这个过程叫重构。

    ​ 测试:正交地设计和实现的系统也更易于测试。我们建议让每个模块都拥有自己的,内建在代码中的单元测试,并让这些测试作为常规构建过程的一部分自动运行。使用源码控制系统,可以分析每个bug修正所影响的源文件数据的变化趋势。

    ​ 文档:对于真正正交的文档,你应该能显著地改变外观,而不用改变内容。

    ​ 认同正交性:DRY原则寻求使系统中的重复降至最小;运用正交性原则,可降低系统各组件间的相互依赖。

  3. 可撤销性:

    要把决策视为写在沙滩上的。

    提示14:不存在最终决策。There Are No Final Decisions.

    灵活的架构:考虑维持架构、部署及供应商集成等领域的灵活性。你是否处理了所有可移植性问题。把第三方产品隐藏在定义良好的抽象接口后面。无论你使用的是何种机制,让它可撤销,如果某样东西是自动添加的,它也可以被自动去掉。

  4. 曳光弹

    曳光弹行之有效,是因为它们与真正的子弹在相同的环境、相同的约束下工作,它们快速飞向目标,所以枪手可以得到即时的反馈,同时,从实践的角度看,这样的解决方案也更便宜。

    提示15:用曳光弹找到目标。Use Tracer Bullets to Find the Target.

    曳光代码并非用过就扔的代码:你编写它,是为了保留它,它含有任何一段产品代码都拥有的完整的错误检查、结构、文档、以及自查,它只不过功能不全而已。

    曳光代码优点:用户能够及早看到能工作的东西;开发者构建了一个他们能在其中工作的结构;你有了一个集成平台;你有了可用于演示的东西;你将更能感觉到工作进展。

  5. 原型与便签

    原型可以忽略不重要的细节。但如果你发现自己处在不能放弃细节的环境中,就需要问自己,是否真的在构建原型,或许曳光弹开发方式更适合这种情况。

    原型制作的要点在于所学到的经验教训。

    原型可以忽略的细节:正确性/完整性/健壮性/风格

    提示16:为了学习而制作原型。Prototype to Learn.

    原型制作中,思考每个模块是否能访问其所需的数据?是否能在需要时进行访问?

  6. 领域语言

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

    提示17:靠近问题领域编程。Program Close to the Problem domain.

    实现小型语言;数据语言与命令语言;独立语言与嵌入式语言;

    易于开发还是易于维护:考虑到大多数应用都会超过预期的使用期限,你可能最好咬紧牙关,先就采用更复杂、可读性更好的语言,最初的努力将在降低支持与维护费用方面得到许多倍的回报。

  7. 估算

    通过学习估算,并将此技能发展到你对事物的数量级有直觉的程度,你就能展现出一种魔法版的能力,确定它们的可行性。

    提示18:估算,以避免发生意外。Estimate to Avoid Surprises.

    多准确才足够准确;要选择能反映你想要传达的精确度的单位;一个估算技巧:去问已经做过这件事的人;理解提问内容;建立系统的模型;把模型分解为组件;给每个参数指定值;计算答案;追踪你的估算能力;估算项目进度:检查需求,分析风险,设计、实现、集成,向用户确认。把改进进度表作为每次迭代的一部分。在被要求进行估算时说什么:我等会儿回答你。

    提示19:通过代码对进度表进行迭代。Iterate the Schedule with the Code.

第3章 基本工具

工具放大你的才干。你的工具越好,你越是能更好地掌握他们的用法,你的生产力就越高。要与工匠一样,想着定期添加工具,要总是寻找更好的做事方式。

  1. 纯文本的威力

    提示20:用纯文本保存知识。Keep Knowledge in Plain Text.

    纯文本:

    缺点:与二进制相比,存储纯文本所需空间更大;要解释及处理纯文本文件,计算上的代价可能更昂贵。

    优点:保证不过时:只要数据还在,你就有机会使用它;杠杆作用:计算世界中的每一样工具都能够在纯文本上进行操作;更易于测试。

  2. Shell游戏

    如果你使用GUI完成所有的工作,你就会错过你的环境的某些能力,你将无法使常见任务自动化,或是利用各种可用工具的全部力量;同时,你也无法组合你的各种工具,创建定制的宏工具。GUI的好处是所见即所得,缺点是所见即全部所得。

    注重实效的程序员并非只是剪切代码、或是开发对象模型、或是撰写文档、或是使构建过程自动化——所有这些事情我们全都要做。

    提示21:利用命令Shell的力量。Use the Power of Command Shells.

    去熟悉Shell,你会发现自己的生产率迅速提高。

  3. 强力编辑

    精通一种编辑器。提示22:用好一种编辑器。Use a Single Editor Well.

    确保你选择的编辑器能在你使用的所有平台上使用。如Emacs, vi, CRISP, Brief及其他一些编辑器可在多种平台上使用。

    编辑器特性:可配置/可扩展/可编程

    生产率:只是敲键和使用基于鼠标的剪贴是不够的

  4. 源码控制

    提示23:总是使用源码控制。Always Use Source Code Control

    把整个项目置于源码控制系统的保护之下具有一项很大的、隐藏的好处:自动的和可重复的产品构建

  5. 调试

    要接受事实:调试就是解决问题。

    在技术的竞技场上,你应该专注于修正问题,而不是发出指责。

    提示24:要修正问题,而不是发出指责。Fix the Problem, not the Blame.

    提示25:调试第一准则:不要恐慌。Don’t Panic.

    在开始查看bug之前,要确保你是在能够成功编译的代码上工作——没有警告。

    你也许需要与报告bug的用户面谈,你必须强制地测试边界条件。

    开始修正bug的最佳途径是让其可再现。使你的数据可视化。跟踪。橡皮鸭:向别人解释阐述那些你在自己检查代码时想当然的事情。

    提示26:“Select”没有问题。不要先怀疑是第三方产品的问题

    提示27:不要假定,要证明。

    如果bug是坏数据,看能否进行更好的参数检查是否能更早的隔离它;是否有其他地方受同一个bug影响;如果修正bug需要很长时间,问问你自己能否做点什么让下次修正这个bug变得更容易:测试挂钩或日志文件分析器;如果bug是某人的错误假定结果,与团队讨论这个问题,如果一个人有误解,那么许多人可能也有。

  6. 文本操作

    提示28:学习一种文本操纵语言,如Python,Tcl, Perl

  7. 代码生成器

    提示29:编写能编写代码的代码。Write Code That Writes Code。

    (1) 被动代码生成器:只运行一次来生成结果,结果就变成独立的,它与代码生成器分离了。

    ​ 用途:创建新的源文件;在编程语言之间进行一次性转换;生成查找表及其他在运行时计算很昂贵的资源

    (2) 主动代码生成器:在每次需要其结果时被使用,结果是用过就扔的——它总是能由代码生成器重新生成。例如通过表结构生成的对象和代码文件。

    代码生成不一定要很复杂;代码生成器不一定要生成代码,可以生成几乎任何输出:HTML, xml, 纯文本

第4章 注重实效的偏执

提示30:你不可能写出完美的软件

  1. 按合约设计

    合约可以解读为:如果调用者满足了例程的所有前条件,例程应该保证在其完成时,所有后条件和不变项将为真。

    提示31:通过合约进行设计。Design with Contracts.

    继承和多态是面向对象语言的基石:替换原则:子类必须要能通过基类的接口使用,而使用者无须知道其区别。

    在设计时简单的列举:输入域的范围是什么,边界条件是什么,例程允诺交付什么,例程不允诺交付什么。

    不管发生何种方式的失败,结果都应该是:不处理交易,而不是处理重复的交易。

  2. 死程序不说谎

    提示32:早崩溃。Crash Early.

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

  3. 断言式编程

    提示33:如果它不可能发生,用断言确保它不会发生。If it can’t Happen, Use Assertions to Ensure That It won’t.

  4. 何时使用异常

    提示34:将异常用于异常的问题。Use Exceptions For Exceptional Problems.

    TODO 尝试用C实现异常处理机制:参考

    https://blog.csdn.net/tian_dao_chou_qin/article/details/6386621

    https://www.jianshu.com/p/ccd2c53d1021

    http://www.uml.org.cn/c%2B%2B/201208212.asp

  5. 怎样配平资源

    提示35:要有始有终。Finish What You Start.

    以与资源分配的次序相反的次序解除资源的分配;在代码的不同地方分配同一组资源时,总是以相同的次序分配它们,这将降低死锁的可能性。

    检查配平:(1) 为每种资源类型编写包装,并使用这些包装追踪所有的分配和解除分配;(2) 使用检测内存泄露情况的工具,如Purify和Insure++。

第5章 弯曲,或折断

  1. TODO
  2. TODO
  3. TODO