开源社区的暗面

June 08, 2021

“How to Use Open Source and Shut the Fuck Up At the Same Time”

去年在用 Node.js 编写一个 side project 的过程中,因为需要集成不同第三方网站的 OAuth 登陆,所以接触到了 passport.js 。虽然各类渠道都表明它似乎是 OAuth 解决方案的不二之选,但是在实际集成的过程中发现问题颇多,在前往 GitHub 上查看有没有相关的 issue 时,惊讶的发现 passport-github (passport 下允许使用 GitHub 进行 OAuth 登陆的子模块 )已经至少有两年没有新的代码提交了。正在我纳闷这个项目还会不会继续维护时,在主项目 passport 的 issue 里也找到了提出了相同问题的人:Library still mantained?

这则 issue 的讨论非常简短,很快就能阅读完毕。在我看来最能体现项目维护者对于这个问题的答复,是他直接对于这则文章的引用:

“How to Use Open Source and Shut the Fuck Up At the Same Time”

你甚至不用读完整篇文章,光是看标题就大致明白他的态度如何了。这篇文章含标题在内一共使用了 fuck 这个单词8次。它所表达的是作者对于开源社区目前“衣来伸手,饭来张口”和“端起碗吃肉,放下筷子骂娘”现象的不满:作者认为项目维护者完全是无偿在贡献出自己的时间,且从中没有丝毫的获利,也就没有义务满足任何人提出的任何需求;作者还认为使用开源项目完全是各位自己的决定,不爱用就滚——虽然“滚”这个词在是我提炼出来的,但用来表达作者的态度一点都不夸张。

这篇文章的作者可不是名不见经传的无名小辈,他是 Eran Hammer,是 Node.js 社区中赫赫有名的 web 框架 hapijs 和数据验证类库 joi 的核心贡献者之一,在 GitHub 上有超过 2k 的关注者。

过去一年因为工作的关系,我需要和越来越多的开源项目打交道,自然就被动地接触到了开源社区中各种讨论甚至争吵。虽然这些内容最终只不过沦为我和朋友们茶余饭后的谈资, 但联想到几年前 event-stream 被植入恶意代码 以及 antd 的圣诞节彩蛋 等一系列事件,不得不承认这些“八卦”已然让我对开源社区的信心产生动摇。终于, passport.js 作者的这则令我不适的回复则彻底点燃了我的好奇心:

我们究竟应该以怎样的姿态与开源项目相处?

这个时候我才发现似乎我们每个人都置身其中,但实际上我们每个人也都置身事外:你可能下载过 lodash 这个类库成千上万次,但是却对它背后的维护团队、演进路线和发布节奏一无所知;你会在antd 的圣诞节彩蛋事件的 issue 下会看到很多大跌眼镜的评论,但仔细想来你也无法对其掷地有声地反驳;抛开 Eran Hammer 文章中情绪化的文字,他所想表达的观点也并不无道理:项目消费者的权利和贡献者的义务是否具有天然正当性的?

这篇文章不会对上述的任何一个问题予以解答,它只不过是一个旁观者在碎碎念中表达出来的个人意见而已,充其量丰富了你的认知。你所认可的答案,要靠你自己去探索才行,

但它并非完全没有意义——借用贾樟柯2013年在接受《三联生活周刊》采访时说过一段话:我拍《天注定》就是想从中跳出来告诉大家,我们正在经历的时代到底是怎样的,只有把我们正在经历什么搞清楚,可能接下来才能知道将来要怎么办——同样地,开源社区也值得被审视和反思。落到我们的个人利益上,如果你正有打算发布开源项目的冲动或者回馈开源社区的想法,这篇文章在这些方面都能给你一些建议。

当我们在这篇文章中将自己抽离出来重新认识开源社区时,我们审视的并不是空气,而是实实在在的人和真真切切的事。所以文章选取了大量开源社区中的事例,来对观点进行说明,这些事例的选取是有倾向性的——我们当然可以畅想如果没有 Richard Stallman 或者 Linus Torvalds 开源社区会怎么样;如果没有 GitHub 的话 mailing list 的协作方式会比现在更好吗?但很多时候与其追求宏大叙事,不如随手截取一些开源社区的剖面展示在大家面前,这些接地气的例子始终会比 那些高高在上的假设更具有说服力一些。

