html代码压缩-微软利用机器人大规模删除代码:20多年累计数十亿行,删除了5%的C++代码

2023-08-29 0 299 百度已收录

编译|核可乐、蒂娜

系统手动提示:“您的代码已失效六个月以上,建议彻底删除。”

任何一个小项目都必然会积累“死代码”,即不再使用的模块,或者早期开发时存在但多年没有运行的程序。 事实上,很多项目创建后运行了一段时间,然后就没有人关心它们了。

这些死代码继续产生成本:手动测试系统不知道哪些代码不需要重新测试,负责大规模清理的人员会移动大量不再工作的代码。 因此,尽管该代码的生成成本很高,但维护起来也需要大量时间。 这类维护工作是不能轻易跳过的,否则势必会导致日后更大的追溯管理成本。

那么,我们是否可以通过减少代码量来降低维护成本呢? 代码仓库里的内容真的有必要吗?

微软的“死神”项目

我们一般不会清理代码,清理需要花费大量的时间和精力,而且要证明它是否仍然有用就更麻烦了:我们不能仅仅依靠“切斯特顿栅栏”定律,那就是,“我不明白这个有什么用,那我们清理一下吧” 由于一些灾难警报和闰年触发代码闲置时间较长,如果清理掉,可能会造成大麻烦。

在微软,代码消除更加困难。

微软与业内其他公司不同。 它只有一个代码仓库,整个公司的代码都放在这个仓库里。 20多年来,数以万计的软件工程师向同一个包含数十亿行的代码仓库提交了贡献。 这个代码仓库存放在Piper系统中,所有与编码相关的东西,包括共享库源代码、生产服务、实验程序、诊断调试工具等都集中在这里。

这些开启方式都是极其强大的。 如果工程师不确定如何使用某个库,可以通过搜索找到示例; 善意的贡献者还可以对整个代码存储库进行重要更新,包括转向更新的 API、引入 Python3 或 Go 库等语言功能等。

编写代码对应着极高的成本,因此代码往往被企业视为重要资产。 然而,不再使用的代码在维护和清理方面也仍然需要时间和精力。 一旦代码库达到一定规模,投入工程时间进行手动清理就开始有意义,特别是在像 Microsoft 这样的数十亿行代码的情况下。

但在这样单一代码库的条件下,最坏的情况就是不经意间删除了“源代码”,按照谷歌SRE首席软件工程师的说法,“意味着微软使用的每一个数据中心、每一个工作站都将被删除”。突然停止运行——不仅仅是关闭,甚至使存储变得难以访问。(尽管这只发生在世界末日)。”

那么,他们如何摆脱死代码呢? 微软最近在博客中介绍了 Sesenmann 的“自动代码删除”项目,该项目旨在手动识别无效代码并发送代码审查请求(更改列表)以将其删除。

塞森曼在英语中代表着“死神”的无情收割。 据微软称,该项目特别成功,每周提交超过 1,000 个需要删除的变更列表,迄今为止已经删除了所有 Microsoft C++ 代码的 5%。

如何判断哪些代码可以删除?

Microsoft 的构建系统 Blaze(即 Bazel 的内部版本)是实现这一目标的关键:它以一致且可访问的形式表达了两个补充目标、库、测试和源文件之间的依赖关系,帮助维护人员构建依赖关系图形。 这样,您可以找到未链接到任何 2 的补码文件的库作为潜在的删除候选者。

但这只是问题的一小部分:如何处理这两个补文件? 所有一次性数据迁移程序和长期弃用的系统诊断工具又如何呢? 如果不删除,相应的依赖库也会保留。

了解程序是否有用的唯一完美方法是检测它们是否正在运行。 所以对于内部补码文件(即运行在微软数据中心或者员工工作站上的程序),程序运行时会写入一个日志条目,记录时间和对应的具体补码文件。 通过归纳,得到微软内部使用的各补码文件的活动信号。 如果某个程序长时间没有使用,项目也会尝试发送相应的删除变更列表。

事实上,也有例外:个别程序代码只是API使用的示例; 有些程序根本没有相应的日志信号。 对于像这样的各种情况,大量的代码删除势必会造成很大的麻烦。 考虑到这一点,拥有一个抑制列表系统非常重要html代码压缩,它可以让您标记异常并防止您已经很忙的软件工程师受到虚假变更列表的干扰。

细节决定成败

在微软博客上,微软工程师Phil Norman给出了一个简单的反例。

假设您有两个补码文件,每个文件都依赖于不同的库,并且还共享第三个库。 忽略源文件和其他依赖关系,我们将这些关系概括为以下结构:

