专栏名称: OSC开源社区
OSChina 开源中国 官方微信账号
目录
相关文章推荐
51好读  ›  专栏  ›  OSC开源社区

从 Scala 迁移到 Go,永不回头

OSC开源社区  · 公众号  · 程序员  · 2017-03-08 08:32

正文

#点击图片,报名深圳源创会#


OSC-协作翻译

原文:Making the move from Scala to Go, and why we’re not going back

链接: https://movio.co/blog/migrate-Scala-to-Go

译者:Tocy, 无若, butta, 被盗用户, WeiXiaodong


这篇博客文章自发布以来受到了广泛的关注,已出现在 Hacker News、Golang Weekly 和 Scala Times 各大社区,感谢大家!有读者认为这篇文章是对 Scala 的攻击,但并不是这样的。正如文中所解释的,Movio 使用 Scala;一些小型开发团队使用 Scala 作为主语言。 我们两年前也曾经主持过 Scala Downunder。Scala 社区在过去 4 年里教给我们很多知识。因此,Scala 和 Go 在 Movio 中是共存的。



文中我们简述了选择从 Scala 迁移到 Go 的原因及将 Scala 代码库重写到 Go 的内情。 作为一个整体,Movio 要接受各种不同的观点,在这篇文章中的“我们”仅是一方观点的持有者。不可否认,Scala 仍然是 Movio 的一些小组的主语言。




为什么我们首选 Scala?


是什么使得 Scala 如此有吸引力? 如果你看一下我们的发展背景,这就很容易解释了。下面是一些人随着时间的推移对所喜爱的语言的连续变化:



正如你所看到的,我们大部分来自不断变化的程序世界。


随着 Scala 的出现,函数式编程开始热起来。纯函数使确定性测试变得容易,然后 TDD 得到普及,用以检测我们的软件质量问题。


我认为我第一次看到类型系统的积极一面是在 Scala 上。就个人而言,经历无数的 PHP 静默错误和一些奇怪行为后,有了支持类型检查和妥当的测试,代码终于能正常运行。除此之外,它要在重构之后继续之前的工作,否则会破坏类型检查或测试用例。虽然 Java 也能提供这些功能,但并没有 FP 的优雅,却拥有所有的 EE 的麻烦。


Scala 还有一些特质。它允许你创建自己的运算符或覆盖现有运算符,本质上是具有非字母数字标识符的一元和二元函数。您还可以通过宏(供编译器调用的用户定义函数)来扩展编译器,并通过隐式类(也称为“pimp库”模式)来丰富第三方库。


但 Scala 也有它自身的问题。



慢编译


Martin Odersky 曾提出的一个话题承认并彻底描述了 Scala 编译器的慢,并为此感到沮丧。与庞然大物和复杂的依赖关系树结合,这是一个复杂的解决机制 —— 之后几年里,工程师们就像保姆照顾婴儿那样看护着它 —— 在核心模块中添加一个模型类,这是一次休整,但利弊共存。最重要的是,编码的反馈时间会变得难以接受。(例如:代码测试重构在迭代间延迟)。



慢部署


缓慢的编译时间和一个庞然大物会导致缓慢 CI,反过来,就导致了冗长的部署。幸运地是,聪明的工程师可以并行在不同的节点上测试,把整体上的 CI 时间从一个小时压低到 20 分钟。结果很成功,但在敏捷部署上还是存在问题。


Tooling(工具集)


IDE 支持很差。 Ensime 在多个 Scala 版本项目(在不同模块上的不同版本)上存在的问题使得导入、非 grep 型跳转到定义等的优化无法实施。这意味着所有开源和社区驱动的 IDE(例如 Vim、Emacs、Atom)都会有不太理想的特性集。这种语言似乎太复杂,而不能创建工具集!

Scala 集成也尝试进行多个项目构建,最引人注目的是 Jetbrains 的 Intellij Scala 插件,它支持跳转到定义,允许我们跳转到旧版 JAR 包,而不是已修改的文件中。我们可以使用高级语言特性查看已破坏的高亮显示。

从积极的一面来看,我们只要根据笔记本电脑的散热板的响度,就能准确地判断该程序员使用的是 IDEA 还是 sbt。但对于 MacBook Pro 用户来说,散热非常耗电,不能没有电源插座。


在全球 Scala 社区的发展(以及非 Scala 社区)


对面向对象的批评由来已久,但真正进入人们视线是在 Lawrence Krubner 发布博文之后。从那以后,选择非面向对象语言的想法开始被接受。

我们中就有好几个成员一度在学习 Haskell。


