go 2025年1月1日

The Rules of Programming

编程规则:如何编写更好的代码
书籍封面

The Rules of Programming

作者:Chris Zimmerman 出版日期:2023-01-17 出版社:O'Reilly Media
书中作者结合其在微软和Sucker Punch游戏公司的编程团队管理经验,总结出一系列编程原则,旨在帮助程序员编写更简洁、易于测试和维护的代码。这些原则涵盖了代码简洁性、算法选择、测试策略、团队协作、代码审查以及代码重构等多个方面,并通过具体的代码示例和案例分析进行阐述。 书中还讨论了如何处理代码复杂性,以及如何平衡渐进式改进和彻底重构之间的关系。

这份规则摘自克里斯·齐默曼的《编程规则:如何编写更好的代码》一书。书中作者结合其在微软和Sucker Punch游戏公司的编程团队管理经验,总结出一系列编程原则,旨在帮助程序员编写更简洁、易于测试和维护的代码。这些原则涵盖了代码简洁性、算法选择、测试策略、团队协作、代码审查以及代码重构等多个方面,并通过具体的代码示例和案例分析进行阐述。 书中还讨论了如何处理代码复杂性,以及如何平衡渐进式改进和彻底重构之间的关系。

以下是对《编程规则》一书中每一条规则的总结:

  • Rule 1. 尽可能简单,但不能过于简单 (As Simple as Possible, but No Simpler)

    • 核心思想:代码应尽可能简单,但不能为了简单而牺牲必要的功能和清晰度 (Code should be as simple as possible, but not simpler than necessary).
    • 要点:
      • 目标是在避免不必要的复杂性确保代码完整解决问题之间找到平衡点.
      • 代码应该易于理解和维护.
      • 这个规则是本书中其他规则的基础.
  • Rule 2. 错误是会传染的 (Bugs Are Contagious)

    • 核心思想:一旦代码中存在错误,人们就会无意中编写依赖于这个错误的代码,使得修复错误更加困难 (Once a bug exists, people will unintentionally write code that relies on that bug).
    • 要点:
      • 越早发现错误,修复就越容易.
      • 依赖于错误的代码可能出现在附近,也可能出现在上游或下游的代码中.
      • 这使得调试和修复变得复杂,因为一个错误可能会导致多个地方出现问题.
  • Rule 3. 好的命名是最好的文档 (A Good Name Is the Best Documentation)

    • 核心思想:好的命名是代码最重要的文档形式,应清晰地表达代码的意图 (The name of a thing is the first and most important documentation you have).
    • 要点:
      • 命名应准确地反映变量、函数或类的作用.
      • 保持命名的一致性至关重要.
      • 避免使用过于简短或难以理解的命名.
      • 机械化的命名规则可以提高代码的一致性.
  • Rule 4. 通用化需要三个例子 (Generalization Takes Three Examples)

    • 核心思想:在尝试通用化之前,至少要有三个用例 (Don’t generalize until you have at least three concrete examples).
    • 要点:
      • 一个例子不足以预测通用模式.
      • 两个例子可能让你对错误的概括更自信.
      • 三个例子能更准确地预测模式,使概括更保守.
    • 实践:在考虑通用化之前,确保至少有三个独立的用例.
  • Rule 5. 稍后优化 (Optimize Later)

    • 核心思想:在没有实际的性能问题之前,不要进行过早的优化 (Don’t optimize unless you have to).
    • 要点:
      • 先编写简单清晰的代码,然后测量性能.
      • 优化应该基于性能分析,而不是猜测.
      • 过早的优化可能会使代码更复杂,难以维护.
  • Rule 6. 代码审查有三个好处 (Code Reviews Are Good for Three Reasons)

    • 核心思想:代码审查对于提高代码质量至关重要 (Code reviews are good for three reasons).
    • 要点:
      • 代码审查可以帮助发现错误和潜在问题.
      • 代码审查有助于促进团队成员之间的知识共享.
      • 代码审查可以提高代码的可维护性.
  • Rule 7. 消除失败情况 (Eliminate Failure Cases)

    • 核心思想:通过设计,使代码难以被错误地使用,而不是仅仅依赖于用户的正确使用 (Make it impossible to use the code incorrectly, rather than merely avoiding incorrect usage).
    • 要点:
      • 使错误用法不可能发生.
      • 利用编译器进行类型检查.
      • 多阶段操作分解为独立的对象.
      • 使用 C++ 模板来实现类型安全的可选参数.
  • Rule 8. 没有运行的代码是没用的 (Code That Isn’t Running Doesn’t Work)

    • 核心思想:未被实际执行的代码是不可靠的,应及时删除或修复 (Code that isn’t running is code that isn’t working).
    • 要点:
      • 强调了测试和实际运行的重要性.
      • 鼓励删除无用代码而不是保留着它.
      • 假设其他部分的代码基本正常运作.
  • Rule 9. 编写可折叠的代码 (Write Collapsible Code)

    • 核心思想:编写易于理解和概括的代码,使得阅读者可以快速理解代码逻辑,避免在细节中迷失 (Code should be written to collapse easily into a few memorable ideas).
    • 要点:
      • 使用抽象来简化复杂逻辑.
      • 考虑人类短时记忆的限制,尽量减少读者需要同时记住的内容.
      • 代码应该具有良好的可读性,方便快速理解.
  • Rule 10. 局部化复杂性 (Localize Complexity)

    • 核心思想:将复杂性限制在尽可能小的范围内,避免复杂性扩散到整个代码库 (Limit the scope of complexity as much as possible).
    • 要点:
      • 封装复杂逻辑,避免在多个地方重复实现.
      • 保持接口的简洁和一致性.
      • 通过抽象和封装来减少代码的理解难度.
  • Rule 11. 它好两倍吗? (Is It Twice as Good?)

    • 核心思想:只有当重构后的系统比现有系统好两倍时,才值得进行大规模重构 (Don’t tear up something to replace it with something marginally better; that’s a bad strategy. Tear something up to replace it with something much better. Twice as good).
    • 要点:
      • 重构是一项有风险的活动,只有当收益足够大时才值得进行.
      • 如果收益不明显,则应采取增量式改进.
      • 在架构改变时,需要考虑是否值得彻底重构.
  • Rule 12. 大型团队需要强大的约定 (Big Teams Need Strong Conventions)

    • 核心思想:大型团队需要严格的约定,以确保代码的一致性和可维护性 (Big teams need strong conventions to ensure consistency and maintainability).
    • 要点:
      • 团队应采用统一的命名、格式化、错误处理和代码组织约定.
      • 约定可以减少理解代码的认知负担.
      • 统一的约定可以提高团队的效率和合作.
  • Rule 13. 找到引发雪崩的鹅卵石 (Find the Pebble That Started the Avalanche)

    • 核心思想:调试的关键在于找到导致问题的根本原因,而不是仅仅关注表面现象 (The key to debugging is finding the root cause, not just the surface symptom).
    • 要点:
      • 减少状态可以更容易定位问题.
      • 通过断点和单步调试来定位错误.
      • 如果问题的根本原因在代码附近,就很容易被发现.
  • Rule 14. 代码有四种类型 (Code Comes in Four Flavors)

    • 核心思想:根据问题和解决方案的复杂程度,代码可以分为四种类型 (Code can be classified into four types based on the complexity of the problem and solution).
    • 要点:
      • 简单问题,简单解决方案
      • 简单问题,复杂解决方案
      • 复杂问题,复杂解决方案
      • 复杂问题,简单解决方案
    • 强调了优秀程序员应追求使用简单方案解决问题.
  • Rule 15. 拔掉杂草 (Pull the Weeds)

    • 核心思想:及时清理代码中的小问题,避免它们累积成大问题 (Pull out small problems in the code as they come up, to prevent them from accumulating into larger issues).
    • 要点:
      • 清理不一致的命名、过时的注释和拼写错误.
      • 删除无用代码,保持代码的整洁.
      • 即使是小问题,也值得花时间去修复.
  • Rule 16. 从结果出发,而不是从代码出发 (Work Backward from Your Result, Not Forward from Your Code)

    • 核心思想:在编写代码时,先考虑期望的结果,然后反向推导出实现方法 (Start with the desired result, and then reason backward to figure out how to achieve it).
    • 要点:
      • 最终目标出发,设计代码的结构.
      • 不要过早地陷入细节.
      • 使用清晰的数据结构来组织代码.
  • Rule 17. 有时更大的问题更容易解决 (Sometimes the Bigger Problem Is Easier to Solve) * 核心思想:有时,解决一个更通用的问题比解决一个特定问题更容易 (Sometimes, solving a more general problem is easier than solving a specific one). * 要点:

    • 如果遇到难以解决的特定问题,考虑是否可以推广到更通用的情况.
    • 更通用的解决方案可能更简单、更优雅.
    • 并不总是要使用通用的解决方法, 而是寻找最简单的方法.
  • Rule 18. 让你的代码自己讲述故事 (Let Your Code Tell Its Own Story)

    • 核心思想:代码应该具有良好的自解释性,通过清晰的结构、命名和格式化来表达意图,减少对注释的依赖 (Code should be self-explanatory, with the structure, naming, and formatting clear to explain the intent, instead of relying on comments).
    • 要点:
      • 使用有意义的变量和函数名.
      • 通过空格和缩进组织代码结构.
      • assert来验证代码的假设,而不是用注释.
  • Rule 19. 并行重构 (Rework in Parallel)

    • 核心思想:在重构代码时,并行进行,即保留旧代码的同时逐步引入新代码 (When refactoring code, do it in parallel, keeping the old code while introducing the new).
    • 要点:
    • 使用适配器模式在旧代码和新代码之间切换.
    • 通过运行时标志控制新旧代码路径.
    • 逐步迁移到新代码,降低风险.
  • Rule 20. 做数学 (Do the Math)

    • 核心思想:在做出决策时,应该进行数学计算,而不是依赖直觉 (You should do the math in a decision rather than relying on intuition).
    • 要点:
    • 权衡自动化带来的成本和收益.
    • 使用实际的数据,而不是估计.
    • 考虑所有相关的因素.
  • Rule 21. 有时你只需要敲钉子 (Sometimes You Just Need to Hammer the Nails)

    • 核心思想:编程有时需要直接和实际的解决方案,不要过度设计 (Sometimes, programming requires direct and practical solutions without over-engineering).
    • 要点:
    • 并非所有问题都需要复杂的抽象或算法.
    • 有时候,简单直接的代码就足够了.
    • 不要为了追求完美而过度设计.