在数字化程度越来越高的今天,代码无处不在, 从我们使用的各种电脑, 智能手机,汽车等智能设备, 都来不开代码实现各种各样的功能。代码的质量影响用户体验, 关乎产品成败,关键系统的缺陷将导致巨额且无法挽回的损失。据报道, 造成波音737 MAX坠毁的部分原因被指是由于MCAS系统上的软件引发错误。
目前, 代码还是靠人来编写, 这就难免会有的缺陷,而现代软件越来越复杂, 代码量通常也是惊人的,开发人员水平参差不齐。所以我们就需要通过工具帮助我们提升效率, 就如同车企不但自己不造轮子, 还会用工业机器人,房企不但不会自己造砖,还会用各种工程机械提高效率。现在软件开发也越来越依赖开发工具和平台的来提高效率, 如开发过程中我们需要像Git, SVN这样的工具来协助版本控制, 需要Ant, Maven这样的工具协助代码编译构建, 也会需要JUnit, TestNG这样的工具来协助我们进行单元测试, …通过这些工具可以提升开发效率, 交付可靠的软件程序。
软件工程是一个很大的话题, 话题扯大了扯不下去了, 接下来进入正题,分享一下个人在Eclipse中代码代码审核工具和单元测试工具的一些心得。
1. PMD
PMD(https://github.com/pmd)是一个开源的代码分析工具, 它可以找出代码中常见的编程缺陷, 如未使用的变量,空的catch块,不必要的对象创建等等。它支持Java,JavaScript, Apex, Visualforce, Modelica, PLSQL, Apache Velocity, XML, XSL, Scala。
PMD是由Java编写的, PMD本身可以独立运行, 也可作为插件集成到很多流行的各种构造工具和IDE中, 其中就包含了PMD Eclipse Plugin (https://github.com/pmd/pmd-eclipse-plugin)。
1.1. PMD(Eclipse Plugin)安装
PMD Eclipse Plugin可以在Eclipse的"Eclipse Marketplace"中搜索并在线安装,也可以离线安装。以离线安装为例:
- 下载离线包
在PMD Eclipse Plugin的发布页面下载离线包: https://github.com/pmd/pmd-eclipse-plugin/releases
- Eclipse安装
在主菜单"Help" -> "Install New Software…"中安装, 选择下载的zip包。
选择"PMD for Eclipse"一路Next, 安装完成后按照提示重启Eclipse即可以使用。
1.2. PMD使用
安装完成后, 就会有PMD相关菜单,选中项目/代码,点击相应的PMD的功能菜单,就可以执行想要的功能。
执行"Check Code"开始对选择的Java代码文件或者Eclipse项目进行检查,只有选择的是Eclipse项目时才有"Generate Reports"菜单, 可以将"Check Code"的结果保存到项目根目录下的reports/pmd-report.txt文件中,注意,需要先执行"Check Code",才能产生检查报告。
完成代码检查后, 如下图, PMD会在检查发现有问题的代码处,通过不通颜色的箭头图标进行标注,不通颜色代表不同的优先级(Priority), 红色代表High (1), 蓝色代表Medium High (2),… 优先级是对应的规则定义的。
PMD检查的量是巨大的, 上面一个简单Java项目,就有144处违反了PMD定义的规则(满屏的标记, 我的代码有这么菜吗? 汗~)。满屏的标注会让人觉得页面会很乱,PMD可以按优先级分类进行过滤,如上图右下角, 选中/不选中对应的箭头图标, 可以显式/隐藏对应优先级的标注。例如,我们只想显示高优先级的,那么可以只选中红色箭头图标。如果我们要恢复正常编写代码状态,可以通过PMD菜单的"Clear …"来清空检查结果和在代码中的PMD标注。
1.3. PDM规则
PMD的代码检查是根据规则来进行检查的, PMD规则是可以自己编写的(自定义规则类, 继承AbstractJavaRule). PMD也自带了大量内置的规则。这些规则说明可以在官方文档(https://pmd.github.io/latest/pmd_rules_java.html)中找到.
可以看到PMD内置了多种语言丰富的规则, 而对应Java包含了: 最佳实践, 编码风格, 性能相关,…相关的规则。如上上图所示,标注位置的代码违反了两个规则:“DoubleCheckedLocking"和"CommentRequired”。对应的代码如下:
private static JuiceFactory juiceFactory = null;
public static JuiceFactory getJuiceFactory() {
if (juiceFactory == null) {
synchronized (JuiceFactory.class) {
if (juiceFactory == null) {
juiceFactory = new JuiceFactory();
}
}
}
return juiceFactory;
}
DoubleCheckedLocking是"Multithreading"相关的规则, PMD文档对其有详细说明,并且还有参考的文章:
DoubleCheckedLocking
Since: PMD 1.04
Priority: High (1)
Partially created objects can be returned by the Double Checked Locking pattern when used in Java. An optimizing JRE may assign a reference to the baz variable before it calls the constructor of the object the reference points to.
Note: With Java 5, you can make Double checked locking work, if you declare the variable to be volatile.
For more details refer to: http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double.html or http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
This rule is defined by the following Java class: net.sourceforge.pmd.lang.java.rule.multithreading.DoubleCheckedLockingRule
双检查单件(singleton)写法仍不能绝对的线程安全,因为juiceFactory变量没有volatile关键字修饰,编译器可能对指令重排序优化,在多线同时调用getJuiceFactory()时产生多个实例,无法确保单件。
"CommentRequired"是"Documentation"相关的规则, 说的是定义的方法应该编写Javadoc风格的方法说明。
很棒吧,就好像有个高手在帮你检查代码,找bug,并给你建议。
1.3. 自定义规则集
PMD对于Java内置将近400条规则,也许并非所有规则都是你需要,如"DoNotUseThreads: To be compliant to J2EE, a webapp should not use any thread.", 你的应用只是普通的应用,你不想检查这条规则, PMD是允许你自定义规则集的。
我们可以通过Eclipse项目属性的PMD页面进行配置:
我们可以通过勾选/取消勾选来开启/关闭某个规则, 还可以通过编写ruleset来定义规则。上述的配置,对应的是Eclipse项目根目录下的.pmd和.ruleset配置文件,他们都是一个xml文件,结构非常简单。每条规则,对应的引用可以在规则文档中找到。如"DoNotYseThreads"规则,对应ruleset的引用为:
<?xml version="1.0" encoding="UTF-8"?>
<ruleset xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
name="pmd-eclipse"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
<description>PMD Plugin preferences rule set</description>
<rule ref="category/java/bestpractices.xml/AbstractClassWithoutAbstractMethod"/>
...
</ruleset>
这样,再执行代码检查时,只会执行规则集里面的规则。
2.Alibaba P3C
Alibaba P3C(https://github.com/alibaba/p3c)是基于PMD,其内置规则实现的是《阿里巴巴Java开发手册》中涉及的规则。《阿里巴巴Java开发手册》是阿里工程师的经验总结,在Java开发圈内有非常高的知名度。
2.1. P3C安装
Alibaba P3C的wiki有详细说明,这里就不赘述了。
https://github.com/alibaba/p3c/wiki/Eclipse%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3
2.2. 使用感受
P3C的用法和PMD类似,P3C提供中文/英文语言切换,对国人更加友好, 而P3C对于违约的标注和显示界面也比PMD更友好,在内置规则上相对PMD内置的会少,两种有重叠,也互有不同,P3C更关注于编码风格。
在"Rule Detail"页有对规则的详细说明,不像PMD还需要去查官方在线文档。
除了说明还贴心的给出了实现的案例(使用google guava),非常贴心。Executors创建的连接池,等待队列太大(Integer.MAX_VALUE), 可能导致请求大量的堆积,耗尽内存从而导致OOM。 另外一个问题是无法对线程池的线程进行命名,无法清晰的看出线程用途,这对未来的故障分析排除是不利的(如VisualVM / Thread dump)。
3. 小结
用文本编辑器编写代码的时代一去不复返,类似的Code Review工具还有很多如FindBugs,拥抱并充分利用工具,可以提升你的代码质量,提高效率,降低工作量,使得开发人员将更多的尽力放在业务逻辑本身。