书 · 1993 · 史蒂夫·麦康奈尔

《代码大全》

计算机与 AI书单第 21 名

一句话结论

好程序来自对复杂度、错误和变更的持续控制,而不只是把功能写到能运行。

值不值得读完整本?

值得读完整本,但不必每章同样用力。它把设计、编码、测试和维护连成一套工作方法,能帮助已经会写程序的人理解怎样把程序写可靠;旧语言和旧工具的细节可以略读。

  • 以下章节号均按1993年初版。先读第1至3章,弄清软件构建的范围及其前提,再读第4至7章,掌握例程和模块的设计。
  • 接着读第23至28章,理解质量保障、审查、单元测试、调试、集成和性能调优策略;这是从“写出来”走向“交付得了”的关键。
  • 第8至19章按数据、控制流程、排版和注释的主题阅读。可以跳过已经熟悉的语言语法说明,但别跳过变量作用域、初始化、复杂条件和代码可读性的理由。
  • 第20至22章关注工具、项目规模和构建管理,第30至32章关注演化、个人习惯和全书原则;过时的具体工具介绍可略读。
  • 配合一个小项目练习:设计模块接口、用伪代码展开一个例程、做一次代码审查、补边界测试、分步集成,再测量一次性能。准备考试时,应能解释这些步骤分别防止什么问题。
  • 若要购买用于今天工作的版本,可优先考虑2004年第二版;作者官网也明确更推荐第二版。不要混用两版的章节号。

核心观点

1. 软件构建不只是敲代码,准备工作决定返工多少

构建包含详细设计、编码、调试、单元测试和集成。动手前应检查问题定义、需求与架构是否足以支撑当前工作。

为什么:代码会把需求和设计中的假设变成具体依赖。如果假设有误,继续编码只会让更多模块依赖它。等到系统测试才发现问题,修改范围就可能从一处说明扩大到接口、实现和测试。提前澄清关键问题因此能减少返工,但这不意味着所有需求从此冻结;变化仍需要被识别和管理。

2. 用抽象、信息隐藏和模块边界控制复杂度

设计的关键是让人每次只需理解有限的一部分。模块内部应围绕明确职责组织,对外则尽量减少依赖并隐藏实现细节。

为什么:人的注意力和记忆有限,无法同时推演整个系统的所有状态。抽象让调用者通过接口理解功能,不必追踪每一行实现。高内聚把相关工作放在一起,低耦合减少理解一个模块时必须知道的外部知识。信息隐藏进一步把容易变化的决定关在边界内,使局部修改较少扩散成全系统修改。

3. 让代码直接表达意图,减少读者需要猜的东西

命名、变量使用、控制流程、排版和注释共同决定代码是否容易理解。写代码时应照顾人的阅读,而不只是满足编译器。

为什么:维护者必须先理解代码,才能判断修改是否安全。含糊的名字、反复改变用途的变量和过深的嵌套,会迫使人记住更多隐含关系。明确表达问题含义,并让相关操作在结构上靠近,可以减少这种推理负担。注释则应补充意图和理由;如果只是重复语句,它会增加阅读量,却没有提供多少信息。

4. 质量需要多种手段配合,调试需要检验假设

审查、测试和调试各有作用,不能指望最后一次测试解决全部质量问题。发现故障后,应系统定位原因,再修复并验证。

为什么:不同方法能看见不同类型的缺陷:审查可以检查意图与结构,测试可以观察实际行为。只靠作者自己阅读或只运行正常输入,都容易留下盲区。错误越早发现,依赖错误结果的后续工作通常越少。调试时先重现故障、提出解释并用实验排除解释,比同时修改多处更容易确认真正原因,也更容易判断修复是否有效。

5. 逐步集成并管理变更,让系统持续保持可理解

应把系统逐步组装起来,并有意识地管理后续修改。程序不是各部分分别写完后自然就能拼好的成品。

为什么:模块单独运行正确,不代表它们对接口、数据格式和调用顺序的理解一致。一次合入大量代码,会同时引入许多可能的故障来源,使定位困难。每次增加较小的一部分,就能较快发现接口误解,并缩小排查范围。配合版本和变更管理,团队才能知道正在运行的究竟是哪套代码,以及问题可能由哪次修改引入。

6. 靠测量和判断改进程序,不把经验规则当教条

性能调优应先确认目标和瓶颈,再选择改动并测量结果。更广泛地说,程序员需要谦逊、求证,并按项目条件选择实践。

为什么:看起来耗时的代码未必占据主要运行时间,凭直觉修改可能花费很多精力却没有明显收益。算法、数据组织或系统设计的改变,也可能比局部语句技巧更有效。局部调优还可能损害可读性,因此必须比较实际收益与维护代价。同样,项目规模和约束会改变某种做法的成本,好的工程判断需要持续检查自己的假设。

反对意见

变更成本可以被主动压低,前期准备不宜无限扩大(肯特·贝克)

贝克在《Extreme Programming Explained: Embrace Change》中挑战“修改成本必然随时间急剧上升”的假设:自动化测试、简单设计、重构和频繁集成,可以降低后续修改的代价,因此不必提前实现尚未证实需要的灵活性。与麦康奈尔相比,他更强调通过短反馈周期处理不确定性。分歧在于准备多少、何时决策;麦康奈尔也承认需求会变化,不能把本书理解成全面设计完成后才能编码。

测试能够发现错误,却不能证明没有错误(艾兹赫尔·戴克斯特拉)

戴克斯特拉在《The Humble Programmer》中主张,让正确性证明与程序一起形成,并以可推理的结构引导设计,而不是先完成程序再主要依赖测试增加信心。这比本书以多种工程实践降低缺陷的路线提出了更强的正确性要求。这是方法上的对照,不是他对1993年这本书的直接评论;麦康奈尔也没有声称测试能证明程序完全正确。

清晰代码和方法清单不能保存全部设计理解(彼得·瑙尔)

瑙尔在《Programming as Theory Building》中认为,编程的核心产物还包括程序员对现实问题如何映射到程序的理解。这种理解不能完整地装进代码、文档或规则里;接手者往往需要与原团队共同工作才能获得它。这为本书的手册式知识提出了边界:规范和可读性很有帮助,但不能保证交接成功。这里是编辑安排的观点对读,不是瑙尔直接批评过本书。

相关推荐

导读由 AI 根据公开资料整理,没有读取原书全文,一切以原著为准。导读 Primer 首页