“On whose authority?”

Chris Zheng 在2017年发表了一篇名为 On whose authority? 的文章,在这篇文章中他叙述了他个人从加入Clojure社区到失望离开的经历,并且着力痛斥了导致他离开的主要原因 1. 迷信明星程序员;2. 忽略社区的声音;他认为这些问题是由 Clojure 背后的商业赞助公司 cognitect 一手造成的。

这篇文章中频繁提到的明星程序员之一 Rich Hickey 在 Reddit 上对文章里提到的问题一一进行了回应,在回复的最后,他也毫不客气地指出对于开源社区的攻击等同于对所有无偿付出的贡献者的否定:

……In the end it’s about people. You can’t say f**k XYZ and deny that it is an attack on the people who work on XYZ…… it’s a bunch of people with families trying to make a living, pay their mortgages and send their kids to college. And, if you are talking about Clojure, you are talking to me. The indirection doesn’t mask the attack on people, their work and their choices. **

咨询行业中的金句“不管一开始看起来什么样,它永远是人的问题”(温伯格《咨询的奥秘》)在这里也同样成立——虽然我们三句话离不开“社区”,离不开“项目”,但我们谈论的本质都是人的问题。

事件背后的孰是孰非暂且搁置,不过这个“On whose authoirty?”(谁说的算?)实在是一个再经典不过的问题了:当一个开源项目发布到开源社区之后,项目的拥有者是依然享有“统治”它的权力,还是应该交由另一类人群来管理,是一个经久不衰的话题。

大部分真实情况没有那么复杂:谁拥有代码仓库提交权限,谁就有最后的决策权,甚至是生杀大权:所以 Linus Torvalds 才得以排除众议坚持 Linux 应该使用 GPL-2.0 而非 3.0 的开源协议;而 Dave Gamache 可以选择从2014年开始不再维护 skeleton,哪怕这个项目在 GitHub 上的收藏数量已经达到了 18.2k 次。

但现实是作为项目的维护者,你很难忽略社区发出的声音。或者准确来说,阻止社区发出声音。当我们承认这个无法避免的事实之后问题就变成了,应该如何对待社区的这些声音。

让我们看一个实际的例子。

prettier 是一个将前端代码格式化的工具,去年中旬开发者 Vadorequest 以 issue 的方式向社区提出了一则建议,他认为目前 pretttier 格式化过于追求格式美观,而忽略了代码的可读性,他希望工具在设计格式化规则时,能够将格式化之后代码的可读性也考虑其中。 如果你是项目的维护者你会怎么看待这则建议?独立来看它的目的只是改善愿景,甚至不存在代码改动的成本,采纳也未尝不可。但如果我们把它归纳到 feature request 的标签下整体看这一类需求的话,恐怕尽善尽美满足每一则提议是不现实的,一方面因为(我在下一节会谈到)维护者的精力有限,另一方面有的建议在提出时并非是经过深思熟虑的,甚至不同建议之间当中还会存在互相矛盾的情况。这种体验和你作为 leader 在团队中进行技术决策非常相似:在项目架构演化过程中会面临太多的诱惑和方向以供选择,我相信每一个给出这些建议的人都是出自真心,我也相信每一则建议都有它的道理,但你才是最终为决策负责的人。

即便这样的技术决策并非出自于个人之手,但也只可能出自于人数有限的小团体之中。因为集体的决策成本太高,它绝非是最佳实践。《团队协作的五大障碍》一书中指出的协作障碍之一就是欠缺投入,而欠缺投入的其中一个最重要原因就是追求绝对一致。回想你目前所在公司内网上的热门讨论,任何被提出的观点,大到制度改革小到文化衫投票,反对声音总是存在。在处理这些问题时我的意见正如我上一段所说,辨别声音的分量比感知声音的大小更重要,向结果迈进比尽如人意更有意义。请放心,无论是这样的团体还是个人都不应该是随机挑选出来的,他们应该符合某种资质,这种资质的合法性来源于多个方面,有来自于对于业务知识的长年积累,也有来自于对技术的深刻见解,这些沉淀有助于他们来把握架构的发展方向,并从容应对业务上的变化。

