程序员修炼之道——通向务实的最高境界(第二版)

第一章 务实的哲学

  • 编程是一门技艺
  • 是什么造就了务实的程序员
    • 早期的采纳者/快速的适配者。对技术和技巧有一种直觉,喜欢尝试。
    • 好奇。倾向于问问题
    • 批判性的思考着:在没有得到证实前很少接受既定的现实
    • 现实主义:理解面临的每个问题的本质。这种现实主义让你对事情有多困难、需要用多长时间有一个很好的感知。
    • 多面手。熟悉各种技术和环境,并努力跟上新的进展。
    • 关注你的技艺。如果你不关心怎么把软件开发好,那么软件开发领域就再也没有什么好谈的事情了。
    • 思考!思考你的工作。为了成为一名务实的程序员,我们要求你在做事的时候,思考一下自己正在做什么。
  • 我活着不是为了满足你的期望,正如你也不是因为我的期望而活着。——李小龙
  • 人生是你自己的,是你在拥有、经营和创造。
  • 你有权选择:你可以去改变组织,或是让自己换一个组织。
  • 在你的职业发展、学习教育,以及你的项目、每天的工作等各方面对你自己负责,对你的行为负责,这是务实哲学的基石之一。一个务实的程序员能完全掌握自己的职业生涯,从不害怕承认无知和错误。
    • 团队信任:你的团队需要能信赖和依赖你——你也应该同样地放心依赖他们每个人
    • 承担责任:责任意味着你对某事积极认同。你保证事情能搞定,并为之做出承诺,但你不必直接掌控事情的每个方面,但是需要分析超出控制范围的风险。
  • 提供选择,别找借口。不要说搞不定,而是需要去找怎么才能挽救这个局面。
  • 破窗效应。不要打破窗户
    • 心理学家研究表明,绝望是会传染的,就像狭窄空间中的流感病毒。无视一个明显损坏的东西,会强化这样一种观念:看来没有什么是能修好的,也没人在乎,一切都命中注定了。所有的负面情绪会在团队成员间蔓延,变成恶性循环。
  • 做推动变革的催化剂。当遇到一个异常复杂糟糕的系统,可以先找出合理的请求,然后不断的完善,一旦有成果产出,展示给人们看,让他们大吃一惊。人们觉得,加入一个推进中的成功项目更容易一些。因为只要一窥未来,大家就能团结在一起。
  • 牢记全景:永远留意着大局,持续不断地审视你身边发生的事情,而不要只专注于你个人在做的事情。
  • 够好的软件:所有系统必须达到用户的需求才算完成,需要达到基本的性能、隐私和安全标准。你做的东西,从用户需求角度来说是否足够好?最好还是留给用户一个机会,让他们能亲自参与评估。
  • 将质量要求视为需求问题
    • 不要过度的修饰和精炼侵蚀掉一个完好的程序。继续前行,让代码在它该有的位置驻留一段时间。它或许并不完美,不要紧的——它就算永不完美也没关系。
  • 投资知识
  • 批判性地分析你读到和听到的东西
  • 交流
    • 了解听众:为了把信息传达,你需要了解受众的需求,兴趣和能力
    • 明白自己想说什么
    • 选择时机
    • 挑选风格:根据听众调整你的表达方式。
    • 让它看起来不错。
    • 让听众参与
    • 做倾听者。如果你不听他们的,他们也不会听你的
    • 回应别人。
    • 文档交流。务实的程序员会把文档视为整个开发过程的一个组成部分。把代码和源码绑定在一起

