起。曾经的动态类型语言粉丝
我曾经是一个 Ruby Developer。 我写了差不多4年的 Ruby,曾经是一个强烈的动态类型语言支持者。 我想这很大程度上源于我对 Ruby 的喜爱。 Ruby 的设计良好,书写起来很程序员友好。 所以当时的我认为,Ruby 的各种设计都是良好的,包括动态类型这一点。 之前写过一些 Pascal 和 C,让我认为不停的声明变量的类型完全是多此一举的事情,你看,我不声明类型,Ruby 写的也很愉快和正确呀。 但是后来的经历告诉我,静态类型语言,尤其是在大型项目中,如此长盛不衰是有原因的。
承。我是动态类型语言粉丝了好多年
一开始我一直都是在写 Ruby on Rails。 因为我喜欢快速回馈,简单快速的就可以看到自己修改的成果。 过去在 GitCafe 创业,Startup,项目不大,没大到需要拆分代码库的程度。 Ruby 和 Ruby on Rails 在这种快速迭代不停转型的场景下基本就是大杀器。 代码行数和字符数都很少,写起来读起来都很快。 代码表意丰富,语义简单,连测试都不用写,因为代码好读,而且业务变化快,写出来的代码都不知道会生存多久,不清楚的地方写个注释就是了。 那时候逢人便会推销 Ruby。 It just works。
之后去 Twitter 做了一暑假的实习。 同样是在写 Ruby on Rails,只不过项目很大,大到所有人都想拆分代码库就是拆不了的程度。 同时又写了很多 Javascript 的代码,同样都是动态类型的语言。
那时候我的世界里都是动态类型的语言,我觉得静态类型的语言都是老古董,已经上不了舞台了,还在台上的都是公司太大没法迁移到另外的语言平台而造成的,你看,Google 这么大的公司都不抱着 Java 不放开始启用 Python 了,是吧。
不过在 Twitter 的经历让我隐约感觉这些代码读起来都不太痛快,代码跳转也比较痛苦。 我想代码库大了可能都这样。
转。岔路另一边我从未见过的美丽景象
转折点是我 Master 的最后一个学期。 这个学期之后两门课,一门是 Operating System,最后一个项目用 Python 写分布式计算系统 Spark 的扩展版本; 另一门是 Principal of Software Development,最后一个项目用 Java 写 Web 邮件客户端的后端 API 服务器,前端我选择用 Javascript 写单页面应用。
Java 我用的 IDE 是 IntelliJ IDEA 14;Python 和 Javascript 用的是 Sublime Text 3。 这是我第一次用 Java 写这么大的项目,而我以前却有还不错的 Javascript 的经验。 但是即使在我 Java 代码行数比我 Python 项目和 Javascript 行数加起来还要多的情况下, 我仍然感觉书写 Java 要轻松许多。 虽然并非是客观的对比测试,但是却让我重新思考了静态类型和编程系统的价值。 这也同时让我重新思考了 IDE 的价值,要知道我原先是个狂热的 Editor 支持者和 IDE 的贬低者。
到现在,我到 Google 开始工作,才发现在一些简单的工具的帮助下,即使是超大代码库,Java 依旧可以保持良好的可读性和重构性。
Java 是一个非常结构化的语言,它要求写作者把每个对象的各种属性都写到字面上,比如某个类的所有属性,属性的类型,和特性(final,volatile,static 等)。 虽然多了很多字符,但是给读者带来了非常多确定的信息,而不需要隐式的让读者自行判断与推导,这隐式的判断在动态语言中是非常普遍,甚至是根基。
我在进行 Ruby 开发的时候就会经常遇到有歧义或是有过多暗示、假设与类型推导,
因为语言把这些都给隐藏了,所以写代码的时候不用写他们,所以减少了很多代码量。
但是这些都需要阅读的时候自行脑补,所以阅读的时候会加重读者的负担。
所以开发的时候往往为了提高可读性,会将相关信息写到变量名中去。
比如我在写 Javascript 的时候会习惯把类型写到变量名的后缀中去:data_hash
,并把哈希结构写到注释中去,不然很快在几个 map
,reduce
等数据转换函数的调用之后,自己就会迷失在数据结构之中。
信息字面化的另一个好处是静态处理和分析,由于所有的东西都在纸面上,编译期就可以知道所有 symbol 所指的对象的各种信息,使得 IDE 里的语义化重构工具和跳转工具变得非常容易;
相对的,动态语言甚至难以确定 symbol 的类型,更不要提其对应的方法。
Ruby 的method_missing
给了写作者至高无上的动态方法能力,
却是 Ruby 的 IDE 几乎无法实现那些辅助工具,而这些小工具对于实际开发流程有非常大的促进作用。
合。天下分久必合
所以我想,动态语言和静态语言是两个方向,各有优劣,各有取舍。
直到我看了《七周七语言》。
这本书是本非常值得一读的书。 它跳过语法的例举,而专注于每一门语言最独特的特性,使得这本书每一页都意味十足,值得一读。 在这本书里,最后描述的语言,也是令我印象最深的语言是 Haskell。
Haskell 这门语言很有趣,是开源界少有的直接由委员会制定和发展的语言,而且却设计的很完善。 很多委员会由于纷争,使得设计支离破碎。 据一位委员所说,这是因为委员会的成员从一开始就在很多基础问题和设计方向上达成了一致。
Haskell 给我印象最深的特性是类型推断和函数泛型。
Java 里面,一个变量的类型是要写下来的,一个函数的参数和返回值的类型也是要写下来的。 Ruby 里面,都不要写。 Haskell 里面,不是必须写的可不写。
这带来了一个巨大的好处:保持语言静态特性的同时减少了大量代码。
想象一下,当我们将1+1
赋值给变量a
的时候,a
的类型是如此明显,而再声明其是int
实在是多此一举。
而在这种情况下,类型推断系统就可以帮助作者推理出这些变量的类型,所以写作者便可略过这些声明。
如果推断系统无法判断类型,便会提示作者增加类型声明。
而由于类型在编译期间就已经是可知的了,所以各种静态分析工具依然可以发挥作用。
函数泛型也有同样的好处。 如果你不声明类型,函数会默认推断出最上级、适用范围最广的类型。 缩小适用范围,意味着更多的检查,所以才书写更多的代码。
这意味着类型检查不是强制的,而是按需的。
所以我想说的其实就是一句话: 静态类型的语言会需要越来越少的代码; 动态类型的语言会增加越来越多的检查。
世界大同,万物归一。