第 1 章
列表里的第一声
第一封邮件在2008年2月6日发出。里奇·希基没有选择在某个技术大会上宣布这个消息,也没有在博客里贴出一篇宣言式的文章。他只是向Common Lisp社区里一些认识他的人发了一封简短的电子邮件,告诉他们自己完成了一个做了两年半的项目:一门运行在Java虚拟机上的Lisp方言,名字叫Clojure。这个动作本身不太像一场语言发布的常规仪式。彼时距Python 2.0发布已经过去了八年——那是一个有发布事件、有版本号体系、有社区管理结构的成熟生态。而希基的邮件更像一个手艺人推开作坊的门,对街上几个相熟的同好点了点头,说,我做完了,你们来看看。邮件的措辞没有营销腔调,没有路线图承诺,甚至没有刻意强调这门语言的优势。他只是说,开发快要完成了。这个时刻之所以值得停下来仔细看,是因为它包含了后来一切结构的种子。希基在那封邮件里不是“核心决策者”——这个词是后来的发明,是社区在无数次争论和选择之后回过头来贴上的标签。
在2008年2月,他只是一个开发者,花了两年半时间,没有外部资金,把大部分时间都投入到一个项目上,然后觉得差不多可以给别人看了。他此前做过类似的事:dotLisp,一个基于.NET平台的尝试;更早之前,他还试过三次在Lisp与Java之间建立互操作——Common Lisp的Java外语接口、Lisp的外语对象接口、以及一个Lisp友好的Java Servlet接口。这些项目都没有成为后来的Clojure,但它们留下了一种工作方式:反复回到同一个问题,每次换一个角度再试一次。那封邮件的收件人名单现在已不可完整复原。但从早期邮件列表的讨论语气和引用线索可以推断,最初的接收者大多来自Common Lisp圈子。这意味着Clojure的第一个听众群体不是Java程序员,而是一群已经在Lisp传统里浸淫多年的人。他们熟悉S表达式,熟悉宏,熟悉函数式编程的习语。他们带着一套完整的审美惯性进入这个对话空间。
而希基要做的,不是向他们推销一门新语言——他对Lisp的忠诚是毋庸置疑的,他的设计动机恰恰来自他对Common Lisp的深刻理解和不满足。他要做的,是在这个熟悉的语法表面之下,解释那些不同的设计选择。邮件列表很快建立起来。Google Groups上的“Clojure”组在二月下旬开始有了稳定的讨论流量。最初的三个月——二〇〇八年二月到四月——构成了一个独特的观察窗口。在这段时间里,社区的规模小到每个参与者的声音都清晰可辨,但讨论的密度已经足够形成模式。翻看那个时期的存档,会看到一种后来很少再现的景象:几乎所有问题都是开放的,所有回答都是试探性的,没有现成的惯例可以引用。规则尚未被写下来,但它们正在被说出来。早期订阅者的构成可以从讨论主题中大致推断。一部分人来自Common Lisp背景,他们的问题集中在类型系统、宏的卫生性、以及与现有Lisp实现的兼容性上。
另一部分人来自Java生态,他们更关心与Java类的互操作语法、构建工具集成、以及性能特征。还有一小部分人来自其他函数式语言社区——Haskell、Erlang、甚至早期的Scala——他们带来的问题是关于惰性求值、并发模型和类型推断的。这三群人进入同一个邮件列表,带着各自的技术惯性,开始提问。而希基的回复方式,从一开始就呈现出一种后来被反复讨论的风格:温和、冗长、反复回到设计原则。二〇〇八年三月,一个订阅者发帖询问为什么Clojure不支持尾调用优化。这个问题在函数式编程社区里是一个经典话题。Scheme规范要求实现必须支持尾调用优化,Common Lisp则没有这个要求。对于从Scheme传统过来的人,缺少尾调优化是一个显著的缺失;对于从Java过来的人,这可能根本不是一个问题。
希基写了一篇很长的回复,从JVM的字节码限制说起,讲到Clojure提供的替代方案——loop/recur构造——的设计理由,再回到语言设计哲学上关于显式递归与隐式递归的权衡。最后他承认了这种设计的不完美之处,但解释了为什么在当前约束下这是最好的选择。这个回复的结构值得仔细分析。它没有使用权威口吻——希基没有说因为自己是语言作者所以这样设计。它也没有回避问题的复杂性——他花了大量篇幅解释技术约束,假设提问者有能力理解这些细节。它把整个讨论的框架从“这个功能缺不缺”转换成了“在这个约束条件下,什么样的设计是最优的”。这不是一个命令,而是一种邀请:邀请提问者进入设计者的思考过程。同样的模式在最初三个月的邮件列表里反复出现。有人质疑为什么Clojure使用向量而不是列表作为主要的序列数据结构。希基的回复追溯了数据结构选择与不可变性、持久性、以及缓存局部性之间的关系。有人问为什么没有提供可变的变量。
希基从标识与状态的哲学区分讲起,再落到引用类型的设计语义上。有人对宏系统提出改进建议。希基会先认真考虑建议的合理性,然后解释当前设计的约束来源——有时是JVM的限制,有时是与其他语言特性的交互,有时是尚未解决的设计难题。这种回复风格的一个重要特征是其时间投入。写一封那样的邮件需要二十分钟、四十分钟甚至更久。它不是那种可以在手机上快速回复的东西。它要求回复者暂停手头的工作,进入一种解释性的写作状态。对于一个还在完善语言实现、没有团队支持的独立开发者来说,这种投入是非同寻常的。但希基持续地做了下去。在最初的三个月里,他的回复几乎覆盖了每一个提出实质问题的线程。这种投入产生了两个层面的效果。最直接的效果是认知层面的:早期订阅者逐渐理解了一门语言的设计决策不是任意的偏好组合,而是一组互相约束的选择。尾调优化的缺失不是“还没做”,而是与JVM互操作这一核心设计目标之间的权衡结果。
不可变数据结构的强调不是教条,而是与并发模型设计一体的工程判断。更深层的效果是社会层面的。希基的回复方式为这个空间设定了一种论证标准:技术讨论应该回到设计原则上。这不是一条被写下来的规则——当时没有任何行为准则文件——但它通过反复实践变成了一种预期。当新来者提出一个已经讨论过的问题时,老订阅者会给出链接,或者简要概括之前的讨论结论。当有人提出一个真正新的问题时,讨论会沿着希基示范的那种路径展开:从问题出发,分析约束条件,探讨替代方案,最后落回到语言的整体设计逻辑上。这个过程并不总是和谐的。最初三个月里出现过几次小规模论战。一次是关于命名约定的。Clojure的函数命名使用了一种与Common Lisp不同的风格——比如用更短的名称替代了Common Lisp中那些承载了历史记忆的长函数名。一些从Common Lisp迁移过来的开发者对此感到不适。
他们认为这些传统名称承载了Lisp社区的知识积累,改变它们意味着切断与那段历史的联系。希基的回应是耐心的但也是坚定的:他解释了选择更短、更通用名称的理由——降低新手的认知负担,让函数名更接近它们在函数式编程中的通用名称——但他没有让步。这场论战很小,可能只有十几个人参与,持续了不到一周。但它的结构预示了后来许多更大争议的模式:一方从传统的连续性出发提出质疑,另一方从设计的一致性和可接近性出发进行辩护。没有投票,没有最终裁决。论战逐渐平息,不是因为某一方被说服了,而是因为讨论的能量耗尽了。命名约定保留了下来。那些强烈反对的人中的一部分留在了社区里,一部分离开了。另一次论战是关于宏系统的卫生性。Common Lisp的宏系统是不卫生的,这意味着程序员需要手动避免变量名冲突。Scheme的宏系统是卫生的,编译器会自动处理这个问题。一些来自Scheme背景的开发者认为Clojure应该采用卫生宏系统。
希基的解释再次回到了设计原则上:Clojure的宏系统设计选择是在简单性、表达力和JVM互操作性之间权衡的结果。他承认卫生宏的理论优势,但认为在当前阶段引入这种复杂性不符合语言的整体目标。这场论战的结局与命名约定之争类似:没有赢家,但讨论本身沉淀下了一些东西。那些参与争论的人——无论站在哪一边——都经历了一个过程:他们必须用代码示例来支持自己的论点,必须回应对方的技术论证,必须面对语言设计者本人的详细解释。情绪化的表达没有消失,但它们被更长的、更技术性的回复所包围和稀释。这不是因为有人制定了讨论规则,而是因为希基的示范行为创造了一种引力场:在这个空间里,长篇的技术论证比简短的情绪表达更能获得回应。这就是共识仪式的原始形态。这个说法描述的是社区通过反复实践形成的、具有固定程序和非成文规则的决策集会。
在二〇〇八年的邮件列表里,这种仪式还没有任何正式的形式——没有主持人,没有议程,没有投票程序——但它已经有了一个可辨认的结构:问题被提出,约束条件被分析,设计原则被引用,替代方案被探讨,然后讨论自然平息。这个结构不是被设计出来的,而是在一次次讨论中被重复出来的。那些不成文的规则也在这个过程中逐渐成形。提问前需先阅读源码——这条规则从来没有被明确宣布过,但当一个新来者提出一个可以通过阅读源码回答的问题时,回复往往是沉默或者一个简短的指向源码的链接。反驳需附带代码示例——同样没有被写下来,但那些只表达不满而不提供替代方案的帖子很少引发有意义的讨论。情绪化表达会被沉默消解——不是被删除或被警告,而是被忽略,被更技术性的回复所覆盖。这些规则构成了后来被称作隐形宪法的第一层。这个说法指的是一套非成文的治理规则体系,由邮件列表存档、会议记录、库命名规范和补丁接受模式共同构成,其约束力不来自正式授权,而来自社区成员对违反后果的集体预期。
在二〇〇八年春天,这部宪法还只有寥寥几条条款,而且全部是负面的——它们规定了什么样的行为不会得到回应,什么样的提问方式会被忽视——但它们已经开始定义“Clojure人”的边界。这个边界不是通过排斥来定义的。早期邮件列表里没有驱逐过任何人。但那些不适应这种讨论风格的人会自然淡出。他们可能觉得这里的回复太冗长了,或者觉得自己的意见没有被足够重视,或者觉得这门语言的设计方向与自己的偏好不合。他们的离开没有引起注意,因为邮件列表的订阅量在稳步增长。留下来的人逐渐形成了一个核心群体:他们学会了用代码示例说话,学会了在提出质疑之前先理解设计约束,学会了在争论中区分个人偏好与技术问题。希基本人在这个过程中的角色也在演变。在最初的几周里,他几乎回复了每一个帖子。随着核心群体的形成,一些早期订阅者开始替他回答新来者的问题。他们的回答往往模仿了他的风格——引用设计原则,解释约束条件,提供代码示例——尽管可能不如他那样详尽和有说服力。
这种模仿不是被要求的,而是自然发生的:在一个小型社区里,你能看到什么样的行为获得回应和尊重,然后你会调整自己的行为去匹配那个模式。到了二〇〇八年四月末,邮件列表已经呈现出一种稳定的日常节奏。每天有几封到十几封新邮件。大多数问题在二十四小时内得到回复。技术讨论的质量保持在较高水平——部分是因为那些不会带来高质量讨论的问题已经被沉默机制自然过滤掉了。希基的回复频率有所下降,不是因为他不活跃了,而是因为其他人开始承担了一部分解释工作。这个变化是微妙的但重要的。它标志着一个转变:从一个人回答所有人的问题,到一个群体共同维护一套讨论标准。这个转变不是通过任何正式的程序完成的——没有宣布过任何人的资深成员身份,没有授予过任何管理权限——它只是在邮件列表的日常运作中发生了。如果用一个比喻来描述这个过程,它像一条河流的形成。最初的水流是希基一个人提供的——他的邮件设定了方向和速度。随着更多人的加入,水流开始自我维持。
河床在反复冲刷中逐渐成形——那些不成文的规则就是河床的轮廓。后来的水流会自然地沿着已有的河床流动,不是因为有什么力量在强迫它们,而是因为那是阻力最小的路径。这个比喻也适用于理解精英治理在这个社区中的含义。精英治理的核心是由少数技术权威负责最终决策,但这种权威必须通过透明讨论和一贯原则来赢得认可。在二〇〇八年的邮件列表里,希基的权威不是来自他的身份——他不是任何公司的技术总监,不是任何基金会的负责人——而是来自他在每一条回复中展示的对设计原则的把握和解释能力。他的权威是被每一次讨论重新确认的:当他的解释说服了足够多的人,当他的设计选择经受了足够多的质疑而没有被推翻,权威就积累了下来。但这种权威从来不是绝对的。它不是那种“就这样定了”然后关闭讨论的权力。它是一种更微妙的东西:一种对讨论框架的定义权。
希基通过他的回复方式定义了什么样的论证算作有效的论证——必须回到设计原则,必须考虑约束条件,必须提供可操作的替代方案——而那些不接受这个框架的人会发现自己在讨论中越来越边缘化。这不是因为他们被禁止发言,而是因为他们的发言无法在这个框架内获得牵引力。这就引出了那个需要正面回应的问题:Clojure的存活是否主要归功于希基的个人权威和JVM生态的寄生优势?社区共识是否只是事后合理化的表象?JVM生态的优势是真实的。Clojure能够直接调用任何Java库,这意味着它在诞生之初就拥有了一个庞大的可用软件生态。这个优势降低了迁移成本:一个Java程序员可以在不放弃已有代码库的前提下尝试Clojure。早期邮件列表里有相当数量的帖子是关于如何调用特定的Java库、如何处理Java异常、如何管理Maven依赖的。这些问题与语言设计本身无关,但它们构成了日常讨论的重要部分。
但如果把Clojure的存活主要归因于JVM寄生优势,就无法解释为什么其他同样运行在JVM上的新兴语言——其中一些也有强大的个人领导者——没有建立起同样持久的社区结构。JVM提供了技术基础,但没有提供治理模式。邮件列表里那种特定的讨论风格、那些不成文的规则、那种通过反复阐述设计原则来建立共识的做法——这些不是从JVM生态里继承来的,而是在这个特定群体的互动中生成的。至于个人权威的解释,它的问题在于混淆了权威的来源和权威的效果。希基的个人权威确实在社区治理中发挥了重要作用——后来所有重大争议最终都由他做出决定——但这种权威本身是在邮件列表的日常实践中被建立起来的,而不是事先存在的。2008年2月的希基不是一个有权威的人。他是一个在邮件里耐心解释设计意图的开发者。他的权威是在解释的过程中积累的,而解释的过程本身就是一种共识建设:每一次解释都是一次邀请,邀请对方进入设计者的思考框架。这就是为什么说社区共识不是事后合理化的表象。
共识不是在一次投票或一份宣言中达成的。它是在数百封邮件、数千次回复、无数次重复的设计原则阐述中逐渐凝结的。每一个参与过早期讨论的人都经历了这个过程:他们起初可能质疑某个设计选择,然后读到希基的解释,然后提出反驳或追问,然后得到进一步的解释,然后——如果他们被说服了——内化了那条设计原则。这种内化不是对权威的服从,而是对一套逻辑体系的接受。到了2008年5月初,Clojure邮件列表已经不再是一个简单的技术问答场所了。它变成了一个有隐性规范的公共空间。新来者会感受到这种规范的存在——他们可能注意到某些帖子得到了详细回复而另一些被忽略了,可能注意到某些提问方式引发了讨论而另一些被沉默消解了——然后他们会调整自己的行为去适应它。这种调整不需要任何人告诉他们规则是什么。规则就在存档里,在那些被认真对待的帖子和那些被礼貌搁置的帖子之间的对比中。这个空间的形成是一个历史事件。
在那个五月午后的邮件里,新来者得到的不是希基本人的回复,而是一个早期订阅者引用的三周前的解释链接,外加一段自己写的代码示例。这个动作的每个组成部分都值得拆开来看。引用链接——这意味着讨论有历史,历史可以被检索,检索到的内容具有论证效力。补充代码——这意味着回应不只是复述权威,而是要在权威奠定的框架内提供新的可操作证据。语气耐心——这意味着回应的目的不是终结讨论,而是延续讨论,让提问者进入同一个思考过程。这些组成部分合在一起,构成了一个微型的共识仪式。没有人宣布仪式开始。没有人规定仪式的程序。但如果你把2008年2月希基回复尾调优化问题的那封长邮件,和五月十二日这个早期订阅者的回复放在一起比较,你会看到同一个结构:从问题出发,引入约束条件,引用设计原则,提供替代方案,最后落回到语言的整体逻辑上。这个结构被复制了。复制它的人可能并没有意识到自己在复制什么。
他只是在前几个月里反复看到这种回复方式获得了讨论的延续和社区的尊重,于是他学会了。学习的内容不是某条具体的技术知识——尾调优化在JVM上的限制是可以查文档的——而是一种论证的语法:什么样的句子能在这个空间里产生意义,什么样的句子不能。
这种论证语法的核心在于一个看似简单实则苛刻的要求:任何对设计选择的质疑,都必须先承认设计约束的存在。你不能只是说“这个功能应该有”,然后列举其他语言怎么做。你必须先理解JVM字节码的限制、或者不可变性与并发模型之间的耦合、或者语法形式与宏展开之间的交互——然后在这个约束空间内提出你的论证。希基在最初三个月里反复做的事情,就是把这些约束从背景提到前台。当一个提问者说“为什么没有尾调优化”,希基的回答不是“因为JVM不支持”——那是一个事实陈述,不是解释。他的回答是把JVM不支持这个事实,放进一个更大的设计选择的网络里:我们选择了JVM因为它的生态;JVM不支持尾调优化;我们提供了loop/recur作为替代;loop/recur的设计与不可变性和显式递归的风格一致;这种一致性降低了代码的认知负担。这个解释链条的每一个环节都是可质疑的。你可以质疑选择JVM是否明智。你可以质疑loop/recur是否真的能替代尾调优化。你可以质疑显式递归的风格是否真的降低了认知负担。但你不能忽视这个链条的存在而直接跳到结论。这就是那部隐形宪法的第一条实质性条款:论证必须进入设计者的约束空间,否则不予回应。
这条条款从未被写下来,但它的执行是严格且一致的。翻看2008年3月到四月的存档,会发现那些忽视约束空间的帖子——不管写得多长、情绪多强烈——几乎都沉没了。它们没有被删除,没有被驳斥,只是没有人回复。沉默在这个空间里不是中立的行为。它是一种负反馈机制:不回应意味着不认可论证的有效性。新来者很快会学到这一点。他们可能第一次发帖时抱怨某个设计选择,然后发现帖子在二十四小时内没有任何回应,而同一时间其他技术问题得到了详细回复。这种对比本身就是一种教育。有些人会调整自己的提问方式,重新发帖,这次附带代码示例和对设计约束的考虑。有些人不会调整,然后他们就不再出现了。这个过程看起来像是自然选择,但它不是自然的。
它发生在2008年2月到四月之间,发生在一个Google Groups邮件列表里,发生在一群从不同技术传统迁移而来的程序员之间。它的初始条件包含了希基的个人风格、JVM生态的技术约束、早期订阅者的多元背景、以及邮件列表这一媒介本身的特性——异步的、文字的、可存档的、需要一定时间投入才能参与的。这些条件中的任何一个如果不同,结果可能就会不同。如果希基的回复风格是简短和权威式的,邮件列表可能会发展出一种不同的讨论文化——更高效但更少共识建设。如果早期订阅者全部来自同一个技术背景,讨论可能会更同质但更少创造性摩擦。如果媒介不是邮件列表而是一个实时聊天平台,存档和反思的空间会更小,不成文规则的形成可能会更慢或更不稳定。但这些都只是反事实推想。实际发生的是:一个开发者发了一封邮件,一些人回复了,讨论开始了。在接下来的三个月里,一个文化场域从这些讨论中浮现出来。它不是被设计出来的,但它有自己的结构、自己的规则、自己的边界定义方式。
它后来成为所有重大决策的辩论场——那些关于语言特性、社区治理、资助模式的争议都发生在这个邮件列表里——而争议的形式和节奏,在最初三个月里就已经奠定了。存档翻到2008年5月12日。一个订阅者发帖问了一个关于序列抽象的问题。希基没有亲自回复。一个早期订阅者——他的名字出现在二月的最初几封邮件里——给出了回答。回答引用了三周前希基在一个相关线程里的解释,然后补充了自己的代码示例。帖子的语气是耐心的、技术性的、回到了设计原则上。那个时刻安静地过去了。在那个回复的结构里——引用先例、补充论证、维护讨论框架——已经可以看到后来那部隐形宪法的轮廓。它不是被写下来的法律条文。它是一部由邮件列表存档构成的法律,其条款存在于那些被反复引用的解释里,其约束力存在于那些被沉默消解的帖子所留下的空白中。2008年2月的那封邮件很短。它没有宣告一场革命。它只是说,我做完了,你们来看看。一些人来了,看了,开始提问。回答开始了。一部隐形的宪法在问答中开始书写它的第一条条文。没有人意识到这一点。他们只是在写邮件。