小站重新装修,欢迎到访。

中国式开源的三宗罪

“月亮还是外国的圆”

这话放到IT行业,我感觉让人不好去否认。

IT技术发源自西方(没算盘什么事吧?!),根基也在西方。先不说各种各样的网络协议、有名无名的编程语言,即使比较优秀的框架或库什么的也都难觅中国智造。这有语言、文化、国情等多方面原因,不想吐槽过多,今天只想聊聊“中国式开源”。

这两年IT圈子不知怎么,突然一改只从开源社区索取,绝不向社区贡献的猥琐姿态,各种中国智造的开源项目如雨后春笋般出现。但笔者感觉这些项目大都是中国特色的,属于中国式的。什么是中国式开源?我觉得下面三个字概括的很好(出处不详):

晒 代 码

最近业余在看国外一个著名开源项目的源码。深感其社区之活跃,笔者读书那会虽然已经经常在sourceforge.net(日薄西山)爬来爬去,但对社区(community)这个概念理解并不深,毕竟那会太嫩,几百上千行代码写出来就敢自称框架,还厚颜无耻地扔到sourceforge.net给人看。扯远了。

前几日,由于工作需要,去看了国内一家互联网大厂开源的某项目(就不点名了,该项目自称用户很多)。两相比较,感慨万千,正好反映了我本文想表达的“三宗罪”。下面细数一下。

###代码品质###

我没有用代码质量这个词。因为代码质量直接让人联想到项目的源码写的好不好、格式工不工整、逻辑清不清晰、抽象优不优雅等,这些我不够格来评判。这里说品质,包括几方面。

首先是测试用例。有时候测试用例可以从侧面反映出某些类的用法,也可以暴露某些关键逻辑,这对于代码的学习者,还是比较关键的。可是我看的那个项目源码,一个用例都没有。

其次是代码内容。这里有个关键问题就是出自中国的开源项目,很多都是来自企业内部的改造,即把内部运行良好的项目,抽取适宜公开的部分包装而成。这就导致这些项目里有时会残留有这家企业的业务气息。导致不能很好的抽象大众化的需求。

###文档###

中国式文档也不得不让人吐槽。该大厂的这个开源项目,我翻遍网络,只觅得一份架构简介、安装说明,区区几页纸。不过好在有一些javadoc,可以生成源码的文档。但谈到前面所说的某国外项目,从README到如何为本项目贡献代码,从WIKI到tutorial,从ISSUES到maillist,一应俱全。甚至作者在采纳了你的patch,要把你加到contributor列表之前,都要先签一份agreement才行。不得不佩服老外的职业和专业精神。

至于为什么我们很难写出一份好文档,我觉得和国情有关,也和文化有关。中国人码农大都年轻,而且大都忙于糊口,公司也大都在压榨员工。很多时候大家都在赶工期。代码都写不完,何谈文档?虽然没有和老外共事过,也没出过国,但从很多老外的博客来看,很多人年龄都比较大,属于经验派,同时,生活压力也不会太大,爱好广泛,生活安逸。饱暖思淫欲,这话放到ITer身上,便是饱暖思代码,一个道理。

###社区活跃度###

上文谈到的国外的开源项目,社区活跃,contributor很多,项目的leader也经常出来和社区互动,言辞亲切。

我在阅读大厂的开源代码时,遇到一些不解的问题,由于文档太少,搜索引擎上关于此项目的讨论也不多,无奈便去微博@了一下几位该项目的开发者,至今杳无音讯。何故?项目主页不是说了有问题可以这么问的么。除此之外,我没看到如何能贡献patch,没看到邮件列表。

综上所述,我认为中国式开源就是在晒代码,虎头蛇尾般。有如小树成长为大树,开源项目亦是如此。好的开源项目,码农乐于参与,维护者做得好的话,肯定会朝着好的方向演进。但面对晒代码式的开源项目维护者,再好的项目都怕是让人望而却步。

临了,此文绝非对大厂的开发者不回答笔者问题的打击报复。实乃多年码农生涯积累下来的吐槽。希望中国码农少一些浮躁。多一些对技术的真挚追求。国内企业少一些压榨,多给码农一些时间和空间。码农从来不是企业的成本,而是企业难得的财富。

clojure工程构建之lein篇

最近为了看storm的源码,开始了clojure的系统学习。clojure因为背负了Java这个历史大包袱,在语法上相对于其他Lisp方言,还是稍显复杂和罗嗦。JVM语言似乎都很难摆脱JAVA的身影,互操作是件很难做得优雅的事情。不过FP的魅力还是让我坚持下来,准备长期作战,不断学习和积累。本文不进一步讨论clojure,只简单介绍下使用lein进行clojure工程的构建,因为我个人对gradle很感兴趣(出于对groovy的好感)后续可能会再写一篇使用gradle的构建。

storm的源码就采用了lein构建,可以看下工程根目录下有project.clj文件。就目前看到的clojure开源项目,用lein的还是居多的。

##lein的安装##
查看lein的github主页:https://github.com/technomancy/leiningen,对于lein在*nix上的安装,比较简单的步骤是下载此脚本,放到PATH里,并执行chmod 755 /path/to/lein即可。首次执行该脚本会下载相关的文件并默认安装到~/.lein

