一年一语言之2016


背景

曾经给自己定下一个目标,每年学会一门新编程语言,尽管可能没办法作为工作语言使用,但我始终认为任何语言(特别是现代语言)都有自己的特点,了解其他语言有什么更新更好的解决方案对自己的平时工作还是很有帮助的。毕竟没有任何一门语言是完美的,用最适合的语言解决问题才是关键。

从毕业以后,已经陆续学习过Javascript、Objective-C、Python之类的了,这个习惯中间断了几年。15年底换了工作之后,陆续接触了一些新的语言,用的比较多的就是Go和Scala了。

Go

总结

Go作为Google的亲儿子,又是一门新世纪的语言,在业界关注度还是很高的。尽管Go才出了没几年的时间,在工业界已经有很多成熟的应用了,比如Docker这种大型项目。总的来说Go的风格比较像更现代化的C。当时选择Go的主要原因有几个:

  • 诞生于Google,比较适合互联网开发,从Go的标准库可以看出,Go是一门非常适合互联网服务开发的语言,各种相关的库一应俱全,大厂维护也使这门语言比较可控,不会脱离工业界而走向学术界
  • 现代语言,面向并发,支持routine,比较典型的CSP模型语言
  • 语法相对简单,带有一些面向对象特性的面向过程,和我之前“使用一些c++特性的c”的工作语言风格接近
  • 社区热度高,基本上需要的库都会有开源实现
  • 很多工业界成熟项目使用Go实现,说明这门语言靠谱
  • 静态类型,并且开发效率高
  • 直接编译成二进制,静态链接,分发很简单
  • godoc文档生成工具,输出文档很方便

在花了一些时间熟悉了语法以及一些标准库之后,基本就上手了,写了一个spider/extractor,以及一些web服务。因为整个语言模型和c/c++很像,所以从上手到应用对我来说几乎没有任何成本,写码的感觉也非常爽,配合atom+一些go的插件,实现代码自动格式化,自动import啥的也非常方便,写码体验可以说非常不错。

优点说完再来谈谈我认为的缺点。首先一个是我觉得Go的构建工具方面做的不好,作为一个工业界应用的语言,竟然要到1.5、1.6版本才有官方的依赖解决方案。这个方案在我看来也并不完美,不能依赖某个库的某个版本,只能按照git的commit checksum去依赖,其实很不友好。尽管有一些第三方的构建工具如govender之类的可以对依赖进行控制,但其实还没有像Rust的Cargo或者Js的npm这一类比较完美的包管理+构建的工具。而且在我看来,很多go的库几乎也没有个版本管理的概念,即使用上govender也是按源码去依赖。就这点来说,很难去管理。

第二个缺点是Go在语言feature上面还是太少了,比如泛型、对函数式语法的支持之类的现代特性都还很缺乏,而Google在语言级特性上又比较谨慎,可想而之在未来的几年内可能都看不见这些新特性。

第三个问题是goroutine的健壮性。go的异常处理是panic/recovery机制,但是goroutine的recovery是要靠闭包去实现的,因此,如果你调用了一个第三方库,并且第三方库里的goroutine里写了一个panic并且没有做recovery,那一旦触发panic逻辑,整个程序就core掉了,调用者是没办法在自己的程序中去捕获这个panic并做处理的。比如之前用的一个hbase库,在网络异常时会panic,并且是在goroutine里panic的,作为调用方没办法做捕获重连之类的,只能通过supervisor这种进程管理去提高服务可用性。这个问题我在mail list里问过,Go社区的人确认确实有这个问题,但是他们说第三方库是不应该panic的,除非一些初始化工作就完成不了。但问题就在于,调用者也没办法控制第三方库的质量。

至于目前看到说的比较多的GC问题,因为还没有用Go做一些真正意义的东西,所以也没什么体会。尽管Go有着这样那样的问题,但不妨碍Go成为一门好语言,而且Go相对来说比较简单,在技术团队,特别是C系的团队里推广起来不是太难,未来也期待用Go做一些真正意义上的工作。

2016年下半年以来很少写Go,基本上也就用来写一些command line tools了,毕竟静态链接分发太方便了。

web技术栈

Go的web框架比较多,最早用的matini,但是性能不如gin所以后期都用gin-gonic了。gin是比较轻量级的web框架,不像beego那种一站式框架全面,但是用来快速写一些restful服务还是不错的,号称性能很好,并且route是zero memory cost,但缺点就是真的太轻了,除了架子啥都没有,还要去选一些log啊、config啊、orm啊之类的,这个考虑结合gin和beego使用吧。