类似的观点早在《人月神话》一书中就提出过,在书中“外科手术”一章中作者指出“需要协作沟通的人员的数量影响着开发成本,因为成本 的主要组成部分是相互的沟通和交流,以及更正沟通不当所引起的不良结果(系统调试)”。在软件应该由尽可能少量人员开发的前提下,作者认为软件开发的团队模式类似于外科手术的方式进行组建,由一人拆解问题,其余人负责实施。当观点发生冲突时,由外科医生单方面进行统一。并且为了追求系统中的概念的完整性,专制统治也是可取的。

归根结底,我的结论是技术决策不应该是直接民主的。苏格拉底之所以否定雅典城邦实现的直接民主制度,是因为在他认为既然我们生病的时候会去找医生看病,那为什么当城邦的健康出现问题的时候,却会认为应当求助于普通人的意见呢?技术决策也是同理,对于开源社区而言,核心维护团队或者个人拥有对于整个项目最完整的上下文。长时间倾听社区的声音,使得他们对于项目的现状,消费者的诉求有全面的了解。在掌握更完整的信息的前提下,我相信他们理应比个体做出更理性的决策。

开源社区中刚好有一个概念描述了这类角色的存在:仁慈的独裁者(Benevolent Dictators)或者是终身仁慈独裁者( Benevolent Dictator For Life),简称为BDFL。

顾名思义,独裁者一言九鼎,他拥有对项目社区中争议问题的最终决定权。你大可不必担心他成为一名滥用权力的“暴君”,因为一方面这个称谓只是一个荣誉头衔,是对退居二线曾经常年为开源社区付出努力的贡献者的认可(比如 Guido van Rossum 之于 Python);另一方面他并非是开源社区中唯一的决策者,而是当作解决争议问题的终审裁判。在问题触达他之前,社区的公共事务通常由少数人组成的委员会负责解决,也就是我们熟知的 TSC (Technical Steering Committee)。

比如在 Node.js 的社区治理章程中,就详细说明了 nodejs/node 是由核心协作者(Core Collaborators)来维护 。任何一则 pull request 都需要两位协作者的批准才能合入到代码中。协作者负责社区的日常运营,例如贡献代码、完善文档以及解决疑问等等;其中一小部分人组成的 TSC 则负责决定技术的演化方向,制定社区章程等更高层次的议题。

而开源项目 SciPy 的治理方式则是委员会(Steering Council)与独裁者并存。委员会的候选成员在过于的一年中对项目的贡献必须有质量和数量上的保证,由现有委员会提名产生。委员会负责项目的日常运营工作,包括但不限于项目方向的制定,社区问题的解决,文档的更新等等。而当前的 BDFL Pauli Virtanen 则只在委员会处理问题发生“死锁”时做出决策。为了防止权力被滥用,项目还鼓励任何与 BDFL 意见相左的人 fork 一份属于自己 SciPy 代码库

如果以 GitHub 诞生之日为一个起点开始算起,开源社区至少已经经过了数十年的发展,其中很多实践已经相当成熟了。 https://opensource.guide/ 是 GitHub 官方发布的一个站点,来指导大家如何参与和维护开源项目,上面描述几种社区治理形态几乎就是在 Leadership and Governance 一章中的全部了。抽象看,运营一个开源社区和运营其他形态的实体社区(比如大学社团)需要解决的问题没有太大不同,你同样要面临拉新,提高留存率,发展第二梯队等问题;甚至你还需要想方设法拉取赞助(对应于给项目建立赞助页面),为社团制定活动规范(对应于社区的 Code of Conduct)等等。

最后,我认为无需担心开源社区中“掌权”的个人和小团体会演变成僭主(一个人统治且为了私人利益)或者寡头(少数人统治且为了私人利益)。因为在下一节中我会谈到,维护开源项目无利益可言:与社交网络恰恰相反,你无法将日益增长的“粉丝”流量兑现,它越受欢迎,你心力交瘁的感受越是强烈。

现在我们已经回答了一个问题,那就是在开源社区中应该由谁说的算。如果说这场归宿是有关开源项目终点的话,别忘了我们还没有回答另一个更关键的问题,那就是开源项目的起点在哪:为什么要有开源项目。