##创建新工程##
这里我们创建一个简单的示例工程:

$ lein new app leinexample

控制台输出:

Generating a project called leinexample based on the 'app' template.

也就是说,app是工程的模板名,lein默认的模板是default。模板是插件化的,所以可以很容易扩展,这里就有很多模板。下图是我们用find .列出的lein的默认目录结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
billmac:leinexample jingege$ find .
.
./.gitignore
./doc
./doc/intro.md
./project.clj
./README.md
./src
./src/leinexample
./src/leinexample/core.clj
./test
./test/leinexample
./test/leinexample/core_test.clj

重点是project.clj

1
2
3
4
5
6
7
(defproject leinexample "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]]
:main leinexample.core)

默认只列出了lein project的一部分属性,包括工程名以及相关元信息、license、依赖等等。这里有最全面的工程定义样例可以参考。

##导入到IDE##

起初像学习erlang一样,我使用emacs进行clj的练习,但尽管我个人对emacs很有好感,不过对于阅读代码这种事情,还是使用IDE的好。

如果需要使用eclipse或IntellijIdea等支持maven的IDE,可以使用lein pom来生成pom文件,然后直接使用IDE导入maven工程。个人感觉IntellijIdea真的是非常强悍的IDE,当然不仅仅是说对clojure的支持。

##管理依赖##

在project.clj中可以添加依赖包,比如,我们在project.clj的dependencies中添加一条:

:dependencies [[org.clojure/clojure "1.5.1"] [clj-http "0.6.5" :exclusions [crouton]]]

执行lein deps,控制台输出:

1
2
3
4
5
6
Retrieving clj-http/clj-http/0.6.5/clj-http-0.6.5.pom from clojars
Retrieving org/apache/httpcomponents/httpcore/4.2.3/httpcore-4.2.3.pom from central
……
Retrieving clj-http/clj-http/0.6.5/clj-http-0.6.5.jar from clojars
RetrievingRetrieving slingshot/slingshot/0.10.3/slingshot-0.10.3.jar cheshire/cheshire/5.0.2/cheshire-5.0.2.jarfrom from clojars
clojars

你可能发现,下载的依赖包,并不在工程目录里,其实lein是整合了maven,上述包其实已经下载到maven的本地仓库了。

##运行测试用例##

lein会默认生成一个clj和对应的测试用例文件,打开leinexample/test/leinexample/core_test.clj,修改a-test函数的返回值为true,即修改最后一行为(is (= 0 0))即可。然后执行:

lein test

控制台会打印出测试用例的运行结果:

1
2
3
4
lein test leinexample.core-test
Ran 1 tests containing 1 assertions.
0 failures, 0 errors.

##编译代码##

此时如果直接运行lein compile,你会发现,target目录里没有.class文件。这个起初也让我很不解。查阅了相关文档发现需要开启aotcompile Ahead Of Time,在project.clj的defproject函数添加metadata:

:aot [leinexample.core]

之后再执行lein compile,即可在target/classes里看到对应的.class文件了。

注意,上述大多数目录,如target、classes等,都可以在project.clj中修改。

##打包##

lein支持jar、uberjar等等打包方式,具体可以使用lein -h可以查看lein的其他子命令。应该也可以直接打出war包,这个我没有尝试过,有兴趣的充分发挥google的力量吧。

简析Java Reference

Coding了多年Java,自然早就听说过四种引用类型,不过偶尔也才浅浅的用一下,今天突然想看看这块的内部实现,读了读jdk源码,这篇文章就当做个笔记。先简单介绍下四种引用类型:

####Java的四种引用类型####

  • StrongReference

强引用。最常见的引用类型,用赋值号,即“=”来创建。GC不会回收强引用,即使内存不足,也是宁可抛OOM先。

  • SoftReference

软引用。关键看内存,在内存不足时,GC会把软引用的对象回收掉。适用于对内存敏感的缓存。

  • WeakReference

弱引用。和软引用的区别是,无论内存充足与否,GC扫描到弱引用所引用的对象不再具有强引用时,会将其回收。

  • PhantomReference

虚引用,也称幽灵引用。其get()方法固定return null,看起来似乎没有什么大的用处,但在某些场景下结合ReferenceQueue,可以有意想不到的效果。

####ReferenceQueue####
站在coder的角度看,ReferenceQueue似乎更“有用”一些。其作用是追踪被gc的Reference对象,更多的是做一些统计或清理的工作。

####Reference的四种内部状态和ReferenceHandler####

Reference依赖内部的四种状态,和GC、ReferenceHandler配合来运作,包括:Active、Pending、Enqueued和Inactive,具体可以查看下Reference类的注释,鉴于笔者理解不足够深刻,就不误导大家了。

ReferenceHandler是个高优先级的线程,用于把gc处理的Reference对象enqueue到ReferenceQueue中。

近期使用SoftReference自己做了个缓存工具,用以缓存一定size的Hive查询结果,代码在这里

博主是一个不是很聪明的码农。完美主义者,强迫症中期。这里会记录一些回忆和点滴,以博为镜。

武器库:

该博客使用基于  Hexo  的  simpleblock  主题。博客内容使用  CC BY-NC-SA 3.0  授权发布。最后生成于 2017-02-20.