第二章 务实的方法

  • ETC(Easier To Change):优秀的设计比糟糕的设计更容易变更
  • DRY:不要重复你自己。在一个系统中,每一处知识都必须单一、明确、权威地表达。
  • 让复用更容易。你要努力的方向,应该是孕育出一个更容易找到和复用已有事物的环境,而不是自己重新编写。如果复用不容易,人们就不会这么做。(创造复用条件)如果你未能复用,就有重复知识的风险。
  • 正交性:在计算机科学中,这个术语象征着独立性或解耦性。对于两个或多个事物,其中一个的改变不影响其他任何一个,则这些事物是正交的。
  • 非正交系统天生就复杂,难以变更和控制。当系统的组件相互之间高度依赖时,就没有局部修理这回事。
  • 消除不相关事物之间的影响:当组件批次隔离时,你知道可以变更其中一个组件,而不必担心影响到其他组件。
  • 正交系统的两个主要收益:提高生产力及降低风险
    • 获得生产力
      • 将变更限制在局部后,开发时间和测试时间都会减少。
      • 正交的方法同时促进了重用。
      • 组合正交组件能获得相当微妙的生产力提升。
    • 减少风险
      • 代码中病变的部分被隔离开
      • 获得的系统不那么脆弱。任何问题都限制在局部
      • 正交系统利于测试,因为为其组件设计和运行测试更加容易。
      • 不会被特定的供应商、产品或平台紧紧束缚。
  • 模块化、基于组件和分层
  • 不要依赖那些你无法控制的东西。
  • 编写正交性代码的几种方法:
    • 保持代码解耦:模块不会向其他模块透露任何不必要的信息,也不依赖于其他模块的实现。
    • 避免全局数据:只要代码引用全局数据,就会将自己绑定到共享该数据的其他组件上。
    • 避免相似的函数:
  • 不做最终决定:灵活的架构。
  • 曳光代码:可运行的生产级别代码,可不断优化。原型代码:一次性代码,用完就丢。
  • 估算:所有的估算都是基于对问题的建模。
    • 建模会给估算过程引入不准确性,这不可避免,但也是有益的。你在用模型的简单性来换取精确性。
    • 将模型分解成组件。一旦得到了模型,就可以将其分解成组件。每个组件都有相关的估算
  • 估算项目进度:三个估算值,乐观的、一个最有可能的和一个悲观的估计。
  • 估算时间根据项目进度不断迭代。

第三章 基础工具

  • 将知识用纯文本保存。人类可读形式的数据与自描述数据,会比所有其他形式的数据,以及创建数据的应用程序,更有生命力。
  • 发挥shell命令的威力
  • 加强编辑能力
  • 永远使用版本控制
  • 调试
    • 去解决问题,而不是责备。Bug是你的错还是别人的错并不重要。无论是谁的错,问题仍然要你来面对。
    • 不要恐慌
    • 修代码前先让代码在测试中失败。 对于前期复现步骤很长的bug,不要每次都重头开始去测试。有时,只要强制自己对暴露Bug的环境进行隔离,就能获得对如何修Bug的洞察力。
    • 读一下那些该死的出错信息。二分法找bug

第四章 务实的偏执

  • 你无法写出完美的软件
  • 契约规定了你的权利和责任,同时也规定了对方的权利和责任。
  • 契约式设计:如果调用者满足了例程的所有前置条件,则例程应保证在完成时所有后置条件和不变式都为真。
    • 前置条件:一个例程永远不应该在前置条件被违反的时候被调用
    • 后置条件:例程保证要做的是什么?例程完成时世界的状态。例程有后置条件这个事实,意味着能得出这样的结论——不允许无限循环。
    • 类的不变式:从调用者的角度来看,类会确保该条件始终为真。在例程的内部处理期间,可以不遵守不变式,但是当例程退出并将控制权返回给调用者时,不变式必须为真。
  • 尽早崩溃
  • 使用断言去预防不可能的事情。不要用断言来代替真正的错误处理。断言检查的是不可能发生的事情。
  • 有始有终。理想情况下,分配资源的例程也应该负责释放它。
  • 资源嵌套分配
    • 释放资源的顺序和分配资源的顺序相反。
    • 在代码的不同位置,如果都会分配同一组资源,就始终以相同的顺序分配它们。这将减少死锁的可能性。
  • 小步前进——由始至终,总是采取经过深思熟虑的小步骤,同时检查反馈,并在推进前不断调整。把反馈的频率当做速度限制,永远不要进行“太大”的步骤或任务。

第五章 宁弯不折

  • 解耦代码让改变更容易
  • 只管命令不要询问。这个原则说的是,不应该根据对象的内部状态做出决策,然后更新该对象。这样做完全破坏了封装的优势,并且在这样做时,也会把实现相关的知识扩散到整个代码中。
  • 不要链式调用方法。方法是可变的,对于不可变的,可采用。
  • 继承增加了耦合
  • 编程讲的是代码,而程序讲的是数据。
  • 继承就是耦合。替代方案
    • 接口和协议。尽量使用接口表达多态。
    • 委托
  • 使用外部配置参数化应用程序。如果代码依赖某些值,而这些值在应用程序发布后还有可能改变,那么就把这些值放在程序外部。

第六章 并发

  • 通过分析工作流来提高并发性
  • 随机故障通常是并发问题
  • 用角色实现并发性时不必共享状态。采用消息传递取代共享状态
  • 使用黑板协调工作流。

