自Google在2009年发布Go语言的第一个正式版之后,这门语言就以出色的语言特性受到大家的追捧,尤其是在需要高并发的场景下,大家都会想到是不是该用Go。随后,在国内涌现出了一批以七牛为代表的使用Go作为主要语言的团队,而许世伟大神本人也在各种场合下极力推动Go在国内的发展,于是在这种大环境下,中国的Go开发者群体逐渐超越了其他地区。 那么问题来了,业余时间好学是一回事,真正要将一个新东西运用到生产中则是另一回事。JavaScript的开发者可以义无反顾地选择Node.js,但是对于Java开发者来说,在下一个大项目里究竟是该选择Go,还是Java呢?
首先,需要说明一下,作为一个技术决策者,在进行技术选型时并不能单方面地根据语言本身的特点直接下结论。实际情况下,大多数人会使用一系列的框架、库及工具,简而言之就是会考虑很多周边生态环境的因素,同时还要结合公司的特点、各种历史问题和实际客观因素等等一系列的考虑点综合下来才能完成决策。所以,接下来我们先从语言开始,一步一步来分析下在你的项目中选择Go是否合适。 Go在高并发编程方面无疑是出众的,通过goroutine从语言层面支持了协程,这是Java等语言所无法比拟的,这也是大多数人在面对高并发场景选择Go的重要原因之一。虽然Java有Kilim之类的框架,但没有语言层的支持始终稍逊一筹。 除此之外,Go的其他语法也很有趣,比如多返回值,在一定程度上为开发者带来了一定的便利性。试想,为了返回两到三个值,不得不封装一个对象,或者抹去业务名称使用Map、List等集合类,高级一点用Apache的Pair和Triple,虽然可行,但始终不如Go的实现来得优雅。在此之上,Go也统一了异常的返回方式,不用再去纠结是通过抛异常还是错误码来判断是否成功,多返回值的最后一个是Error就行了。 Go在语言的原生类型中支持了常用的一些结构,比如map和slice,而其他语言中它们更多是存在于库中,这也体现了这门语言是从实践角度出发的特点,既然人人都需要,为什么不在语言层面支持它呢。函数作为一等公民出现在了Go语言里,不过Java在最近的Java 8中也有了Lambda表达式,也算是有进步了。 其他的一些特性,则属于锦上添花型的,比如不定参数,早在2004年的Java 1.5中就对varargs有支持了;多重赋值在Ruby中也有出现,但除了多返回值赋值,以及让你在变量交换值时少写一个中间变量,让代码更美观一些之外,其他的作用着实不是怎么明显。 说了这么多Go的优点,当然它也有一些问题,比如GC,说到它,Java不得不露出洁白的牙齿,虽然在大堆GC上G1还有些不尽如人意,但Java的GC已经发展了很多年,各种策略也比较成熟,CMS或G1足以应付大多数场景,实在有要求还能用Azul Zing JVM。不过从最新的Go 1.5的消息来看,Go的GC实现有了很大地提升,顺便一提的是GOMAXPROCS默认也从1变成了CPU核数,看来官方对Go在多核的利用方面更有信心了。 许世伟在《Go 语言编程》的前言中预言未来10年,Go会取代Java,位居编程榜之首,当时是2012年,为了看看2009年TIOBE年度编程语言如今的排名,笔者在撰写本文时特意去TIOBE看了下,最近的2015年8月排行榜,Java以19.274%位居榜首,Go已经跌出了前50,这不禁让人有些意外。 但总体上来说,笔者认为Go在语言层面的表现还是相当出色的,解决了一些编程中的痛点,学习曲线也能够接受,特别是对于那些有C/C 背景的人,会感觉十分亲切。 一个人写代码时可以很随性,想怎么写就怎么写,但当一个人变成一个团队后,这种随性或者说随便就会带来很多问题,于是就诞生了编码规范这玩意儿,大厂基本都有自己的编码规范,比如Google就有针对不下十种编程语言的规范。团队内约定一套编码规范能够很大程度上地确保代码的风格,降低阅读沟通的成本。Go内置了一套编码规范,违反了该规范代码就无法编译通过,可以说只要你是写Go的,那你的代码就不会太难看,当然Go也没有把所有东西就强制死,还有一些推荐的规范可以通过gofmt进行格式化,但这步不是必须的。 虽然Go自己解决了这个问题,但并不能说Java在这方面是空白,Java发展至今周边工具无数,并不缺成熟的代码静态分析工具,比如CheckStyle、PMD和FindBugs,它们不仅能扫描编码规范的问题,甚至还能扫描代码中潜在的问题并给出解决方案,并且使用方便,在Java开发者社区中有很高地接受度,应该说大多数靠谱地开发者都会使用这些工具。除此之外,一些大厂也有自己的强制手段,比如百度内部也有很多语言的编码规范,而且大部分情况下如果没有通过编码规范的扫描,你是无法提交代码的;还有一些公司会在持续集成过程中加入代码扫描,有FindBugs高优先级的问题时必须修复才能进入下一个阶段。所以说Go在这个问题上的优势并不明显,或者说在一个成熟的环境下,这只是合格而已。 这里需要强调笔者的一个观点:
Go本身对项目结构有一套约定,代码放哪里,测试文件如何命名,编译打包后的结果输出到哪个目录,甚至还有go cover这种统计测试覆盖率的命令行,开发者不用在这些问题上太过纠结,再一次体现了Go注重工程实践的特点。回过头来,Java方面,Maven、Gradle都是注重于工程生命周期管理的工具,而且Maven更是历史悠久,被广泛用于各种项目之中。以Maven为例,不仅能够实现上述所有功能,还有很强的插件扩展能力,这里需要的只是一次性维护好pom.xml文件就行了,由于Maven的使用群很大,网上有大量的范例,甚至还有很多生成工程的工具和模板,所以使用成本并不高。 这里还要衍生出一个话题,就是依赖管理,在开发代码时,势必需要依赖很多外部的东西,Go可以直接import远程的内容,这个特性很有创意,但并不能很好地解决版本的问题,在Maven或Gradle里,我们可以直接指定各个依赖项甚至是插件的版本,工具会自动从仓库中下载它们。如果需要同时在同一个系统的不同模块里依赖同一个库的不同版本,我们还能够通过OSGi这种略显复杂的手段来实现,在模块化方面,Jagsaw虽然被一延再延,但估计有望纳入Java 9,这个特性也会解决不少问题。而根据Golang实践群中大家的讨论,似乎godep、gb和gvt都不尽如人意,在这点上看来Go还有一段路要走。 综上所述,Go在工程方面的确有不少亮点,吸纳了很多最佳实践,甚至可以说用Go之后更容易写出规范的代码,有好的项目结构,但与生态圈完备的Java相比,Go并不占优势,因为最终代码的质量还是由人决定的,双方都不缺好的工具,所以这方面的特点并不能影响技术选型的决策。
下面进入编码环节,先从Go引以为傲的并发开始,《Go语言编程》的前言中有这样一段代码:
func run(arg string) {// ...}func main() {go run("test")...}
书中与之对比的Java代码有12行,而且还是线程,不是协程,对比很明显,但那是在2012年的时候,时至今日,Java已经发展到了Java 8,3年了,看看如今的Java代码会是什么样的: public class ThreadDemo {
public static void main |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|