用Map消灭if-else if-else
尽管三元表达式已经很简洁了,然而仍然不是最优解。
此处的最优解是Map:
public static final Mapoperator2Revoperators = Map.of( "=", "!=", "==", "!=", "!=", "=", "<>", "=", ">", "!>", "<", "!<", ">=", "!>=", "<=", "!<=" ); public String getReversedOperator() { return operator2Revoperators.get(operator); }
很可惜,直到Java9,上述语法(主要是Map.of方法)才得到支持。
那么,是否还有更好的方法呢?“最好的方法”是否存在,以及如何判断自己已经达到最好的方法了?
这时候就要了解一种叫做“上帝代码”的东西。
围棋上帝最早被笔者所知是大约10年前(Alpha Go战胜人类之前5年左右)。
围棋是中国的国粹,有上千年历史。现代围棋(取消座子规则)经过在日本发展之后日趋完善,即使是在中日围棋擂台赛中国大胜之后,也没有太大的新发展;直到出现了韩国流下法,下法又出现了一些变化。然而经过若干年之后,中国围棋手学习并适应了这种下法,重登宝座。
这时候问题来了,如果上帝也会下围棋——从不犯错,但也不犯规——那么人类最优棋手与之差距多少呢?当时中国围棋手执棋者是古力,当时他认为与围棋上帝只有1目左右的差别,也就是棋盘上的一个格子(一共有19*19=361个)。
然而后来Alpha Go的战绩证明这个数字太乐观了。世界第一人柯洁与AG三盘比赛的最小差距为1/4字(半目),最大差距为“中盘认负”(一般差异在5目左右会中盘认负)。而后来的Alpha Zero则号称以100:0战胜了Alpha Go。
AG可以认为是人类的实际最高水平(它的本质是根据人类的历史棋谱进行运算,并不会超过人类,只是“从不出错”而已),而AZ则是真正的计算的最高水平(直接根据规则来做计算,更接近上帝),如果100:0属实的话,人类应该比上帝还差不少,或许至少还有5目的差距。
同样,如果存在编码上帝(他写的代码叫做上帝代码),那么我们写的代码与之相比,差距如何呢?
尽管现在还没有自动化编码的AI来与人类较量,然而单纯从语言分析的角度,已经可以在局部产生一些判断了。
重新审视最后基于Map的实现代码:
public static final Mapoperator2Revoperators = Map.of( "=", "!=", "==", "!=", "!=", "=", "<>", "=", ">", "!>", "<", "!<", ">=", "!>=", "<=", "!<=" ); public String getReversedOperator() { return operator2Revoperators.get(operator); }
public表明外界可以使用;
static表明无需声明实例;
final表明此数据是不可修改的(C++, C#中叫const);
……
顺着代码看下去会发现,任何信息没有一个是可以删除而不改变外界所见的功能的。
唯一多余的反而是Map
多一个字则多,少一个字则少的代码,称之为上帝代码。
上帝代码实际上是基于纯语言学角度即可建立的概念,与技术无关。若Java最早的发明人认识到这一点,那么Java1就能够被设计成可以写出上帝代码的程度。
有追求的编程者必须建立上帝代码的概念,并追求逐渐逼近上帝代码的境界。
在QSM.com网站上,有一个“实现相同功能点所需代码(点击链接可见)”的统计表。下面的讨论中请先抛开“功能点有大有小怎么进行比较”这个问题,因为这里所说的功能点是一种国际标准的定义,不是我们日常中口头说的功能点。
表中可见,对于一个国际标准功能点:
Java最高高手仅需14行代码,而“最差新手”则需要134行代码。不过注意,这里的“最差新手”有点像奥运会上跑的最慢的人一样,其实也绝非等闲之辈——至少他们知道如何度量和计算这个数字。下面这些数字是笔者根据自己的感受估计的结果,既有凭空猜测的成分,也有直接或间接的佐证:
完成1个功能点所需的Java代码行数:
编码上帝:10~12行
人类理论最高水平:12~13行(未必向QSM提交了代码)
QSM世界纪录:14行
笔者自己:14~16行(我们自己的C#实际项目做到13.7,但考虑到C#比Java有一些优势,故此修正)
笔者咨询过的一个项目:15~17行(实际数据13.1,但他们用的方法存在功能点夸大方向的偏差,故此修正)
BAT的正常项目:20~53行(有希望整体优于世界中值,但并非所有项目都如此)
QSM中值:53行(50%的项目高于或低于此数字)
一线银行的项目:40~100行(看过很多个,多数没有代码优化的概念,数据不容乐观)
全国Java项目正常值:70~150行
上述数据意味着,以上帝代码的标准,正常项目的90%的代码都是多余的。这听起来似乎很不可信,实际上却有一些实际数据支撑。
笔者个人重构的局部代码最大差异为4000LOC:55LOC(4000行代码修改后只剩下55),~2000LOC:180LOC,还有一个较大的产品只看了一下未进行重构,预计大约在50:1左右(原代码水平极差,后来他们产品也放弃了)。
较大型的产品则是190000LOC:13000LOC(大约剩下7%的代码,2004年一个电信项目),可惜只参加了代码评审,不是我本人重构的。根据当年主观感受推测,重构后的水平在每功能点20行左右,也就是说重构前在280行水平。
这个项目的第一版本投入超过2000万(100人年左右),而重构只花费了30万(1.5人年),两者相差60倍。估计需求摸索与变更贡献了3倍,人员自我学习与成长2倍,剩下的10倍这一巨大差异可以认为是纯技术和管理问题了。