30 秒看懂
Artie Shevchenko 与 Titus Winters 对谈《Code Health Guardian》背后的思想。他们区分不同的复杂性问题,讨论如何审查生成代码,并把智力掌控、测试和不可变性与长期可维护性联系起来。
- 1三类复杂性问题变更放大、认知负荷和未知的未知带来不同的维护风险。
- 2具体分析原因Shevchenko 将笼统的依赖问题拆解为六类更具体的原因。
- 3优先审查难以改变的决策Winters 优先关注接口、存储、模式、框架和依赖。
- 4两种掌控方式理解系统与测试变更提供互补的证据。
- 5默认优先不可变优先使用稳定的值以减少隐藏状态变化,同时保留实际需要的例外。
要点建议
- 区分变更放大、认知负荷和未知的未知,有助于确定复杂性问题的优先级。
- 依赖既有收益也有成本;具体检查接口与依赖问题比一概否定依赖更有用。
- 审查可以优先关注难以改变的决策,包括接口、数据和依赖。
- 理解、测试与证据为管理变更提供互补的掌控方式。
- 默认优先采用不可变性可以降低复杂性,同时保留务实的例外。
按章节阅读整理后的全文
这本书的起源
Shevchenko 将教学、代码审查与早期软件设计著作同自己的写作联系起来。
Titus Winters 欢迎 Artie Shevchenko 来到 GOTO 读书会,讨论《Code Health Guardian》以及 AI 辅助时代人类程序员的角色。Winters 先问他为什么写这本书。
Shevchenko 说,他一直喜欢分享知识,帮助学生为未来挑战做准备。他在 Google 开发过内部代码审查课程,超过 1,000 名员工参加;反馈让他更有信心继续教学。
John Ousterhout 介绍《A Philosophy of Software Design》的一次演讲也产生了重要影响。Shevchenko 喜欢书中的复杂性模型为常见工程实践提供理论基础。随后多年大学教学和课程迭代又带来了值得分享的新认识。
阅读 Winters 共同编纂的《Software Engineering at Google》后,Shevchenko 注意到实际编码文化中的一些话题只被简要提及。他给 Winters 发了设计文档章节的早期草稿;Winters 回忆说,很高兴看到这个话题被深入讨论。
代码复杂性模型
两位作者讨论三类问题和更具体的复杂性原因。
Winters 询问 Ousterhout 的复杂性框架。Shevchenko 解释三个不同的问题:变更放大,即看似很小的修改扩散到许多位置;认知负荷,即理解代码的困难;以及未知的未知,即开发者缺少发现问题所需的信息。
把这些问题分开有助于确定优先级。Shevchenko 通常认为未知的未知比认知负荷更严重,认知负荷又比普通的变更放大更严重;但他也承认,极大的变更放大会改变排序。
Ousterhout 把复杂性归因于晦涩性和依赖。Shevchenko 保留了三个症状,但写作时重新考虑了原因:依赖可能制造问题,却也是软件的基本构件。Winters 同意,依赖既有收益,也带来维护负担。
Shevchenko 用六个更具体的原因替代笼统的依赖概念:不符合承诺的接口、复杂接口、不熟悉、依赖过多、重复和不稳定的依赖。Winters 指出,每个依赖都有一定成本与风险,但质量差异很大。
审查 AI 生成代码
两人讨论看似合理的输出、人类理解,以及优先审查难以改变的决策。
谈到 AI 时,Shevchenko 认为,看似合理的生成代码本身并不能证明模型理解了代码。这是他对当前模型的看法。他担心完全依赖生成结果会削弱团队对代码库的智力掌控,因此人仍需要验证重要变更。
Winters 说,生成代码乍看通常合理,但如果缺少足够的指令和配套机制,测试可能薄弱,接口也可能有问题。他询问那六类原因是否也可作为 AI 辅助工作的审查清单。Shevchenko 回答说,它们同样适用于人写的代码。
Shevchenko 比较两个考试答案相似的学生:一个理解了内容,另一个只是背熟了材料。这个类比表达了他的担忧:表面上的合理性难以与理解区分,一次有用的回答也未必能推广到另一种情况。
被问到是否逐行审查时,Shevchenko 坦言,他现在更仔细地看测试场景,而不是每一行测试代码,同时仍会审查大部分生产代码。他不确定这种取舍是否正确,也仍在学习如何安排审查优先级。
Winters 说,AI 正在改变开发方式,行业需要重新摸索实践方法;有经验的工程师也应该愿意承认不确定性。他自己优先审查日后最难改变的部分:依赖和框架、状态与存储、API 设计以及数据库模式。
Shevchenko 把接口放在优先列表前列。审查者应检查接口是否作出清晰承诺,以及实现是否真正履行承诺。不良接口既会增加认知负荷,也会制造日后难以发现的未知问题。
掌控、测试与不可变性
测试和理解有助于管理变更,而不可变性可以减少晦涩性。
Winters 区分智力掌控和统计掌控:前者是充分理解系统、能够推理变更;后者借助测试、证据和实验,即使无法解释每个因果细节,也能对变更安全性建立信心。两人认为这些工具可以互补。
Shevchenko 说,他的书推荐读者参阅《Software Engineering at Google》,获取更全面的测试讨论。在他的复杂性模型中,测试有助于验证接口履行承诺,并减少未知破坏未被发现的机会;类型系统和断言也有帮助。
谈到读者反馈时,Shevchenko 解释,他把最重要的思想放在前面,因为读到开头章节的人通常多于读到后面章节的人。他特别提到随时间演进的软件工程、复杂性模型和契约式设计。
Winters 请他介绍半函数式编程。Shevchenko 将其描述为默认优先采用不可变性,这是一种已有实践,并非他的发明。不可变值减少了追踪变量由谁、何时修改的需要,从而降低晦涩性。
他并不主张不计代价地让所有东西不可变。走向极端可能损害可读性;可变状态仍有用武之地。他建议把不可变作为强默认值,同时保留务实的例外。
Winters 把这个问题与测试联系起来:无状态代码更容易测试;读取状态的代码需要有代表性的状态;既读又写状态的代码则需要谨慎设置和安排顺序。可变状态引入了软件工程必须管理的时间维度。
对话最后,Shevchenko 感谢 Winters 的鼓励以及为书写序。两人都强调,AI 辅助开发的实践仍在演进。
同频道的其他文章
42:40EN → 简体中文
44:42EN → 简体中文
51:06EN → 简体中文
40:04EN → 简体中文
51:06EN → 简体中文
20:04EN → 简体中文