![](https://www.azul.com/wp-content/uploads/2024-06-27-trash-panda.jpg)
如果浣熊是软件工程师,它们会在许多企业系统中感到宾至如归。这些系统往往充斥着大量未使用的代码和死代码,这些代码在编写和经过全面测试后,通过某种方式得到修改,致使团队永远不会再运行它们。
这种垃圾代码简直是浣熊的最爱,但对开发人员来说,却是一项维护负担,在进行其他重大更改时必须绕过它们,才能确保测试通过。这些代码通常不会被丢弃,因为很难确定可以安全移除哪些代码而不会破坏应用程序。但是,如果知道如何查找,就可以更好地识别不良代码。
静态分析或日志审查是识别死代码或未使用代码的典型方法。现代 IDE 可以通过可达性分析,检测未使用的代码和死代码,但对于并非完全私有的类和方法,则存在准确性问题。如果代码具有公共访问修饰符,它就可能会被加载,因此您的工具永远不会报告它。
其他时候,当代码被跟踪时,它会在单元测试中运行,因此,这些代码从技术上讲,不会被当成死代码。遗憾的是,虽然基于测试进行设计是一种良好的做法,但有些代码之所以存在,仅仅是因为删除它们将导致单元测试失败。这种测试所做的仅仅是验证不必要的累赘是否满足其原始设计要求。
虽然移除未使用的代码和死代码会导致测试失败,但开发人员也可以移除这些测试,不再运行它们,从而加快整个构建管道。要全面了解哪些代码可以丢弃,最佳方式是分别监控测试环境和生产环境,并观察发生的状况。
未使用的代码和死代码杂乱无章
许多团队都持有“何必担忧”的态度:实际上能有多少未使用的代码和死代码?这又有什么关系?未使用的代码和死代码杂乱无章,会拖慢当前和将来的开发速度。每当人们处理与应用程序相关的工作时,都不得不绕过这些代码。当进行重大变更时,例如从 Java 11 升级到 17 或 21,所有这些不必要的代码都需要得到维护。无论代码是否重要,构建管道都需要花时间确保它们能够运行。
美国的一家大型金融机构着手识别并移除未使用的代码后,成功地将代码库规模缩小了 67%。复杂度的降低极大地改善了开发人员的体验,让他们能够在一年内发布超过 250 次应用程序更新,并最终升级了一些阻碍他们发展的旧库。
IEEE 对一套工业软件系统的类似研究发现,在大型代码库中,有高达 50% 的代码未被使用或永远不会被执行,一般而言,未使用的代码或死代码平均占比 5% 到 10%。应用程序的规模越大、时间越长,这个比例就越高。
Java 中未使用的代码和死代码
Java 工程师可以像收集垃圾一样,检测和处理未使用的代码和死代码:选择设置,让 JVM 完成剩下的工作。代码是否在生产中使用,取决于方法是否被调用(或内联)。而判断结果将记录在以下三个位置之一:字节码解释器、AppCDS(应用程序类数据共享)或 Azul Platform Prime 的 ReadyNow 功能。对于多次使用的方法,除了首次调用时需要记录外,后续调用不会因为记录而对性能造成影响。方法在生产环境中使用过,即表示其代码不属于死代码。在这种情况下,JVM 的运行会被打上“应用程序环境”的标签,以帮助记录特定环境中调用了该方法的应用程序。将这些环境分隔开来,有助于识别那些仅因彼此维持而存在的代码和单元测试。
要监测并确定可以废弃的代码,需要更长的时间维度。除非观察应用程序达到一定时间,否则许多代码都来不及运行。因此,团队通常会将死代码分为两部分:他们认为可以删除,但又不确定的部分;以及需要更长时间的观察才能决定的部分,而这部分往往基于与业务周期相关的周期性活动。
开发人员可能会怀疑代码的某些部分未使用或不会被执行,但没有足够的信心将其删除。解决这个问题的途径是跟踪代码清单,然后在应用程序中执行一些操作,看这些方法是否被报告为正在运行。如果是,则表示代码有效;否则,就很可能是未使用的代码或死代码。像年终报表这样的功能,需要经过完整周期才能进行检测。因此,对代码活跃性的监测最好长期进行。短期内可快速取得成果,之后再逐渐淘汰更多无用代码。
通过代码清单减少代码杂乱
Azul 的代码清单是 Azul Intelligence Cloud 的一项功能,它不同于典型的静态分析工具和可以检测不可达代码的 IDE。代码清单的监视行为是在正在运行的 JVM 中进行的,旨在识别存在但从未运行的完整类或公共方法。它就像清点杂乱物品的工具,驱赶乱翻垃圾的浣熊。它能够准确列出正在运行的自定义代码和第三方代码,从而精准地识别未使用的代码和死代码,以便进行移除。
死代码检测提高了开发人员的工作效率和幸福感。维护垃圾代码是一项繁重的苦差事,这些垃圾代码的唯一用途就是满足测试要求,确保不必要的代码能够正常工作。通过检测未使用的代码和死代码,开发人员可以安全地将它们扔进垃圾桶——这是我们浣熊朋友的美味佳肴。