go的技术栈探索比较少,毕竟标准库就足够强大了。后面再写一些闲码的时候再研究好了。

Scala

2015-2016接触了很多语言,如果要我选择一个我最喜欢的语言,我选择Scala。我对Scala其实并不陌生,2010年左右,就稍微学习过一些,只是后来转向c/c++之后,就完全抛弃了JVM的东西。当时正值Python/Ruby这些动态语言席卷web开发界,作为一个Java web选手,深深的觉得自己真是落后,很多有点水平的同学都去搞Python啊Ruby啊Erlang啊这些了。但我比较懒,还不想去学Java Web以外的东西,所以就调研了一下Jython和JRuby,发现真是麻烦,正好那个时候讨论next java的也比较多,我正好就看到Scala,说真的那时候的水平还不足以领悟什么Scalability什么Actor什么DSL,选择Scala纯粹是因为特立独行,因为别人都去玩热门的Python/Ruby了,我就非要玩点不一样的,毕竟我就是我,颜色不一样的烟火

但说真的,当年Scala是真的难,连面向过程/面向对象都马马虎虎的我,很难去接受什么函数式编程。那时候最热门的Scala的web框架是lift,和熟悉的Java web开发也风格迥异,所以学习Scala也是三天打渔两天晒网,直到10年暑假在淘宝实习期间,才真正能写一些有用的Scala代码。那个时候的感觉是,Scala是一门“学术界语言”,完全是为了教学,设计一堆不实用的feature。后来大四去百度之后,就再也没写过哪怕一行Java,更不要说什么Scala了。

毕业的时候,在选择带那些书去工作的时候,我曾认为自己这辈子再也不会写Java了,所以把所有Java相关的书全都寄回老家了。然而讽刺的是2015年10月换工作时,去到了一个Java系的公司,不得不重回JVM。刚好那个时候需要写一些Spark,而Spark的“标准语言”刚好就是Scala,上一次没来得及征服的语言,这一次一定要学会。不得不说,经过了5年的发展,Scala已经变得非常接工业界的地气了。重学Scala的过程也非常顺滑,就像和初恋情人旧情复燃一样水到渠成。

总结

Scala在现代语言里算得上非常全面,语言feature几乎要啥有啥,纯面向对象和函数式编程无缝对接,同时背靠JVM,可以作为无缝调用Java的库,简直是一门站在巨人的肩膀上的语言。因为有非常好的类型推导,是一门具有动态语言风格的编译型语言。因为5年没关注JVM方面的东西,只能推测这些年来Scala是怎么从一个学院型语言转向工业型语言的了。首先一个是Twitter等众多互联网公司开始使用Scala,这使得Scala在互联网服务方面有了许多开源沉淀。第二一个是Scala之父Martin Ordersky从学院教授成为typesafe的创始人,有了商业公司的支持,也让Scala能够更好的服务于工业界,避免闭门造车的尴尬。

最早Scala的并发模型是Actor,后面Scala放弃了自己官方实现的Actor,把这块全部交给了akka(反正这个项目也是typesafe支持的),转用了Promise/Future这种基于事件的异步并发模型。就个人感受来说,future的代码写起来更舒服,比actor这种异类来的简单。和5年前相比,Scala放弃了不少纯Scala实现的标准库,而是直接使用Java的,这使得Scala的Library非常精简,几乎都是必要的,同时也方便Java程序员转向Scala,不得不说是这也是一步好棋。

对于函数式编程方面,因为我之前也没有过什么纯函数式编程语言的经验,单就Scala来说,函数式编程的风格确实能给代码带来非常简洁直观的写码体验。同时大量闭包的应用,也可以做到很多面向对象做不到的事情。同时Scala也是一门纯粹的面向对象的语言,一切皆对象。Scala 2.12也重点优化了JVM byte code生成方面,利用JVM 8的特性,生成执行效率更高的代码,毕竟Scala是在JVM上的语言。

Scala优点非常多,但也不是没有缺点,这里说说最困扰我的一些问题吧。首先一个,Scala太难了,这意味你很难组建一个水平很高性价比也很高的Scala团队,很难在spring根深蒂固的Java团队中推广Scala,除非他们的自驱力非常强,有学习新东西的动力。

