Redian新闻
>
谷歌用机器人大规模删除代码:二十多年积累了数十亿行,已删除5%C++代码

谷歌用机器人大规模删除代码:二十多年积累了数十亿行,已删除5%C++代码

公众号新闻

编译 | 核子可乐、Tina
来自系统的自动消息:“你的代码死亡已超六个月,建议彻底删除哦。”

任何大型项目都一定会积累下“死代码”,也就是那些不再使用的模块,或者在早期开发期间存在但已经多年没跑过的程序。事实上,很多项目在创建完成后都会先运行一段时间,之后再也无人问津。

这些死代码会继续产生成本:自动化测试系统并不知道哪些代码无需再测,负责大规模清理的人们也会把很多不再运行的代码白白移来挪去。所以虽然这些代码的生产成本很高,但它同时也需要耗费大量时间加以维护。这类维护工作不能轻易跳过,否则未来就一定会造成更大的回溯管理成本。

那么,能不能靠削减代码量来降低维护成本?代码仓库里的内容真的都有存在的必要吗?

谷歌的“死神”项目

我们通常不清理代码,清理它们需要大量的时间和精力,证明其到底还有没有用更是一件麻烦事:我们不能只靠“Chesterton's fence”法则,就是“看不出这个有什么用,那就让我们把它清除掉”, 因为有一些灾难警报、闰年触发代码闲置时间更长,如果被清除了就有可能带来大麻烦。

在谷歌里,代码清除更为艰难。

谷歌跟业界其他公司不同,它只有一个代码仓库,全公司的代码都放在这个库里,二十多年来,上万名软件工程师为同一个包含数十亿行的代码仓库提交贡献。这套代码仓库存储在 Piper 系统当中,与编码相关的共享库源代码、生产服务、实验程序、诊断和调试工具等一切都被集中在这里。

这种开放方法极为强大。如果工程师不确定如何使用某个库,可以通过搜索找到示例;好心的贡献者还可以对整个代码仓库做重要更新,包括转向更新的 API、引入 Python 3 或 Go 泛型等语言特性等。

编写代码对应着极高的成本,所以代码往往被企业视为重要资产。然而,不再使用的代码也会在维护和清理等层面持续耗费时间和精力。一旦代码库达到一定规模,投入工程时间来做自动化清理就开始具有现实意义,特别是像谷歌这样拥有数十亿行代码的情况下。

但在这样的单一代码库的条件下,最坏最坏的情况就是不小心删掉了“源代码”,Google SRE 首席软件工程师说,这种情况“意味着谷歌使用的每个数据中心、每个工作站都会突然停止运行——不仅仅是关闭,甚至连存储都无法使用。(虽然只有在世界末日时才会发生)。”

那么,他们是怎么清理这些死代码的?谷歌最近在其博客中介绍了 Sesenmann“自动删除代码”项目,该项目的目标是自动识别出无效代码,再发送代码审查请求(变更列表)以将其删除

Sesenmann 在德语中代表“死神”的无情收割之义。据谷歌介绍,该项目非常成功,每周可提交超过 1000 个待删除的变更列表,而且截至目前已经删除了谷歌全部 C++ 代码中的 5%。

如何判断哪些代码能删?

谷歌的构建系统 Blaze(即 Bazel 的内部版本)是达成这个目标的关键:它会以一致且可访问的方式表示二进制目标、库、测试和源文件之间的依赖关系,帮助维护者据此建立起依赖关系图。如此一来,大家就能找到未链接至任何二进制文件的库,并将其作为潜在的删除对象。

但这还只是问题的一小部分:那些二进制文件又该如何处理?所有一次性数据迁移程序和已经被弃用的系统诊断工具呢?如果不把它们清理掉,相对应的各个依赖库也将被保留下来。

了解程序是否有用的唯一完美方法,就是检查它们是否正在运行。所以对于内部二进制文件(即运行在谷歌数据中心或员工工作站上的程序),程序在运行时会写入一个日志条目,记录下时间和对应的特定二进制文件。通过汇总,得到谷歌内部所使用的各个二进制文件的活跃度信号。如果一个程序很长时间都没有被用到,该项目就会尝试发送相应的删除变更列表。

当然,其中也有例外:某些程序代码仅仅是 API 的使用示例;有些程序的运行位置根本就没有对应的日志信号。对于凡此种种的各类情况,贸然删除代码肯定会惹出大麻烦。有鉴于此,建立一套阻止屏蔽列表系统就非常重要,可供大家标记异常,避免用虚假的变更列表打扰到已经忙碌不堪的软件工程师。

细节决定成败

在谷歌的博客上,谷歌的工程师 Phil Norman 举了一个简单的例子。

