写点什么

冗余代码检测与分析

  • 2017-10-09
  • 本文字数:3456 字

    阅读完需:约 11 分钟

本文要点

  • 代码冗余的原因多种多样,从未使用的变量到未完成的变更,再到废弃的代码;
  • 冗余代码会产生一系列的影响,包括源代码臃肿、可靠性及可维护性降低。在某些情况下,死代码也会影响性能;
  • 为了检测冗余代码,作者开发了一个工具,使用 Roslyn 创建 C#源码抽象语法树。作者使用包括 Roslyn 和 MSBuild 在内的多个 GitHub 项目对这个工具进行了训练;
  • 检测到冗余代码可以手动删除或添加注释,也可以使用一种自动化工具。使用特性分支有助于防止冗余代码检入主代码分支。

导言

前段时间,我开发了一款工具,分析源代码中的依赖关系。它使用Roslyn 创建C#源代码抽象语法树使用libclang 创建C++ 源代码抽象语法树。为了验证它是否可以取得预期效果,我接下来实现了识别未使用方法的功能。结果显示,C#代码解析比C++ 代码解析准确得多,因此,我选择把重点放在C#分析器的进一步开发和其他人开发的更复杂的C#代码上。

起初,该工具会标记出冗余方法所在的行,在弄清楚问题范围之后,我实现了自动删除那些行的选项。一个典型的分析过程会多次执行这个工具,尽可能地修剪源代码树。接下来是多个变更还原循环,以便可以成功地构建并通过测试。失败的原因是工具行为异常或者已知的局限性,例如,反射或代码契约。

我选择了多个自己用过而又想回馈的C#项目,用它们的GitHub 库训练了这个工具。最后,我向社区提交了pull request,请求他们讨论我在自己的分支里做的变更。由于这个工具很苛刻,而我又是第一次在网上与人交流,不懂技巧,所以希望我没有冒犯太多的人。在向社区做贡献及参与后续讨论的过程中,我对问题的理解更深入了,本文旨在将我的所得回馈给更广泛的社区。

分析过的GitHub 项目

由JB Evain 编写的 Mono.Cecil 可以将.NET 代码反编译成 C#。根据建议,只有 36 行代码需要删除,经过审核,JB 选择单独添加部分变更,而不是合并分支。

Automatic Graph Layout 是微软官方的一个项目,由 Lev Nachmanson、Sergey Pupyrev、Tim Dwyer、Ted Hart 和 Roman Prutkin 开发,用于绘制图和有向图,Visual Studio 也用它显示各种交互图。Pull request 要求删除 4674 行代码,其中有一些和 SilverLight 有关(已于 2015 年宣布停用)。不经过修改或讨论,分支就被合并了进去。

Roslyn 是一个现代化的 C#编译器,由.NET 基金会的一个团队负责维护。在这个例子下,Pull request 要求删除 18364 行代码,这引发了有益的讨论,并产生了下面讨论的大多数分类。显然,这个分支太大了,无法合并,取而代之,多个单独的议题被提了出来。

MSBuild 是微软官方的一个项目,Visual Studio 的用户应该比较熟悉。根据分析,我提交了删除 3722 行代码的 pull request,遗憾的是,其团队当时没有余力审核我提出的变更建议。

最后分析的是.NET Core 基础库里的System.XML 程序集。这些库由.NET 基金会负责维护,为了删除死代码,其团队发布了一条问题追踪信息。该问题的解决方法是逐个修剪程序集(通常被称为死代码消除),然后比较未修剪程序集和已修剪程序集之间的差异,从而确定哪些编译代码被删除了。通过这些差异可以知道哪些源代码被删除了,这项工作通常是由志愿者社区承担。

鉴于只用该工具抽样分析了五个项目,得出任何结论都是不明智的,尤其是在缺少可靠的统计数据的情况下:

Mono.Cecil MSAGL Roslyn MSBuild CoreFX (System.XML) 已删除 36 4674 18364 3722 427 初次提交时间 2010/04/12 2015/02/22 2014/03/18 2015/03/12 2014/11/08 作者(主要) 39 (1) 25 (4) 285 (31) 90 (6) 526 (29) 鉴于其悠久的历史,MSBuild 的初次提交时间值得注意。仅数一下作者的数量而不评估他们的贡献几乎可以肯定是没有意义的,因此我大致估计了主要的贡献者。说到这里,我推测:

  • 新开发的项目比成熟项目冗余代码多
    • 编写代码时假定将来会需要
    • 测试少,相应的,发现的 Bug 就少
  • 团队越大制造的冗余代码越多
    • 沟通成本会随团队规模的扩大而呈几何级数上升,参见《人月神话

测试结果分类

该工具测试冗余方法,和任何测试一样,分析有成功和失败之分。