Coda Hale 发给 Scala team 的邮件“Yammer 放弃 Scala”在 2011 年引起轰动,虽然消息陈旧,但当大家观念发生转变后,就会发现 Coda Hale 说的很有道理。参考以下叙述:


“因为有些内容只有库作者需要理解,部分的复杂度已经被移除了。但是当一个库的 API 牵涉到所有的复杂度时(因为大部分的功能在调用空间中解决细节问题),工程师就需要对库运行的机制和转变成 cargo-culting 代码片段的设计模型有一个精确地认识。”


从那时起,大玩家也纷纷加入,比如 Twitter 和 LinkedIn。


以下是 Raffi Krikorian 在 Twitter 上发布内容的引用:


“与四年前不同,这次我使用 Java 作为重写的部分,而不是 Scala。 [...] 一位工程师需要花两个月的时间才能充分高效率编写 Scala 代码。“


Paul Phillips 离开 Scale 的核心团队,他在一次长谈中对它进行了讨论,并绘制了一个恼人的语言状态图 - 与我们已知的形象形成鲜明的对比。


其中恼人的原因,你可以在这个 JSON AST 辩论中找到 Scala 社区的所有先驱。 读完之后的感觉就像这样:


需要一个替代品


在“Go”进入公众视野前,似乎没有真正可以替代 Scala 的语言。看看 Coursera 博客文章“为什么我们爱 Coursera 中的 Scala?”的节选:


“我个人发现编译和加载时间是可以接受的(它没有 PHP 编辑测试循环那么紧凑,但是相比于 Scala,我们可以接受其中的类型检查和其他细节)。”


这是另一个来自同一个博客的节选:


“Scala 确实很慢。并且,动态语言要求你不断地重新运行或测试代码,直到找出所有类型错误、语法错误和 null 反向引用。 ”



为什么 ‘Go’ 有意义


易于学习


我们当中的一些人在 下班后的MOOC 上用6个月时间来学好 Scala ,而重新拾起“Go” 只要两周。实际上,我们第一次接触 Go 代码是在十个月前的一个 Code Retreat 上,那个时候我就能编写一个非常简单的 类似马里奥的游戏 了。


我们总是害怕低级语言,它们会强迫我们处理不必要的复杂层,其实这些只是在高级抽象的 Scala 中被隐藏了,例如:Futures 隐藏了 signal(信号),syscall(系统调用)和 mutexe(互斥器),不过这对于所谓的全栈开发者来说可能并不算什么事。


自古以来,当我们不确定怎么让某些东西工作的时候就会阅读 语言规范。很简单对吧,规范很好懂的!对于我这样的普通人来说意义非凡。我对 Scala(和 Java) 不满意的是看不到一个问题的完整上下文,因为它太复杂了。在看代码时,一份亲切完整的指导手册应该能在我对语言进行臆测时给我信心,并成为印证我决断正确与否的准则。


越简单的代码越易读


没有 map,没有 flatMap,没有 fold,没有泛型(generics),没有继承(inheritance)......我们是错过了他们吗?而让我们去做,大概只要两周。


我们一时半会说不清为何它在没有借鉴 Go 的情况下,也具有良好的表现力。但无论如何,Russ Cox,Golang 的领导者在 “Go 的平衡” 上做得很好(详情请看他在 2015 年写的  keynote)。


事实证明,在没有约束的情况下写出的代码,会让他人难以理解,无法把握其中的逻辑。反过来说,有人也会因为理解了别人无法理解的代码而自命不凡。但从动力学上来看,这种公开考量智力的事并不利于团队的发展,而当复杂的代码出现时,这种情况又在所难免。


从代码复杂性的角度来说,这不仅仅针对我们的团队;很多非常聪明的人都会这样做(持续去做)直到走向极端。有趣的是,因为在 Scala-land(也包括 Java-land)上依赖地狱无处不在,在我们最终使用一些工程的时候,我们就会觉得我们的代码库太复杂(例如:scalaz)了,因为它们出现了传递依赖。




这些例子随机选自我们使用(持续维护)的 Scala 库:

Strong Syntax

(你能明白文件的目的是什么吗?)

Content Type
(在 Github 上已经停止维护)

Abstract Table
(你能给我解释一下外键的签名吗?)


Channels 和 goroutine 让工作变得如此简单


Channel 和 goroutine 在 资源管理上比基于 Future 和 Promise 的线程池更轻,这是不争的事实。编码时也更容易理解。


总结一下,我认为两种语言基于两种不同的方式基本上做了一样的工作,最后目的是一样的。“Go”简单的原因可能是它的工具集有限,你在反复使用之后就掌握了。而 Scala 的选项演变频繁,很难精通它的技术。


案例学习







请到「今天看啥」查看全文