小毛的胡思乱想

凡走过,必留痕迹.

Improve Bitter Code: 对付魔鬼数字

| Comments

备注: 示例中的代码并不是真实代码的完全拷贝

道高一尺,魔高一丈

魔鬼数字在项目中大量出现,是代码可读性维护性变差的重要推手。 为了控制事态恶化,项目中加入findbugs,checkstyle等静态检查工具,试图让人自觉修复魔鬼数字这类头疼的问题。

最近在review N项目的代码时,发现有新童鞋对修复checkstyle的问题热情高涨,有些修改的确是有益的, 但是对魔鬼数字的修改就显得不是正路了。大家先看看:

private static final int INT_2 = 2;
private Static final int INT_80 = 80;
private Static final int INT_1000 = 1000;
private Static final int INT_60000 = 60000;

这种情况以前也出现过,那个时候刚推广checkstyle,结果有人定义了NumberUtil类,里边就有ONE, TWO…等变量, 一直延伸到好几十。这让我非常纠结,劝说了很多次,结果这个类最终还是扎下根来了。我对此深恶痛绝。

今天再次看到这种方式,真是道高一尺魔高一丈呀。我又要发牢骚了。

认清工具的本质

这种做法完全就是为了对付checkstyle,而不是对付那对问题代码。工具本来是想提醒程序员,避免写出难以维护的代码。 结果我们更聪明,把代码藏起来,眼不见为净。这样其实是把数字和变量名直接关联起来了, 你能想象一个叫INT_2的变量值确是1么? 如果在不同含义的逻辑里边使用这样一个魔鬼变量, 一旦值发生变化,就会顺带把不应该修改的地方也改动了。

如果我们真的是为了提高自己的编码水平,提高项目的代码质量,就应该认真的对待这些魔鬼数字。 对于魔鬼数字,应该有一个良好的命名,对于经常出现的,还应该找个合适的地方加以管理。接下来以上面的例子继续分析。

解决魔鬼数字

要解决魔鬼数字,首先是认清魔鬼数字代表的意义,给它起一个合适的名字。

查看源代码,可以发现,做了下面的代码调整:

  1. 2是某个值在列表中的位置索引,换成XXX_IDX
  2. 80是http的默认端口,换成DEFAULT_HTTP_PROT
  3. 1000是用来把秒换成毫秒的,可以用MILLISECONDS_PER_SECOND
  4. 60000是默认超时时间来的,换成DEFAULT_TIMEOUT

同样,经常会看到魔鬼字符串,”0”,”1”这样的值出现代码里边,也应该 把给他们起一个好的名字,例如作为执行结果,有SUCCESS、FAILED等。

更进一步

需要考虑的还有常量定义的地方,另外考虑使用方法封装来处理魔鬼数字的逻辑。 这样可以隐藏一些细节,把作用域限制在很小的地方。 例如下面经常出现的魔鬼字符串,就可以考虑把整个判断逻辑封装到user类里边去, 而不只是简单的定义出ACTIVE这样一个常量。

// 原有的代码
if("1".equals(user.getStatus())){
    // ...
}

// 改造后,"1"作为user的常量使用于isActive方法
if(user.isActive()){
    // ...
}

不过话说回来,解决魔鬼数字、字符串之类等’小枝小节’,花费的精力不小。 但不要忽视这些细节,这样可以让自己不断提高对代码的认识,也便于其他人维护你的代码。

对付魔鬼数字,还是不要走捷径的好!

“improve bitter code”系列文章:

Comments