“Pay Me or Fork This”

如果一则颇受欢迎的开源项目的维护者突然宣布停止维护项目,你会作何感想?我猜你第一反应情绪大多是负面的:疑惑、不解、失望、担心——至少你肯定不会为他感到高兴。

但为什么不呢?为什么他要长达数年的无偿的为成千上万人贡献出他的业余时间?

首先我们要承认一个这样的事实:绝大部分开源项目成立的初衷大都出自于程序员的个人需求,比如爱好、学习、市面上还没有这样的轮子等等,绝非为了什么远大的目标。Linus Torvalds 创造 Linux 当初的目的“只是想作为一个爱好而已”(just a hobby, won’t be big and professional ),他发布 Git 系统也只是“想用一些脚本来更高效的追踪代码”(some scripts to try to track things a whole lot faster)。甚至这两者的命名都是极个人化的。

甚至有的人只是为了好玩——event-stream 在被曝出安全问题之后,项目的原维护者 Dominic Tarr 对于他为什么创造和离开这个项目给出了这样的解释

I didn’t create this code for altruistic motivations, I created it for fun. I was learning, and learning is fun. I gave it away because it was easy to do so, and because sharing helps learning too.

If it’s not fun anymore, you get literally nothing from maintaining a popular package.

在我个人代码仓库中,收藏数量排名前三的开源项目也都统统源自于我的个人需求:Node-Simple-Cache 是为了解决一个工作上的缓存模块功能;search-trie-tree 只是突发奇想希望更高效的解决问题;而 scrapy_douban 只是为了解决当时个人想在豆瓣小组里找房源而豆瓣又不支持合并查找和排序的问题。

还有另一个我们可能都没有意识到乃至不愿意承认的原因是:GitHub 还具有社交属性,程序员都想通过这个平台扩大自己的影响力。2019 年有一篇名为 《社会地位即服务》(Status as a Service)颇有意思的文章事无巨细的解释了现代社交网络背后运作的原理。文中围绕的中心以及反复提及的出发点就是“对于地位的渴望是源自于人类内心的本能”:

people are status-seeking monkeys, always trying to seek more of it in the most efficient way possible

并非所有渠道和平台提供的社交地位都值得被一视同仁,社交地位价值还和稀缺性有关,如果用户不需要付出努力就能轻而易举得到的话,那么以这种方式收获的虚拟地位一文不值。GitHub 自然很具有想达成这层目标的潜质,它对所有人开放但并非所有人都能从平台中脱颖而出。但它毕竟不是为“社交”而生,所以从来没有想过解决社交网络里最常见的通病:如何避免赢者通吃,如何解决蒸发冷却效应。 这样的趋势是不可逆的,web 1.0 到 2.0 的进化就是最好的证明。2.0 时代的网络将曾经的信息孤岛紧密的连系在了一起,将信息的流通的方式从单向变更为了四通八达。这正是《未来简史》中描述的数字主义兴起的里程碑:如果你体验没有被分享,没有人看到那就是没有价值的。数据由此产生了异化,曾经数据只是内容的点缀,而现在内容是数字的附庸。

以上状态无论是对于传统上内容媒体还是开源项目都同样成立。不知道你有没有想过这样的一个问题:如何衡量开源项目的价值?我相信你第一时间想到的依然是各种各样的数值:收藏数量、fork 数量、维护者解决 issue 的效率等等——所有这一切在项目 Github 主页的 Insights 标签下全部都有体现,甚至还包括你想不到的依赖图谱——然而有意思的地方在于以上指标其实是围绕项目生长于平台的间接信息,而项目本身比如代码质量和它能提供的业务价值却因为无法被量化而被忽略。

事情比我们想象的还要复杂。

2016年 Azer Koçulu 因为他发布在 npm (JavaScript 的包管理平台)上名为 kik 的模块与某个公司的注册商标相同,而被律师要求从 npm 平台上撤下(unpublish)。一怒之下他撤下了所有的发布在 npm 上的模块。其中包括一个名为 left-pad 的模块。虽然这个模块只有17行代码,但却导致整个互联网的JavaScript 开发工作陷入瘫痪,因为有一些极其重要的模块比如 Babel.js(一款 JavaScript 代码的编译工具)对 left-pad 存在依赖。以至于 npm 的 CTO 和创始人之一 Laurie Voss 不得不采取史无前例的手段来解决这个问题——恢复被撤下的 left-pad 0.0.3 版本

