01 / 导读
导读
引用
Winters, T., Manshreck, T., & Wright, H. (Eds.). (2020). Software Engineering at Google: Lessons Learned from Programming Over Time. O'Reilly Media. Free official edition: https://abseil.io/resources/swe-book
章节概要
第1章:什么是软件工程?
第一部分"论点"只有 Titus Winters 撰写的这一章,它确立了全书的论点:软件工程是"在时间维度上积分的编程"。本章围绕前言提出的三个主题展开:时间与变化、规模与增长、取舍与成本。它提出海勒姆定律(Hyrum's Law:当 API 的用户足够多时,系统的每一种可观察行为都会被某人依赖),并以依赖哈希表遍历顺序的代码为例加以说明,进而论证预期存活多年的代码必须能够承受变化。另外几个例子(编译器升级、"左移"以更早发现问题、分布式构建)展示了哪些政策能随组织扩展、哪些不能;本章最后讨论如何依据数据、先例和论证作出决策。
第2章:如何在团队中良好合作
第二部分"文化"以 Brian Fitzpatrick 关于工程中人的因素的一章开篇。它批评"天才神话"和隐藏未完成工作的习惯,运用早期发现、巴士因子等概念,提出社交互动的三大支柱(谦逊、尊重和信任),并就如何给予和接受批评、如何开展不追究责任的事后复盘给出实用建议。
第3章:知识共享
本章把学习视为组织层面的问题。它认为心理安全是第一位的,然后介绍扩展知识的各种途径:提问、导师制、群聊、邮件列表、内部问答平台、答疑时间、技术讲座、文档以及代码本身。本章以 Google 的 readability(可读性认证)流程结尾,这是一种通过代码评审实现的标准化导师制。
第4章:为公平而工程
本章认为偏见是产品开发中的默认状态,团队必须在工作中融入多元视角和多元文化能力。它以一起公开报道的图像标注失误作为案例,建议挑战既有流程,宁可放慢交付,也不要发布会伤害部分用户的产品。
第5–6章:如何领导团队;规模化领导
第5章区分工程经理、技术负责人和兼任两者的技术负责经理,讨论从个人贡献者转向领导者的过程,并列出反模式(招聘唯命是从的人、忽视表现差的人、把团队当孩子对待)和正面模式(仆人式领导、清除障碍、设定明确目标、关注团队成员的幸福感)。第6章把讨论推广到领导多个团队的人,提出三条准则:始终在决策(识别盲点和取舍,作出决定并迭代)、始终在准备离开(建立能"自动驾驶"的团队)、始终在扩展(保护时间、注意力和精力)。
第7章:衡量工程生产力
文化部分的最后一章介绍 Google 的生产力研究团队如何先判断一个问题是否值得衡量,再用"目标/信号/指标"(GSM)框架选择指标,并检查指标是否覆盖代码质量、工程师注意力、智力复杂度、节奏与速度以及满意度(QUANTS)。一个关于 readability 流程的贯穿示例展示了如何把定性与定量数据结合使用。
第8章:风格指南与规则
第三部分"流程"从 Google 如何编写和维护各语言的风格指南讲起。规则应当物有所值、为读者优化、保持一致并避免容易出错的写法;规则通过由风格仲裁者把关的既定流程修改,并尽可能由错误检查工具和自动格式化工具来执行。
第9章:代码评审
本章介绍 Google 的代码评审流程:每项变更都需要评审者的批准("LGTM"),还需要代码所有者的批准,以及具备该语言 readability 资格者的批准(后两者可以由同一人或作者本人隐含满足)。它列出代码评审的好处(正确性、可理解性、一致性、知识共享、历史记录),以及小变更、好的描述、少量评审者等最佳实践,并区分从全新代码到大规模重构的不同评审类型。
第10章:文档
文档被当作代码来对待:有所有者、要评审、要测试,并纳入同一工作流。本章讨论了解读者、主要文档类型(参考文档、设计文档、教程、概念性文档、入口页面)、文档评审,以及回答"谁、什么、何时、何地、为何"和淘汰过时文档等原则。
第11–14章:测试概述;单元测试;测试替身;大型测试
这四章构成全书最大的一块内容。第11章解释为什么自动化测试使变更成为可能,按规模(小型、中型、大型)和范围对测试分类,介绍"碧昂丝规则"("如果你喜欢它,就该给它加个测试"),讨论代码覆盖率,并讲述 Google 如何通过"厕所里的测试"(Testing on the Toilet)等项目建立测试文化。第12章给出编写可维护单元测试的规则:通过公共 API 测试,测试状态而非交互,测试行为而非方法,测试中不写逻辑,测试代码宁取"DAMP"而非"DRY"。第13章比较真实实现、伪实现(fake)、桩(stub)和交互测试,建议优先使用真实实现,并警告不要滥用 mock。第14章讨论大型测试(其结构由被测系统、数据、操作和验证组成,类型从性能测试到灾难恢复),以及如何避免它们拖慢开发者。
第15章:弃用
流程部分的最后一章认为,移除旧系统往往比构建它们更难;它区分建议性弃用和强制性弃用,并说明如何管理弃用过程:负责人、里程碑、工具,以及维持旧系统运行的真实成本。
第16–17章:版本控制与分支管理;代码搜索
第四部分"工具"从版本控制开始:集中式与分布式系统、长期分支为何有害、基于主干的开发、Google 的单一代码仓库以及"单一版本规则"。第17章介绍代码搜索(Code Search)——Google 用于浏览和搜索整个代码库的网页工具,工程师如何使用它,以及规模带来的设计取舍。
第18章:构建系统与构建理念
本章说明没有构建系统时会出什么问题,对比基于任务和基于制品的构建系统,并介绍 Google 的 Blaze(开源版本为 Bazel),包括封闭式与分布式构建、细粒度模块,以及显式指定版本的外部依赖。
第19–20章:Critique:Google 的代码评审工具;静态分析
第19章逐一介绍一项变更在 Google 评审工具 Critique 中的各个阶段,从创建变更、请求评审到评论、批准和提交,并重点介绍"关注集"(attention set)等功能。第20章说明静态分析怎样才能有效(误报少、修复建议可直接采用、融入代码评审),并介绍 Tricorder 平台。
第21–22章:依赖管理;大规模变更
第21章认为依赖管理比源代码控制更难,考察语义化版本及其局限,并思考廉价的计算资源和测试可能如何改变这个问题。第22章介绍涉及成千上万个文件的大规模变更:为什么原子化变更变得不可能,用于拆分和测试这些变更的基础设施(包括 Rosie 工具),以及把它们合入代码库的流程。
第23–25章:持续集成;持续交付;计算即服务
第23章介绍持续集成的概念和 Google 的 TAP 系统,区分快速的提交前检查和较慢的提交后测试。第24章给出持续交付的惯用做法(功能开关、发布列车、分阶段发布、只发布真正被使用的功能)。第25章解释 Google 的 Borg 集群管理系统如何把工作负载的运行标准化,以及为托管计算环境编写软件需要满足哪些要求。
后记
一篇由 Google 工程副总裁撰写的简短后记,重申了全书关于可持续性以及对用户负责的主题。
核心概念
第1章:论点
- 在时间维度上积分的编程:软件工程不仅包括编写代码,还包括在代码整个生命周期内维护和修改它。
- 海勒姆定律:只要用户足够多,系统的每一种可观察行为都会成为某人依赖的东西。
- 左移:在开发流程中更早地发现问题,此时修复成本更低。
第2–7章:文化
- 谦逊、尊重和信任:本书提出的有效团队协作的三大支柱。
- 心理安全:人们可以提问、承认错误的环境,是知识共享的基础。
- Readability:Google 通过代码评审认证工程师掌握某种语言风格的导师制流程。
- 目标/信号/指标(GSM):一种选择指标的框架,使指标可以追溯到团队真正想了解的问题。
第8–10章:风格、评审与文档
- 为读者优化:规则和评审偏向日后易读的代码,而不是写起来快的代码。
- LGTM 与所有权:一项变更需要评审者的批准,也需要受影响代码所有者的批准。
- 文档即代码:把文档放在源代码控制中,配有所有者并经过评审,使其保持最新。
第11–15章:测试与弃用
- 测试规模与范围:按所用资源(小型、中型、大型)和所覆盖代码的多少对测试分类。
- DAMP 而非 DRY:测试代码应当描述清楚、含义明确,即使因此有些重复。
- 真实优先于隔离:先考虑真实实现或伪实现,再考虑桩和 mock。
- 强制性弃用与建议性弃用:用户是被要求还是仅被鼓励迁离旧系统。
第16–25章:工具
- 单一版本规则:开发者在代码库内永远不必在同一依赖的多个版本之间作选择。
- 基于制品的构建系统:声明输出和依赖的构建工具,因而能够封闭、增量、并行地构建。
- 大规模变更(LSC):涉及代码库范围过大、无法原子化提交的变更,被拆分为可独立评审和测试的部分。
- 提交前与提交后测试:在变更合入之前运行快速、可靠的测试,之后再运行较慢的测试。
评析
优点
- 清晰的统一思想。 "工程是随时间推移的编程"这一论点以及时间、规模和取舍三个主题在前言和第1章中提出,并在各章反复出现;因此,关于风格、测试和依赖的政策都是从它们对长期存续代码的影响来解释的,而不是作为规则直接给出。
- 立足于一个组织的实际经验。 每一章都由负责相应实践的 Google 工程师撰写,配有具体故事(哈希顺序引发的错误、测试文化的发展史、弃用行动)以及一些内部数据,例如关于工具满意度的调查结果。
- 兼顾文化、流程与工具。 作为一本工程类书籍,它少见地用整整一个部分讨论团队合作、知识共享、公平、领导力和度量,与代码评审、测试和构建系统并列。
- TL;DR 总结。 每章都以一份简短的要点清单结尾,便于日后回顾,也便于用于讨论。
局限
- Google 特有的规模和工具。 许多工具(Critique、TAP、Borg、Rosie、Code Search)是内部工具,单一代码仓库或单一版本规则等做法依赖大多数组织所不具备的基础设施;前言本身也说明本书并不是让人照搬的方案。
- 很少涉及设计和编程。 按前言的说法,本书不涉及软件设计、API 设计、项目管理、安全加固或用户界面,因此不能充当通用的软件工程教材。
- 各章风格不一,偏随笔体。 由于作者众多,各章深度和语气差别较大,而且没有练习、案例思考题或形式化模型。
- 2020 年的快照。 本书描述的是 2019–2020 年前后的实践和工具,某些细节(如具体工具和组织结构)此后可能已有变化。
在课程中的定位
在本软件工程书单中,Sommerville 的 Software Engineering 是覆盖需求、设计、过程和验证的综合教材,适合作系统性的概览;Software Engineering at Google 适合与它配合使用,作为一家大型组织如何处理维护、测试和工具问题的详细记述。Ousterhout 的 A Philosophy of Software Design 和 Thomas 与 Hunt 的 The Pragmatic Programmer 讨论个人层面的设计与技艺,正是本书明确略去的主题,因此与本书搭配良好。
Bass、Clements 和 Kazman 的 Software Architecture in Practice 以及 Jackson 的 Software Abstractions 分别在架构和形式化建模方面更加深入。有一定业界或实习经验的学生最能从 Winters 等人的书中获益;没有这类经验的学生,先读 Sommerville 或一本入门书可以提供背景。
如何使用本书
本书面向在职工程师、团队负责人以及在团队中写过代码、用过版本控制、测试和代码评审的高年级学生。不要求掌握特定语言,书中的代码只是示意。
各章相对独立,可以有选择地阅读。第1章必读,因为它定义了全书使用的术语。如果是测试方面的课程单元,请按顺序读第11–14章;关注代码质量,读第8、9、19、20章;关注发布工程,读第16、18 章和第21–24章。对领导力或团队实践感兴趣的学生应读第二部分(第2–7章)。第25章要求读者对分布式系统有一定了解。
可以把每章的 TL;DR 清单当作讨论题,并针对每一种实践提出本书自己提出的问题:在读者自己项目的规模和代码生命周期下,这种取舍是否合理?免费的 HTML 版本在 abseil.io 上以知识共享"署名-非商业性使用-禁止演绎"许可发布。
版本与来源
本导读依据 https://abseil.io/resources/swe-book 上发布的 Software Engineering at Google 免费 HTML 版(第一版,O'Reilly,2020)。内容取材于推荐序、前言全文、目录中的各部分划分、全部 25 章(每个小节标题、章节开头、结论和 TL;DR 清单,其中第1章为细读)以及后记。
