对于一门「现代」的编程语言来说,没有模块支持和像样的包管理器好像说不过去,不过语言的模块机制和外部实际的生态最好是分开讨论。这篇文章就是对某些语言的依赖问题的吐槽,毕竟都说古往今来,当属配环境最难。

首先是Java、Scala等一众基于JVM的语言,jar依赖地狱可以说是声名远扬。像sbt这种工具创建的helloword示例工程,居然都能下载好几屏的依赖,实际工程就更不必说。而由于没有标准的自动构建工具,第三方构建工具可以说是相当流行,无形之中让初学者又多了些负担(由于Java奇葩的包名和目录规则,很难用make来构建;另外,不管是maven还是gradle等,国内的下载速度都极其感人)。另一方面,管理JRE/JDK版本也是一件令人抓狂的事情。

然后是npm,这个全球最大的软件生态。在node这种解释语言里,显然调库会更频繁。前段时间有一个只有数行的库is-promise进行了一次更新,结果由于疏忽出了语法错误,导致全球大量的软件(约3,500,000)构建不过。npm相比jvm生态而言,嵌套依赖的问题尤为严重。但是从用户的角度来讲,毕竟有yarn这种第三方的管理工具可以弥补速度的问题,本身作为解释语言也不需要构建,也不存在虚拟机的问题,所以npm的体验还是很不错的。而且node解释器其实还算是轻量级,版本管理也容易。

Python、Ruby、Perl这几个脚本语言就要正常得多,毕竟有(半)官方的管理工具和托管平台。当然,我觉得最本质的一点在于,这些语言基本不会用于构建大型项目,从而依赖的崩溃并不会产生多大影响——毕竟小脚本用用本地的版本就行了,犯不着更新到最新的版本——大概这也是现在还有人在用py2,perl4的原因吧。而也是因为脚本一般只需要非常非常单一的功能,所以很少会引入大量的依赖。

OCaml的包经常有比较严格的编译器版本限制,所以管理OCaml版本就成了必做之事,所幸有官方的包管理工具opam。一般来说这是比较简单的,不过opam的所有包实际上都是先拉取源码再构建,并没有提供二进制形式的包,时间耗费多不说,有时候编译器出了点问题,包就构建不过(其实也能理解,OCaml毕竟是一个学术项目,服务器的开销不菲,只能把opam搭建成类似包目录的工具,实际代码都托管到github等之上)。所以虽然opam(其实就是github)的下载速度不慢,安装却也是很费时间的。所幸OCaml的包不多,每一个功能都比较有用,本身也比较小众,所以不至于出现依赖的问题。