第二个就是Scala的二进制不兼容问题,目前有2.10和2.11两个主流版本,2.12刚刚release不久,为了1-2年内,可能有三个主流版本并存,虽然语法是兼容的,但2.10和2.11在库上还是有很大差别的。比如2.10就不支持超过22个field的case class、元组什么的,神奇的magic num。虽然目前来说问题不大,但未来可能遇到很多问题,比如我们用spark 1.6是Scala 2.10的,未来一些新的第三方库可能就没有Scala 2.10的版本了,那这些库就没办法在spark里用了,除非升级spark,但这种成本一般会很大。

第三个是官方库落后开源库,比较典型的是Try/Future这些,因为Twitter算是用Scala最多的互联网公司了,他们也开源了很多很好的Scala工具,但Twitter有很多自己的实现,大概是之前官方库没有这些功能,所以当后面官方添加了这些库以后,使用twitter生态系统的开发者就会面临很尴尬的事情,twitter的框架只用自己的实现,而别的第三方库又用了官方实现,这就很难受。

第四个就是sbt的问题,真的太慢了,特别是躲在GFW后瑟瑟发抖的中国用户。如果不翻墙,构建项目时可能一整天都解析不了依赖。就算翻了墙,Scala自己的分析速度也让人惆怅。

第五个就是Scala是一个JVM语言,作为前c/c++开发者,多么希望能用Scala写的程序可以直接编译成二进制啊。当然有一个scala-native项目,就是要这么干,但这个项目目前还在很早期的阶段,就现在看来我认为还有以下一些问题:

  • 非官方支持,纯社区化开发,目前虽然可用,但还在很早期的阶段
  • 还使用慢的要死的sbt作为构建工具
  • Scala很多标准库是用Java的,因此scala-native需要实现这些java库

总的来说,Scala已经成为我目前的第一工作语言了,毕竟可以写Java程序还不用写Java代码。

web技术栈

finatra

用过很多Scala的web框架(目前我们这边后端服务多是restful),比如spary/akka-http, xitrum, colossus,play等,目前觉得最好用的就是finatra。Twitter开源的,所以不用担心它能不能在生产环境用的问题。finatra的性能也非常不错,如果写一个web服务,我的第一选择就是finatra。当然,也有很多让我不爽的地方,比如不支持websocket;基于finagle/twitter-server构建,需要了解的东西太多;twitter future才是第一公民等等。当然这些都不妨碍我痛并爱着finatra,因为其他框架也或多或少有这样那样的问题。如果有人让我推荐Scala的web框架,我首推finatra。

akka

对akka的使用基本是玩票性质的,虽然是用在一个线上服务的很核心的功能里。akka给我的第一感觉是复杂,也确实复杂,它的目标是一个一站式分布式高性能高容错服务解决方案,因此学习成本相对较高。同时actor的系统设计模式也和之前完全不同。不过akka会作为我2017重点去学习的东西的。

slick

一个函数式编程风格的orm框架,还挺好用的,写一些需要用到mysql的web服务还是很方便的,也是typesafe支持的项目。然而就是文档语焉不详,学习成本挺高。

2017展望

2017年的学习目标不出意外的话,应该在Rust, Ocaml, Haskell之中选择,当然最近php7的势头不错,也有可能玩一下世界上最好的语言。

Rust

也是一门现代语言,目标是取代c/c++成为底层系统开发语言,甚至也有用rust写的操作系统。目前rust也是非常年轻,但语言feature,构建工具这些我觉得比go强很多。目前从rust的标准库来看,这门语言还不太适合作为我的工作语言候选,因为它主要还是关注底层。倒是第三方库百家争鸣,一些重要的feature也都是第三方库实现,比如async i/o,routine, future这些,不知道官方打算怎么收编这些库。已经错过了Go和Scala的成长,不希望再错过rust了,因此rust是我2017年的第一目标。

Haskell

因为函数式编程的缘故,特别像学习一门纯的函数式编程语言,Haskell正是FP的佼佼者之一,因此也考虑学一下haskell,而且haskell还能编译成二进制,这很重要。

OCaml

对Ocaml感兴趣纯粹是因为有一天翻facebook在github上的开源项目,发现很多Ocaml写的项目,所以有点像学一下这门语言。

Conclusion

看看2018年的时候,能总结一些什么吧。


文章作者: Odin
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Odin !
  目录