假定有两个二进制文件,它们各自依赖于不同的库,另外还同时共享第三个库。忽略源文件和其他依赖项的话,我们将这种关系绘制成以下结构:

假如 main1 正在使用,但 main2 的最后一次使用却是在一年多之前,那就可以构建起树状传播活动信号将 main1 及其依赖的所有内容均标记为活动。余下的部分则可以去掉;由于 main2 依赖于 lib2,所以这次我们希望在一次变更中同时删除这两个目标:

到目前为止一切顺利,但真正的生产代码需要经过单元测试,其构建目标由测试的库决定。这就让整个遍历结构变得更加复杂:

测试基础设施会运行所有测试,包括 lib2_test,可是 lib2 从未被“真正”执行过。也就是说,我们不能单纯将测试运行作为“活跃度”信号:在这种情况下,可以误以为 lib2_test 保持活动,并导致 lib2 永远存在。只能清理未经测试的代码,而这会严重阻碍清理工作的有效进行。

根本目标是让每个测试都能共享所测试库的使用情况,所以我们可以让库和测试相互依赖来达成这个目标,据此在图中创建循环:

这样就将各个库及其测试转化成了强连接组件,可以使用与以往相同的方法标记出“活”节点,之后寻找有待删除的“死”节点集合。区别在于这次使用了 Tarjan 强连通分量算法来处理循环。

这样做很简单,但前提是能轻松看出测试及所测库之间的关系。遗憾的是,情况并不总是这么乐观。在以上示例中,由于遵循简单的命名约定,所以大家能将测试与库快速匹配起来。但这种方法在实际生产系统中往往并不奏效。

比如以下两种情况:

左边的是 LZW 压缩算法实现,分别存在单独的压缩器和解压缩器库。该测试实际上是对两者都进行测试,以确保数据在压缩和解压缩后不致损坏。在右侧,web_test 负责测试 Web 服务器库,它使用 URL 编码器库来提供支持,但实际上并不会测试 URL 编码器本身。这就希望将左侧的 LZW 测试和两个 LZW 库视为同一连接组件,而在右侧则希望排除掉 URL 编码器,只将 web_test 和 web_lib 视为连接组件。尽管需要不同的处理方式,但这两种情况的基本结构是相同的。在实践当中,可以建议工程师将 url_encoder_lib 之类的库标记为“纯供测试”(即仅用于支持单元测试),这样就能解决 web-test 需求。

除此之外,Phil 表示目前谷歌的方法是使用测试和库名称之间的编辑距离来选择最可能与给定测试相匹配的库。至于如何识别 LZW 这类一项测试对应两个库的情况,这可能需要涉及测试覆盖率数据,谷歌并没有讨论这类方法。

如何消除抵触情绪?

自动代码删除对很多工程师来说可能是个陌生的概念,就如同 20 年前单元测试刚刚诞生一样,那时候很多人对此也抱有抵触态度。

虽然删除死代码最终会给软件工程师自己带来助益,大家也肯定希望管理的代码项目能够保持整洁,但“Sesenmann”运行过程中,谷歌也发现很多工程师并不愿意经常收到用于删除代码的自动变更列表。这就是项目当中社会工程的部分了,而且重要程度丝毫不亚于软件工程。

改变人们的想法需要时间和努力,更需要大量细致的沟通。Sensenmann 的沟通策略主要分三个部分。

最重要的就是变更描述,这也是审查人员首先看到的内容。变更描述必须简明扼要,同时又保证能为审查人员提供充分的背景信息以做出正确判断。这样的平衡其实很难达到:内容太短,很多人会找不到自己需要的信息;内容太长,则可能导致满屏文字令人头痛。事实证明,如果能附上标注清晰的支持文档和常见问题解答链接,会大大提高变更描述的易读性和接纳度。

第二部分则是配套文件,这里同样要使用简洁明了的措辞和良好的导航结构。不同的人需要不同的信息:有些人需要保证源代码控制系统中的删除可以回滚,有些人希望了解要如何处理变更造成的负面影响,例如修复对构建系统的误用。通过认真思考和迭代用户反馈,支持文档将成为满足这些需求的宝贵资源。

第三部分是处理用户反馈。有时候,这可能也是最困难的部分:由于负面反馈多于正面反馈,往往就需要冷静的头脑甚至是不少“外交手腕”。总之,务必牢记这些反馈总体上反映出系统改进的最佳方式,尽量让用户更满意、避免未来继续出现类似的负面反馈。

写在最后

Phil 在谷歌博客中讲道,以谷歌的业务规模出发,估计自动删除代码已经为他们带来了数十倍的投入回报,大大节约了维护成本。

