最近在 Clojure 的邮件列表有很多关于自己所在公司不能使用自己喜欢的语言的抱怨,由此也引发了一些争论。类似的内容在很多相对非主流的语言或技术的用户社区都不难找到,例如 Erlang,Go 和 Haskell,不久以前可能 Node 甚至 Ruby 和 Python 都算是小众的。
有人把软件设计看做一门手艺,把程序员比作工匠,所以才会有 Software Craftsmanship 这样的运动。工匠非常重视自己使用的工具,有了顺手和习惯的工具才能事半功倍,这本是无可厚非的。但作为一个公司来说,为了避免技术上过度的碎片化和重用现有资源,无法避免会在这方面做出或多或少的限制。比如我在 Google 的时间里,在线上面对用户的产品只能使用 C++ 和 Java(YouTube 等收购的产品除外),Python 基本只用于内部工具。现在 Google 发布了 Go,可能选择多了一些。在这种情况下,喜欢使用一些小众技术或语言的程序员和公司之间的矛盾就产生了。
程序设计也是一门艺术。艺术的魅力一方面在于创作中可以有众多的选择,有众多的风格和流派,无所谓对错;另一方面也在于艺术家往往乐于接受挑战,在客观条件的限制下完成看似不可能的事情。比如在米粒这样非常不适合雕刻的介质上也能做出精美的微雕作品。学习 Clojure 的价值并不在于在工作中一定要用到这门语言,而是通过理解它解决问题的方法让自己成为更好的程序员,无论实际使用的是什么语言。如果喜欢函数式编程,那么在任何语言中都可以用它,不一定要强求使用一门函数式。事实上给一门语言打上「函数式」或者「面向对象」等标签都是人为的做法,很多时候本身就是存在争议的。
拿 C++ 做例子,大多数人会说它是面向对象的语言,但它的模版部分是一个真正的纯函数式语言。我曾做的一个项目是把 Google search 的 webserver 逻辑重写,用模版和 C++ 的静态类型系统来实现对后端 RPC 复杂数据依赖的管理,让没有相互依赖的 RPC 并行进行,而存在依赖的 RPC 以正确的顺序进行。现在还记得上线时的忐忑。这件事参考了 Haskell 用强大和完备的类型系统来加强程序正确性的做法,虽然在 Haskell 里会容易和自然很多,但肯定不可能为了这个优点把很大的 code base 重写。 同一时期我的另一位同事实现了一个非常高效的 C++ continuation API,和 Scheme 的 call/CC 一样好用,只是不知道后来有没有用在生产环境里。
学一门语言重要的是理解设计者解决问题的方法,这样也许客观条件限制你不能用它的语法,但你可以用类似的方法解决类似的问题。有句话说「当你只有一个锤子的时候,你看什么都觉得像钉子」。其实了解越多的语言、技术和工具,会越觉得没有必要执着于某一个选择。可以选择的时候就选择最适合的工具,没有选择的时候也能恰当利用手上的工具用合适的方法解决问题。大家要做 artist,不要做 zealot。