真负:

  • 代码有用

假负:

  • 测试代码
    • 测试的功能只有测试使用。这可能是 TDD BDD 过程的产物,在这种情况下,它可能用来追溯不需要或者未满足的需求。
  • 死代码
    • 虽然被调用了,但代码什么都没做,这种调用可以删除。
    • 可以是重复代码
    • 注意,可以认为已废弃代码距离死代码只差一步。

真正:

  • 故意放弃的开发
    • 方法已经添加,但环境变了,这些方法不会再使用了
  • 未完成的变更
    • 代码已变更,有些方法所有引用都删除了,但后续提交时没有将其考虑在内。这种代码有时候称为 oxbow 代码。它可能是重构的意外产物。
  • 未使用的变量
    • 但愿 IDE 会生成编译器警告和 / 或报告。

假正:

  • 工具缺陷
    • 该工具没有检测使用反射代码契约的代码,它依赖构建或测试过程的错误来检测这些代码。
  • 回归
    • 在开发过程中,经过修改,一个方法不再调用标识为死亡的方法,此时,这种情况就会出现。显然,没有测试识别这种回归。
  • 缺少条件编译
    • 通常,这是指缺少#if DEBUG 保护。Roslyn 已经用于 Release 构建,这个过程会识别相应二进制文件中的代码膨胀。
  • 无意放弃的开发
    • 这是在特定的测试数据下发现的,但没有相应的测试。通常来说,我希望这是一个暂时的问题,随着代码增加会自然消失。
  • 在子系统中未使用
    • 分析低效的代码,找出使用该方法的地方。虽然反射也会导致这个问题,但这主要出现在公共方法分析时。一个常见的例子是执行测试辅助功能的时候没有相应的测试代码,不过,那会抛出一个设计问题,定位到测试辅助代码。
  • 仅限调试器使用的方法
    • 在附加了调试器时(可能是 Release 构建),有些项目会有方法打印出状态。这些方法应该以某种方式标记出来,那样就不用分析它们了。

需要注意,工具失败不一定是因为推理不足。其中有些情况是其他工具的处理范畴,如编译器警告应该标记部分问题,重复代码检测器也有用。

冗余代码的影响

假负和真正都可以视为 YAGNI 的实例,这就需要我们注意以下事项:

  • 臃肿的源代码

    • 以前,我遇到过文本编辑器无法打开大文件的情况。
    • 开发人员的认知受限于大脑中可以同时容纳的独立实体的数量,通常认为是 7 个,因此,删除方法可以提升推理能力。
    • 所有开发人员用来阅读和理解源代码的时间很可能都是浪费。
    • 现代 IDE 通常都是从源代码生成抽象语法树,因此,冗余代码降低了它们的速度。
  • 臃肿的可执行文件

    • 在手机上,这尤其是个问题,为了释放存储,升级会删除应用,最终,当功能受到过度损害,就不得不升级设备了。
  • 臃肿的运行时

    • 为黑客提供了更大的攻击面,让他们发现安全问题。
    • 部分面向嵌入式设备的应用程序会在启动时分配所有的动态内存,因此,冗余代码会减少可用堆的大小。
  • 降低性能

    • 在特定的情况下,死代码执行会浪费处理器周期。
  • 降低可靠性

    • 在特定的情况下,死代码执行可能导致崩溃。
  • 降低可维护性

    • 如果执行到冗余代码时停下了,那么行为将不可预测,如 Knight Capital 损失了 4.4 亿美元。
    • 代码覆盖率可能会因假负而升高,因假正而降低。
    • 不必要的测试会降低测试套件的执行速度。
    • 静态分析工具不得不处理更多的代码,并因此效率降低。
    • 软件的设计 / 架构看起来比实际情况复杂。考虑到冗余代码会导致各种各样的问题,最好是将其视为代码异味。

管理已有的冗余代码

处理冗余代码有四种方法:

  • 忽略

    • 虽然会增加维护成本,但至少可以通过编译。
    • 不推荐。
  • 自动从可执行文件中移除

    • 编译型语言在链接器中使用任意一种死代码移除选项移除。
    • 动态语言使用 Tree Shaking 在运行时移除。
    • 也不推荐。
  • 屏蔽

    • 注释掉或者使用预编译指令。
    • 使用 IDE 提供的代码 / 注释折叠避免看到它。
  • 删除

    • 借助源代码控制保留旧版本供参考,可以随时查看。
    • 或者你可能永远不再需要它。

如果要变更源代码,任何变更都需要由熟悉这段代码的人审核,务必保证代码真冗余。

管理新开发项目