我们应该怎么衡量这个项目的价值?这17行代码显然不是不可替代的;收藏数量?截止项目被归档( archived)累计收藏数量才 1.2k 次。但就它能带来的破坏力而言却是其他更大体量项目望其项背的。

我同意指标的价值,但是如果不参考维护团队的规模,维护者能够投入的资源,用绝对的数值来评判是有失公允的。可这恰恰是这个网络时代需要的:鉴于我们早已经被海量的数据淹没,鉴于我们的注意力早已被碾压的七零八落,降低消化知识的门槛,以及把权力交接给算法和他者看上去是一个不错的选择。

泛社交化是一把双刃剑,一方面它降低了开源社区的准入门槛,给了更多好的开源项目崭露头角的机会;另一方面它也让更多的噪音有了可乘之机。在 GitHub 出现之前,mailing list 是社区主要的沟通方式,但如果你在决定加入某个 mailing list 之前有阅读过官方社区的提供的 FAQ 的话,那么你的念头很有可能会被打消: linux-kernal 的 FAQ 长度堪比一篇论文;Apache 的 tips 甚至会告诉你应该避免使用“你”这个单词,因为这会引起人的戒备心。更不要提社区中的 Code of Conduct 了。这些规则或者说是仪式感天然的会屏蔽掉部分人群。而到了 GitHub 时代当准入的成本几乎为零了之后,人们甚至要被反复告知不要在社区中添加无意义“我也是”的留言,这样对解决问题没有任何帮助。

从根本上与社交网络不同的是,维护一个受人瞩目的开源项目的成本比发一次 twitter 的成本高多了。一旦你的具有一定的影响力和知名度之后,对项目的精力的投入便会产生边际递减效应。 pouchdb 的维护者之一 Nolan Lawson 专门写过一篇名为 What it feels like to be an open-source maintainer 的文章来吐槽维护开源项目的体验:

Outside your door stands a line of a few hundred people. They are patiently waiting for you to answer their questions, complaints, pull requests, and feature requests.

对他而言 GitHub 的消息通知只会给他带来源源不断的负面情绪,光是每天阅读这些消息就已经让他心力交瘁了。

在Dominic Tarr 的在此之前的解释中,用他的亲身经历给出了一个似乎能为所有开源项目维护者辩解为什么要离开的理由——因为责任与收益不对等:

One time, I was working as a dishwasher in a resturant, and I made the mistake of being too competent, and I got promoted to cook. This was only a 50 cents an hour pay rise, but massively more responsibility. It didn’t really feel worth it. Writing a popular module like this is like that times a million, and the pay rise is zero.

我猜你现在才开始意识到 GitHub 的功能迭代是有方向性的,它在尽最大努力减轻项目维护者的负担,所以我们看到 GitHub 上有了issue 模板pull request 模板,机器人,持续集成工具等等。 那我们作为项目的消费者又能为项目维护者做些什么呢?或者在提每一个 issue 之前先前往 StackOverflow 或者是现有的 issue 看有没有相似的问题;或者在提交 issue 的时候可以精心准备好能够复现问题的 demo 来缩减维护者的时间;也许在提交每一个 pull request 之前现在本地运行单元测试看能否通过。但说实话无论你如何小心翼翼的用爱发电,不如考虑另一个更有效的方式——钱。

不知出于什么样的原因,faker.js 的维护者 Marak 决定“不再免费为世界500强公司工作了,要么给他一份年薪六位数的合同,要么 fork 这个项目然后自己维护去”。这个帖子的标题就叫作 No more free work from Marak - Pay Me or Fork This

令人欣慰的是,大家回帖一律对他的决定表示支持,并出谋划策为提供他筹款方面的建议。由此可见大众的思维也在逐渐发生转变,越来越多的人意识到虽然开源代码是免费的,但是贡献者的时间并不是,他们理应得到回报。在这个共识之下市面上出现越来越多的平台为开源项目提供第三方服务,比如 open collective xs code gitcoin 负责筹措资金, Maintainer.io tidelift 为项目提供咨询和诊断。