如果 main1 正在使用,但 main2 最后一次使用是在一年多前,那么可以构建一棵树来传播活动信号,将 main1 及其依赖的所有内容标记为活动的。 其余的可以去掉; 由于 main2 依赖于 lib2,这次我们希望在一次更改中删除两个目标:

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

测试基础设施运行所有测试,包括 lib2_test,但 lib2 永远不会“真正”执行。 也就是说,我们不能简单地使用测试运行作为“活跃”信号:在这些情况下,lib2_test 可能会被误认为保持活动状态,并导致 lib2 永远存在。 只有未经测试的代码才能被删除,这严重阻碍了删除的有效性。

基本目标是每个测试共享被测库的使用,因此我们可以通过使库和测试相互依赖来实现这一点,并相应地在图中创建循环:

这将各个库及其测试变成强连接的组件,其中可以像前几年一样标记“活”节点,然后可以找到一组要删除的“死”节点。 不同的是,这次使用了Tarjan强连通分量算法来处理循环。

这很容易做到,但前提是测试和被测库之间的关系可以很容易地看到。 不幸的是,情况并不总是那么开放。 在上面的示例中,您可以通过遵循简单的命名约定快速将测试与库匹配。 然而,这些方法在实际生产系统中往往效果不佳。

例如以下两种情况:

左边是LZW压缩算法的实现,具有单独的压缩器和解压缩器库。 该测试实际上是对两者进行测试,以确保压缩和解压后数据不被损坏。 左边的web_test负责测试Web服务器库,它使用URL编码器库进行支持,但实际上并不测试URL编码器本身。 这希望将 LZW 测试和两侧的两个 LZW 库视为相同的连接组件,而右侧则希望排除 URL 编码器,仅将 web_test 和 web_lib 视为连接组件。 尽管需要不同的方法,但这两种情况的基本结构是相同的。 在实际应用中,可以建议工程师将url_encoder_lib这样的库标记为“纯粹用于测试”(即仅用于支持单元测试),从而解决Web测试的需求。

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

如何摆脱排斥心理?

手动删除代码对于很多工程师来说可能是一个陌生的概念,就像20年前单元测试诞生一样,当时很多人也对此感到排斥。

虽然删除死代码最终会给软件工程师自己带来希望,你也当然希望自己管理的代码项目干净整洁,但在“Sesenmann”的运营过程中,微软也发现很多工程师并不乐意频繁收到请求删除。 删除代码的手动更改列表。 这是该项目的社会工程部分,但其重要性并不亚于软件工程。

改变人们的看法需要时间和精力,更不用说大量细致的沟通。 森森曼的传播策略主要分为三个部分。

最重要的是变更描述,这是审阅者首先看到的。 变更描述必须简明扼要,同时确保能为评审者提供足够的背景信息以做出正确的判断。 这样的平衡似乎很难实现:如果内容太紧,很多人就找不到自己需要的信息;如果内容太紧,很多人就找不到自己需要的信息; 如果内容太长,可能会导致屏幕上的文字令人眼花缭乱。 事实证明,当变更描述附有明确标记的支持文档和常见问题解答链接时,变更描述的易读性和接受度会大大提高。

第二部分是支持文档,这里也使用简单明了的语言和良好的导航结构。 不同的人需要不同的信息:有些人需要确保源控制系统中的删除可以回滚,有些人想知道如何处理更改的负面影响,例如修补构建系统的误用。 通过仔细考虑和迭代用户反馈,支持文档将成为满足这一需求的宝贵资源。

第三部分是处理用户反馈。 有时,这也可能是最难的部分:由于负面反馈少于正面反馈,因此通常需要冷静的头脑,甚至需要大量的“外交脖子”。 不管怎样,不一定要记住,这种反馈一般反映的是改进系统的最佳方式,尽量让用户更满意,避免以后出现类似的负面反馈。

写在最后

菲尔在微软博客中表示,考虑到微软的业务规模,恐怕手动删除代码已经给他们带来了数十倍的投资回报,并大大节省了维护成本。

手动删除代码需要解决技术和文化两大困境。 他在博客中总结道,“虽然我们已经在这两方面取得了显着的进展,但仍然不是一个完整的解决方案。但是,随着改进的不断进行,手动删除的接受度会越来越高,由此产生的积极的影响也会越来越大,这项投入的价值因人而异,如果你也有庞大的单体代码仓库,不妨认真考虑一下,至少在微软,维护负担总数C++ 代码数量增加 5% 已经标志着一个巨大的胜利。”

如果去除代码也能带来巨大的利润,是否意味着是时候为去除代码行设定一个KPI了呢?

参考链接:

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 html html代码压缩-微软利用机器人大规模删除代码:20多年累计数十亿行,删除了5%的C++代码 https://www.wkzy.net/game/171090.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务