跬步 On Coding

从《软件设计的哲学》谈代码的复杂性与应对

几个月前读完了《软件设计的哲学》这本书,在结合自己多年的工作体会,对于代码的可读性,可维护性有了系统性的体会,然后基于我记录的读书笔记然后经过AI的润色,形成了这篇笔记。希望对你也有所帮助。

读完《软件设计的哲学》,感觉像经历了一次代码的“深度体检”。这本书没有讲解具体的编码技巧,而是从更高的维度帮助我们重新审视代码复杂性的问题,并提出了许多实用的建议。今天,我想结合自己的理解,分享这本书带来的启发。

什么是代码的复杂性?

简单来说,复杂性就是那些让系统难以理解和修改的因素。它不仅仅指代码的行数或逻辑深度,还包括:

  • 难以理解:即便是自己写的代码,过一段时间可能也看不懂,更别提其他人。
  • 修改成本高:一个小改动需要改动多个地方,甚至引发新的问题。
  • 模糊的改动范围:不知道该修改哪些模块才能实现目标,或者不确定修改后是否会引发其他问题。
  • 难以修复的错误:修复一个 bug 可能需要大量时间,还可能引入新的问题。

复杂性的表现形式

复杂性并非抽象概念,它常以以下形式体现:

  • 变更放大:一个简单需求改动需要修改多个模块甚至代码库。
  • 认知负荷:完成一个任务需要了解大量背景知识或复杂细节。
  • 未知的未知:修改代码时,不确定是否会引入新的问题。

复杂性的来源

复杂性通常来源于以下几点:

  • 模块之间的依赖:一个模块的改动可能需要同步修改依赖它的其他模块。
  • 晦涩难懂的代码:不清晰的变量名、函数名以及缺乏注释的逻辑。
  • 文档不足:缺乏解释代码意图和约束的文档。

面对复杂性的两大策略

书中提到了解决代码复杂性的两种核心策略:

  1. 让代码更简单、更直观
    • 通过清晰的命名、简洁的逻辑、规范的实现,让代码易于理解。
  2. 封装复杂性
    • 将复杂逻辑封装起来,通过简洁的接口暴露给外部,用户无需关心内部细节。

如何应对复杂性?

以下是书中提到的一些有效方法:

  1. 模块化设计

    • 将系统分解为独立模块,减少模块间的依赖。每个模块应只负责一个明确任务,提供清晰接口。
  2. 抽象

    • 忽略不重要的细节,只暴露必要的信息。好的抽象能降低认知负荷并提高代码复用性。
  3. 信息隐藏

    • 隐藏模块的内部实现细节,只暴露接口。这样能减少模块之间的耦合,降低修改风险。
  4. 设计通用接口

    • 通用接口能隐藏细节并提高代码复用性。
  5. 专注于任务的知识

    • 设计模块时,应关注任务所需的知识,而非任务发生的顺序。
  6. 注释代码

    • 注释应解释代码的“为什么”,而非“是什么”。例如,描述变量单位、边界条件等。
  7. 清晰命名

    • 使用准确且一致的命名,避免歧义。
  8. 先写注释,再写代码

    • 先用注释明确表达代码意图,然后再实现。
  9. 设计两次

    • 初步完成代码后,重新审视设计,思考是否有更好的接口和实现方式。
  10. 统一规范

    • 制定团队代码规范,保持一致性,提高可读性。
  11. 显式代码优于隐式代码

    • 代码应尽可能清晰易懂,避免晦涩技巧。

危险信号:什么时候该警惕复杂性?

以下是书中提到的一些“危险信号”,遇到这些情况时,需要考虑重构:

  • 浅模块:接口与实现的复杂性相差无几。
  • 信息泄漏:设计决策导致多个模块之间耦合。
  • 时间分解:代码结构依赖操作执行顺序,而非基于信息隐藏。
  • 过度暴露:API 暴露了不常用的功能。
  • 重复代码:相同代码反复出现。
  • 联合方法:两个方法间依赖性强,难以单独理解。
  • 注释重复代码:注释仅重复代码内容。
  • 含糊不清的名称:变量或方法名称传递不了有用信息。
  • 难以描述:需要冗长文档解释变量或方法意图。
  • 非显而易见的代码:代码行为或意图不直观。

软件设计的核心原则

书中总结了以下关键原则:

  1. 复杂性是逐步增加的:从小事做起,持续改进。
  2. 代码跑起来并不够:还需关注可读性和可维护性。
  3. 持续投入改善系统设计:不要忽视代码的长期维护成本。
  4. 模块应该足够深:接口要比实现简单得多。
  5. 简化接口:接口设计应尽可能简化最常见用法。
  6. 通用与专用分离:通用代码与专用代码应明确区分。
  7. 层次分明:不同层次应有不同抽象。
  8. 降低复杂性:始终关注减少认知负荷和模块耦合。
  9. 先设计,再实现:避免仓促决策,多次设计迭代。
  10. 注释不明显内容:好的注释可显著降低认知负荷。
  11. 代码是写给人看的:清晰性优先于实现技巧。

结语

《软件设计的哲学》让我意识到,软件开发不仅是实现功能,更是一门需要深思熟虑的艺术。它提醒我们,代码的核心目标是易于理解和维护。毕竟,代码是写给人看的,其次才是给机器看的。希望这些心得对你有所启发,让我们一起写出更清晰、更优雅的代码!