第七章 当你编码时

  • 务实的程序员会对代码进行批判性思考,包括自己的代码。
  • 编程应该深思熟虑,不要依靠巧合式编程。
    • 时刻注意你在做什么。
    • 能向初级程序员解释自己的代码。
    • 不要在黑暗中编程。构件一个没有完全掌握的应用程序,或者使用一个并不理解的技术,就很可能会被巧合咬伤。
    • 要按计划推进。
    • 只依赖可靠的东西。不依赖假设。如果你不知道某件事是否可靠,就要做最坏的打算。
    • 将假设文档化。
    • 不要只测试代码,还要测试假设。写一个断言来测试假设
    • 为你的精力投放排一个优先级
    • 不要成为历史的奴隶。不要让现有的代码去支配未来的代码。如果不再合适,所有的代码都可以替换。即使一个程序正在进展中,也不要让已经做完的事情限制下一步要做的事情——准备好重构。
  • 评估算法的级别。
  • 对估算做测试。
  • 尽早重构,经常重构
  • 测试是代码的第一个用户。测试驱动编码
  • 为测试做设计。
  • 要对软件做测试,否则只能留给用户去做。
  • 保持代码简洁,让攻击面最小
  • 好好取名;需要时更名

第八章 项目启动之前

  • 无人确切知道自己想要什么。需求一开始是不明确的。
  • 程序员帮助人们理解他们想要什么。完善客户需求,告知用户细节。
  • 需求是从反馈循环中学到的。帮助客户理解他们所陈述需求的后果。
  • 和用户一起工作以便从用户角度思考。
  • 创建详细文档的错误:
    • 客户并不确切知道自己想要什么
    • 客户从不阅读文档。
  • 就需求而言,最简单最能准确反映业务需求的语句是最好的。需求不是架构:需求无关设计,也非用户界面;需求就是需要的东西。
  • 不要跳出框框思考——找到框框。解决谜题的关键是,认识到你所受到的约束和你所拥有的的自由度,因为认识到这些就会找到答案。
  • 跳出自身的局限。当遇到复杂问题,放松大脑。注意力分散的人容易解决复杂问题时比有意识的人做的更好。 放松时潜意识脑在思考。
  • 康威定律:设计系统的架构受制于产生这些设计的组织的沟通结构。
  • 合作性事务的小技巧:
    • 打造代码,而非打造自我。这与谁最聪明无关;我们都有许多闪光的瞬间,也有糟糕的时刻。
    • 从小规模做起,只需要4-5人的群体,或者开始时只组成几对,做一些短期活动。
    • 批评要针对代码,而不针对人。“让我们看看这一块”听起来比“你搞错了”好得多。
    • 倾听他人的观点并试着理解。观点不同不是错误。
    • 频繁进行回顾,为下一次做好准备。
  • 不要一个人埋头钻进代码中。交流。
  • 敏捷不是一个名称;敏捷有关你如何做事。敏捷宣言:
    • 个体和互动高于流程和工具
    • 工作的软件高于详尽的文档
    • 客户合作高于合同谈判
    • 响应变化高于遵循计划
    • 也就是说,尽管右项有其价值,我们更重视左项的价值。

第九章 务实的项目

  • 维持小而稳定的团队。
  • 对于需要做的事务排上日程。而不是“以后再说”
  • 组织全功能的团队。
  • 自动化是每个项目团队的基本组成部分。确保团队拥有构件工具的技能,以便可以构件和部署工具,用其来将项目开发和生产部署自动化。
  • 务实的入门套件
    • 版本控制
    • 回归测试
    • 完全自动化
  • 使用版本控制来驱动构件、测试和发布。
  • 尽早测试,经常测试,自动测试
  • 直到所有的测试都已运行,编码才算完成。
  • 使用破坏者检测你的测试
  • 测试状态覆盖率,而非代码覆盖率
  • 每个Bug只找一次。
  • 取悦用户,而不要只是交付代码。代码最终是为了解决用户问题而开发的,

对社会和用户

  • 先勿伤害。保护用户不受伤害。
  • 不要助纣为虐。不要创造危害社会的代码。
  • 你要为自己的人生做主,精心营造,与人分享,为之喝彩。好好享受吧!你正在为自己和子孙后代建设未来——这是你的职责所在,去创造一个让所有人心向往之的宜居未来。
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值