Reinventing the wheel-talk about new solution involved

所谓新方案,包括方法和技术两方面;相对于“旧”而言,“新”不代表就是自己去创造,而更多的是采用已有的更成熟、更“时髦”的工具或方法。涉及到编码话题,大到架构方案选型,小到具体某块代码都在考虑新方案。

在采用新方案时,我们必须正视一些原则,其实这些原则随处可“见”,而且基本潜移默化都会如此执行,但是这里还是以自己的切身感受重复总结一番:

(1)是否可以不引入。

每引入新的方案,带来的收益是否值得,基本也就一个简单问题:收益>支出?

有一些因素可能会让你避免引入新方案:

1.1 引入新方案就意味着引入新的风险,无新引入则无新风险,有则有新风险。

1.2 有损优势,例如有的项目以简洁见“长”(例如influxdb-java),尽量不引入额外的jar作为一个原则,仅仅为了1处复杂度不高的代码少写几行,以后估计别的地方也不会用,则引入额外的jar则得不偿失。

1.3 有应用新方案的时间,可以去做更有意义或更高优先级的事情。

(2)如果改,改成哪种?

2.1 采用的方案是否收费,版权如何规定的?

在选择时,收费和版权问题基本具有是“一票否决权”。

同时要意识到收费的方案虽“好”,但是也暗含着一定的“封闭性”。

2.2 采用的方案是否成熟?

包括是否有大规模应用案例,是否有活跃的社区支持。

2.3 采用某种方案的什么版本?

什么版本是稳定版,什么是“试验”版,例如netty有v3,v4,v5三个版本,5是试验版,但是一些喜欢“尝鲜”的工程师应用到产品中,结果悲剧发现,某天v5彻底宣布不维护了,而一些喜欢尝鲜的工程师后知后觉发现不维护后,戏称要拿刀砍死源作者!情何以堪!

2.4 所采用的版本有没有什么不能接受的问题?

基本所有的方案都会提及自己的问题, 例如git上的issues, doc更完善的方案会将issue和版本关联起来。使用某个版本时,一定要查看当前的issues,同时在具体使用中,一定要看看是否有提及“不稳定”因素等。

例如:在guava中,有一个实用的方法Splitter:


Splitter.on(",").withKeyValueSeparator('=').split("boy=tom,girl=tina,cat=kitty,dog=tommy");

用来先以,分割,然后以=分割,这个方法感觉挺酷的,正好可以解决去解析格式是key1=value1;key2=value2结构,但是用的过程中,就会发现偶尔会失败,最后定位到因为某个value是编码过的,有时候会含有分割符=,但是guava对于这种情况的处理,是直接抛异常。

这在它的javadoc中并没有说明这种情况,仅仅是在类中标了下@beta表明其有可能有bug(实际上翻阅历史,有2个bug导致其一直挂着@beta标记). (已提交1个pr去fix: https://github.com/google/guava/pull/2663,不过不知道什么时候能够merge)

大家可能说,这些都是废话,因为你要用那个方法,你不去看javadoc,不去彻头彻尾了解源码么?实际上,大家都懂的:

(1)有的方法起的太好了,以致你觉得根本不需要看文档;

(2)javadoc写不写一回事,清楚不清楚是另一会事,不是你想看就能看,想看明白就明白;

(3)就算翻源码,并没有多少时间,毕竟你要用的所有东西都有源码,根本翻不完。哈哈

2.5 持续观察

不管是什么大神级项目,都有bug,只是触发不触发到的问题,所以持续观察,不仅可以了解方案的发展和局限,也帮助预知一些问题。

使用mybatis,不言而喻其广泛使用度,最近发现一个问题,当要查询的procedure返回游标类型且为null时,报NPE错误。实际上不考虑procedure本身有没有问题,这种情况需要处理:“一个列表没有数据应该是空,但是有时有的人就要搞成null”;

Mybatis的处理,导致这种情况下不是返回null或者空,而是直接抛异常,这隐藏了一些问题,或者让人误解,因为找不到就是找不到,是正常情况。


fail  for: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:

### Error querying database.  Cause: java.lang.NullPointerException

### The error may exist in sqlmaps/sqlmap.xml

### The error may involve project.procedure

### The error occurred while handling results

### SQL: {call xxx.YYY.call(    ?,    ?,    ?,    ?,    ?,    ?,    ?,    ?,    ?   )}

### Cause: java.lang.NullPointerException

产品一直work良好,只是有一些错误log,开始以为是产品的bug,后来debug到mybatis的一个bug,而这个bug的fix日期是2015/11/13.  https://github.com/mybatis/mybatis-3/commit/2d6aed5d3d0cb0dd1290cf520dfdc52d89e63b3f#diff-5372ad5ca04a1c3dcfd0a43546bf40ef, 让人情何以堪。而当时引入mybatis时,应该是在2014年末。所以不能认为你用了就一劳永逸了,可能是你还没有触发,或者你观察的不够。时不时跟踪注意下,就可能有新的发现。

总结:

编码就是不断使用轮子的过程,今天的新轮子可能就是明天的旧轮子。所以采用新方案要追“星”但是不能盲目追“新”。

发布者

傅, 健

程序员,Java、C++、开源爱好者. About me

发表评论