这其中最著名的要数 patreon,Vue 作者尤雨溪的赞助页面就托管在这个平台上面,他发起赞助的目的非常明确:帮助他全职全身心的投入开源项目 Vue 的开发中。赞助选项中最“昂贵”的选项名为 Platinum Sponsor, 赞助金额为 2000 美元且每个月只提供三个名额。这个级别的赞助机构或者个人的名字能够出现在 Vue 官网页面的每一个文档页面上。以我的观察这一栏的名额供不应求。

相当长的一段时间内我都对在开源项目网站上进行商业露出的行为感到厌恶,认为这不过是将流量兑现的把戏罢了,但时至今日我才意识到这可能只不过是开源项目在做默默的挣扎而已。

关于为什么以及如何给开源项目筹集资金在 opensource.guide Getting Paid for Open Source Work 一章有很详细的说明,我不再赘述。从这个主题自成一章的规格来看它的重要性不言而喻。金融手段虽然不是支持开源社区唯一的手段,但绝对是有力的手段之一。

“Transphobic maintainer should be removed from project “

以上内容只不过是整个开源社区现状的冰山一角。正如本文开头所说,这篇文章目的并非是给大家一个结论,而是呈现给大家更多平时被忽略的事实。如果说对于前两小节的内容我还能做到夹叙夹议的话,那么有些话题根本就是超出我讨论能力范围之外,比如说有关道德与社会公共议题。

2015 年年中开源项目 opal 的核心团队成员之一 Elia Schito 在 twitter 上发表言论认为跨性别者不过是“不愿面对现实(not accepting reality)”。这则言论被开源社区的一位意见领袖 Coraline Ada Ehmke (她也是开源项目“参与者公约(Contributor Covenant)”的发起人)发现并在 opal 社区中发起讨论,认为这种对跨性别者仇视者应该从核心团队中被移除(Transphobic maintainer should be removed from project)。而维护团队中的另一位成员 meh 坚决不这么认为,他认为技术是与道德无关的,如果你想把他替换掉,你应该比他贡献的更多才有资格说这话。至今 Elia 依然是 opal 核心团队的成员。

如果说上面这个例子离你太远的话,我们不如看一个更实际的:2017 年 3月饿了么前端团队在知乎上发表了一篇名为《写在 Element 一周年之际》的文章,其中除了对 Element 前端类库诞生一周年表示庆贺以外,还对他们眼中 iView 抄袭的行为表示了谴责。当然正如 iView 团队在评论区回应的,他们并不认可饿了么前端团队对于抄袭的指责。

我不敢对这些事件做任何的评价,这类议题已经超越了开源社区,它们更加宏大,同时也更加危险。互联网并非是讨论这些问题的最佳场所,我们也并非是讨论这些问题的最佳人选。

我在此谈论这些话题的目的并非是想让一种声音压倒一切,而是想让不同的声音都能传播的更远。 平克弗洛伊德乐队(Pink Floyd)的概念音乐专辑《月之暗面》(Dark Side of the Moon)绝对可以算作历史上最伟大的音乐专辑之一,它至今依然保持着 Billborad 累计停留958周的最高记录。 乐队的贝斯手兼主唱 Roger Waters 对于专辑标题中月之暗面的解释是:一方面它象征着我们都不曾亲眼见过的地方,但是却不能否认它的存在;另一方面它也代指我们每个人不为人知想对大众隐藏的负面,我们应该学会驾驭这些负面而不是让它们占据我们。

开源社区的暗面就在那里,我们无法不视而不见。

技术写作的困境

## 一在进行技术写作这么多年之后,有时候不禁会想,有什么颇具价值的经验是能够分享出来让大多数人受用的?当然这些经验可能很多,那么再进一步说,如果只允许我选取其中几则的话,我的回答会是什么?但是这些内容可能对大部分没有创作经历的人来说意义不大,因为这些答案尝试解决的痛点只能...… Continue reading

拥抱原则与面对现实

发布于 2021年09月22日

小心 Serverless

发布于 2021年08月24日