假如目标是在开发过程中不引入新的冗余代码,需要制定什么策略?如果允许部分提交,代码库中可能就会增加暂时冗余的代码。这种情况可以通过特性分支来缓解,只有当测试已覆盖且源代码通过了静态分析才合并进主分支。特性分支的另外一个好处就是在放弃开发后可以将分支保持在未合并状态。

关于作者

Zebedee Mason 是一名有着 25 年 CAD/CAM/CAE 行业经验的数值分析员,他最近搬到了 SLAM。多年来,他一直从事与遗留代码库(其中有些在他还是个孩子的时候就已经创建)相关的工作,把许多学术代码改写成商业软件的组件,他甚至还重写了一些原始算法(商业秘密,无法确认)。这种背景使他对软件工具非常了解,他也编写了若干提高生产力的工具,即使以前的开发人员和 IT 管理人员做出了有用的选择。

查看英文原文: Detecting and Analyzing Redundant Code

2017-10-09 18:036066
用户头像

发布了 1008 篇内容, 共 373.7 次阅读, 收获喜欢 340 次。

关注

评论

发布
暂无评论
发现更多内容

如何提高技术领导力?与你分享 5 个心得

LigaAI

程序人生 技术管理 成长与思考 技术领导力 企业号9月PK榜

主动写入流对@ResponseBody注解的影响 | 京东云技术团队

京东科技开发者

spring 注解 企业号9月PK榜 @ResponseBody

数字化转型与架构-架构设计篇|什么是架构风格和架构模式?

数字随行

数字化转型

集成学习方法——随机森林

小魏写代码

教你用API插件开发一个AI快速处理图片小助手

华为云开发者联盟

人工智能 华为云 华为云开发者联盟 企业号9月PK榜

慢SQL治理实践及落地成果分享 | 京东物流技术团队

京东科技开发者

数据库 sql 慢SQL 企业号9月PK榜

在加密货币交易所开发中使用人工智能和机器学习

区块链软件开发推广运营

交易所开发 数字藏品开发 dapp开发 区块链开发 NFT开发

什么是隧道代理、http代理,隧道代理较于http代理有什么优势?

巨量HTTP

代理IP http代理

文心一言 VS 讯飞星火 VS chatgpt (96)-- 算法导论9.3 1题

福大大架构师每日一题

福大大架构师每日一题

Unite for Mac(将网站转化为应用程序) v4.6中文激活版

mac

苹果mac Windows软件 Unite 应用程序转换工具

国庆机酒预订又快又便宜?内附华为Mate60负一屏抢购攻略

最新动态

中国机械总院张红新:强化集团级数据治理 业财融合助力企业降本增效

用友BIP

2023全球商业创新大会

中国广核集团智慧司库系统票据业务成功上线!打造票据数智管理新标杆!

用友BIP

全球司库

Microsoft word 2019 for Mac v16.78 beta中文激活版

mac

windows 办公软件 苹果mac Word 2019 文字处理软件

对话在行人|厦门航空:紧抓数智化转型关键因素实现业财融合

用友BIP

2023全球商业创新大会 对话在行人

软件测试/测试开发丨利用人工智能ChatGPT批量生成测试数据

测试人

人工智能 程序员 软件测试 ChatGPT 测试数据

聚焦企业开放OpenAPI痛难点,华为云API Explorer助力构建API门户

华为云开发者联盟

软件开发 华为云 华为云开发者联盟 企业号9月PK榜

快手发布文生图大模型“可图”,探索AI新玩法

Geek老T

短视频 AIGC

专业级PDF编辑和管理 Acrobat Pro DC 2023 for Mac

胖墩儿不胖y

Mac软件 pdf编辑器 编辑pdf pdf工具

Web3.0时代的全新合作模式:DAO | 京东云技术团队

京东科技开发者

区块链 DAO Web3.0 企业号9月PK榜

百度集团副总裁吴甜:大语言模型面临三大技术挑战

飞桨PaddlePaddle

文心一言 文心大模型

修旧利废,提升净资产收益率

用友BIP

资产管理

行云管家支持信创吗?是真的吗?

行云管家

信创 国产化 行云管家

Java并发Map的面试指南:线程安全数据结构的奥秘

程序那些事

Java 多线程 程序那些事 面试秘籍

对线面试官 - Java基础面试题【一】

派大星

Java 面试题

Rocketmq并发和顺序消费的失败重试机制

石臻臻的杂货铺

RocketMQ

探索以太坊 Layer 2 解决方案的后起之秀——Starknet

Footprint Analytics

区块链 以太坊 Layer 2

JDK8升级JDK11最全实践干货来了 | 京东云技术团队

京东科技开发者

Java jdk8 JDK11 企业号9月PK榜

选择渲染农场的几个标准

Finovy Cloud

游戏制作 影视制作 渲染 云渲染 渲染农场

冗余代码检测与分析_.NET_Zebedee Mason_InfoQ精选文章