自动删除代码需要解决技术和文化这两大难题。在博客中,他总结道,“虽然我们已经在这两个领域取得了显著进展,但仍不能说彻底解决。不过随着改进的继续,自动删除的接纳度会越来越高,产生的积极影响也将越来越大。这笔投资的价值因人而异,如果您也掌握着一个巨大的单体代码仓库,那不妨认真考虑一下。至少在谷歌,将 C++ 代码总量的维护负担降低 5% 已经标志着一场巨大的胜利。”

如果删除代码也能带来巨大的收益,那是否意味着是时候为删除代码行设置 KPI 了?

参考链接

https://testing.googleblog.com/2023/04/sensenmann-code-deletion-at-scale.html

https://news.ycombinator.com/item?id=35755841

声明:本文为 InfoQ 翻译整理,未经许可禁止转载。

今日好文推荐

开发者的好日子要来了?苹果即将在iOS 17迎来大变化

一次电梯故障,“逼得”这个程序员在29岁时写出了 Rust

花8年转型微服务却得不到回报,问题出在哪儿?

拼多多临时决定五一三天假,员工集体退票;字节回应140万美元年薪挖角OpenAI;AI龙头寒武纪裁员,研发员工被逼签字|Q资讯

活动推荐

口碑好课|Flutter 核心技术与实战

Flutter 是 Google 推出的全新跨平台移动开发框架。因为出色的性能、高效的开发方式等原因,Flutter 正被越来越多的开发者和组织采用,比如阿里巴巴、腾讯、京东、美团等。

前美团点评高级技术专家陈航,将通过对比其他框架的特性,深挖 16 个 Flutter 常见开发问题,带你从 0 到 1 搭建 Flutter 混合开发框架,实现快速掌握 Dart 语言核心特性实战,沉浸在 API 的参数和实现细节中。

现有限时特惠活动,原价 ¥99,老用户 7 折 ¥69 到手,新用户 ¥59 抢购,速戳阅读原文链接或扫码抢👇

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
男人出差归来,知道妻子和闺蜜在家,看看门口鞋,他抓下闺蜜假发德国已经用机器人种地了?!二十多年过去,我终于可以放肆地笑出声了世界首例|阜外医院窦克非团队成功应用微亚医疗血管手术机器人完成世界首例全程机器人辅助冠状动脉造影谷歌用MEMS开关,推动数据中心革命!希腊罗德岛(Rhodes),面纱揭开她以为鼻窦炎!美国医生丈夫“砒霜”杀妻,二十多年婚姻抵不过一夜情「桥田智能」完成数千万元天使轮融资,利用机器人末端产品实现制造业柔性化生产最后一公里丨早起看早期与小15岁女友分手后,又牵手刘晓庆的伍卫国,如今选择不婚不育玩转巴黎 | 二十多年来首次!它提前了!!2023最新Nuit Blanche活动推荐美食坊海鲜阁粤式饮早茶扎根职教二十多年,关于落实职业教育法,这位代表这样说|代表委员@你南澳散记 (增订本) :第二十四章:吃蟹杂谈机器人会“遁地术”?意大利理工学院蚯蚓仿生机器人可用于探索和救援二十多年过去了,怎么又是微软唱主角?【2023CMEF】大零号湾骨科手术机器人专题高峰论坛:行业大咖齐聚,共话骨科手术机器人未来耗时两年,谷歌用强化学习打造23个机器人帮助垃圾分类特斯拉人形机器人最新酷炫演示!马斯克:人形机器人需求将超过汽车不只是黑盒测试:测试工程师如何识别和消除代码坏气味?ChatGPT成了机器人大脑?机器人的下一个大风口是...懒人福音!谷歌让机器训练机器,用大语言模型定制专属于你的家务机器人谷歌用ChatGPT训练AI?新的版权风暴来了!达拉斯地区房价指数十多年来首次同比下跌新松机器人:国内机器人技术创新发源地用机器人打75亿通推销电话 电信公司挨告数十家企业参编中国大模型标准;大模型创企获2.5亿美元投资;微软签署数十亿美元AI算力协议丨AIGC大事日报16万人史上最大规模﹗加拿大移民局4月中全体罢工﹗这些服务全受影响!积压十多年未处理过文件? !A轮融资1200万欧元,“手术机器人之父”称其产品为全球采血机器人的新标准【海外案例】哈佛大学用这15张图,教育了数十亿人瞄准基层医疗数字化市场,这家企业历时4年积累数万家付费客户谷歌用ChatGPT训练AI,新时代的版权风暴更复杂了!杭州小伙用Griefbot「复活」祖父,目前已删除:不想过度依赖AI众拓机器人:用匠人精神铸造德标桁架机器人公司宣传“员工通宵加班致流产”?工作人员回应:已删除文章,不存在此事震惊!澳国防军被指控浪费数十亿澳元!数十架战机停在美军基地吃灰!
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。