「10倍程序员」与「仁慈独裁者」

598 👍 / 38 💬

TL;DR:经历过 0.1x 的工作状态后,我理解了 10x 的来源,那就是要成为项目的独裁者。

「10倍程序员」(或者 「10倍工程师」,下文简称 10x)是一个非常诱人的概念。字面意义上,10x 指的是生产力爆棚、能够以一当十的软件开发者。对于开发者和创业者来说,自己成为 10x 意味着在相同时间内有 10 倍价值的产出;对于老板和管理者来说,招到一个 10x 能够代替 10 个普通码农,从而大幅降低用人成本。人类对先进生产力的追求永无止境。因此,自从这一概念被提出以来就引起了广泛的讨论和争议。

「怎样成为 10 倍程序员?」这个问题我和朋友讨论过无数次,但一直没有得出有效的结论。一方面,这个目标显得如此遥不可及,我们能感觉到个人能力存在明显的边界;但另一方面,我们又清楚地看到这个世界上真实存在着很多 10x 的天才,他们以一己之力完成了普通人 10 倍甚至百倍的贡献。比如 Linus Torvalds、Fabrice Bellard、Jeff Dean 等等。需要明确的是,这里的 10x,并不是以 10x 速度完成原本的事情(在这方面任何人都不是计算机的对手),而是有能力解决 10x 复杂度的问题、完成 10 个人也干不成的事情。

怎么量化一个问题的复杂度呢?我们可以类比「柯氏复杂性」的思想,用「解决这个问题所需的最少代码量级」来粗略地进行估计。比如:

上面列出的还仅仅是最小的原型系统,真实世界中对应的产品级系统一般会在此基础上再多一个量级的复杂度。

一个合格的软件工程师至少能够独立负责 10^3 级别的项目。我本人经过多年计算机课程和项目的训练,目前能够独立负责 10^4 级别的项目。但是我已经能明显感觉它达到了个人能力的上限。因为一个人大脑的处理能力和容量是有限的,就好比一个单核 CPU 加上有限的内存。当你思考的问题本身非常复杂、上下文巨大,就好比操作系统运行一个进程的工作集超过了物理内存容量,此时就会出现频繁的换入换出,大幅降低处理速度。

在意识到瓶颈的存在后,我们就开始思考:怎么才能继续扩展能力边界,从「一万行程序员」进化到「十万行程序员」呢?在计算机系统中,一般有两种路线:垂直扩展和水平扩展。垂直扩展是提高单个节点的处理能力,也就是进一步强化个人能力,成为 10 倍程序员;而水平扩展是增加新的节点,从单机系统变为分布式系统,也就意味着要通过团队合作解决问题,需要开始点项目管理技能。在我即将毕业的那个时间点(2022年),大语言模型尚未横空出世,我觉得垂直扩展的道路已经走到了尽头,必须去尝试水平扩展。因此我加入了一家创业公司,和一个二三十人的团队一起,共同开发一个几十万行的开源数据库内核项目—— RisingWave。它具有 10^5 复杂度。

第一次参与大型开源项目的体验是非常新奇的。你不再孤军奋战,而是和大家一起往一个仓库里添砖加瓦。你的代码会经过别人的 review,需要给别人讲明白你的动机和实现原理,然后会收到各种反馈,指出其中含糊不清或者未考虑周到的地方。同样的,你也需要 review 别人的代码,分享自己的观点。这是我第一次体验到象牙塔以外世界中真实的软件工程是什么样子的。一切看上去都很美好。正如 IETF 的宣言一样:这里没有国王,有的是大致共识和可以运行的代码。

这样的好日子大约持续了一年左右的时间。但是在宁静的表面之下,有些不祥的气味也在暗中发酵。在最初的新鲜感过去之后,我似乎对 review 别人代码逐渐失去了兴趣。因为我不了解代码背后模块的整体设计,因此常常给不出实质性的建议。我确实可以花很多时间去熟悉他们的代码,但投入的这些精力对我自己的任务却没什么帮助。同样的,我感到别人对我代码的 review 也不那么积极了。一个 PR 发出来以后经常很长时间没人看,进而阻碍后续的开发。这种代码审查上的懈怠,加上越来越多的需求和 bug fix,这些对现实的妥协,导致越来越多有缺陷的设计进入代码库。

按说,一旦意识到有不合理的代码出现,就应该及时进行重构。但是,在这样一个 10^5 量级高度耦合的项目中进行重构,常常牵一发而动全身,一周时间都不一定搞得定。一个上千行的 “大变更” 还会引发和更多 PR 的冲突,推动它进入主线困难重重,有不少最后都烂尾成了真正的 “大便羹”。这样的结果便是,很多时候即使我们意识到了问题,也无力去改变。久而久之,一坨坨shi山便形成了。

这个 emoji 发不出来,故以 shi 代替

「shi山」这个词说起来有些抽象,因为它来自人类审美的主观判断。我们试图给它一个客观的定义:shi山代表着这样一堆代码,它们自身的复杂度远超它们要解决问题的复杂度。缺少注释、结构混乱、无法理解、难以维护都是它们的外在表现。

shi山对于程序员生产力的影响是毁灭性的。假设人在单位时间能处理问题的复杂度是恒定的,那么当代码本身的复杂度更高时,人的处理速度就更慢。而且,在不合理的结构上添砖加瓦会引入更多不合理的成分,使得复杂度超线性增长。这就好比在危楼上盖楼会越盖越危,在shi山上堆shi也会越堆越shi。以上还都是物理攻击,更致命的是它的魔法伤害。它把「用代码改变世界」的创造性工作变成了「糊shi」般的机械劳动,说得好听一点叫「shi上雕花」。这会极大消耗人的心力,降低工作积极性。两种攻击叠加起来……比如我最近就做了一些shi上雕花的工作,发现生产效率直接降低到 1/10 都不止。此刻,我再次回想起「10倍程序员」的传说,意识到原来 10x 并不是空穴来风,而是真实存在于我们每个人身上。

我不禁反思:难道我之前所度过的每个平凡的日常,都是连续发生的奇迹吗?!为什么我之前写个人项目的时候感觉做什么都很快,现在参与到大型项目中却举步维艰呢?为什么我之前觉得学什么都很快,现在反而感觉什么也学不到呢?这一定不是我能力的问题,一定是做事方法的问题。我之前一定做对了什么,而现在却把那个东西舍弃掉了。后来我意识到,之前做对的事情叫做「独裁」。你需要成为项目的「独裁者」。

在软件工程中,独裁意味着一个人独立负责整个项目的设计、实现与维护。当项目变大需要多人参与时,独裁者仍需要控制项目的关键部分,并对设计决策和实现方式拥有最终决定权。

独裁通常意味着绝对的权力。独裁者能够说一不二地推行自己的意志,但其权力基础来自对治理对象深入骨髓的理解,以及对此承担的无限责任。独裁在现代人类政治中是一个避之不及的存在。但在很多微观领域,独裁却是一种普遍存在的治理模式。比如很多开源项目都有「终身仁慈独裁者」(BDFL)的角色,其中最知名的当属 Linux 与 Linus。Linus 有权最终决定一个 patch 能否合并到自己的分支上。尽管任何组织都可以 fork Linux 另起炉灶,但大家还是公认独裁者 Linus 维护的分支才代表正统的 Linux。

为什么独裁是高效的?我认为是源自上帝视角、执行力与 ownership 的三位一体。首先独裁者一定是最懂这个项目的人。他对代码的整体结构和实现细节了如指掌,因此对于任何问题都能给出接近全局最优且清晰明确的解法。比如要加新功能,他知道该往哪儿加、怎么加、要加多久;出现了bug,他知道大概是哪儿的bug、该怎么查;当代码结构不合理时,他知道该怎么重构、重构以后会带来多大收益。正因为他对于解决问题的路线、代价和结果都非常清楚,因此他可以有很强的执行力。不需要花时间去调研,也不需要依赖他人的帮助。做完以后还会进一步加强他对整体的理解。这样的正反馈循环自然就使独裁者产生对这个项目的责任意识,也就是我们常说的 ownership:如果一个东西只有我懂,只有我做得动,那出了问题自然由我来负责。这是我的项目,它的成功就代表我的成功,因此我想让它变得更好。

这里需要说明一点,独裁并不代表没有shi山,不独裁也不意味着到处都是shi山。但据我观察,独裁者维护的项目较少出现shi山。因为即使写出了shi,独裁者看着不爽就会想办法清理掉它们;而没有独裁者的项目更容易堆出shi山。因为每个人对事物的理解存在差异,体现在代码上就会存在不一致,日积月累就形成了shi山。而由于没有 owner,也很难有人有动力去清理它们。所以整体而言,独裁项目更容易保持代码质量。

那么,怎样才能成为一个独裁者呢?自然是要想办法进入独裁的正反馈循环。最好的起点就是这个项目的创始人。刚开始的时候白纸一张,一切都是由你创造的,这样你天然具备上帝视角、执行力和 ownership。这也是为什么大部分公司的 CEO 都是创始人,大部分开源项目的 BDFL 也都是最早的开发者。遗憾的是,如果你一开始就没坐在独裁者的位置上,那么想进入这个循环是非常难的。如果你每天的工作就是糊shi,那么只会离上帝视角越来越远、执行力越来越差、到最后只想早点下班。你的生产力就会逐渐从 1x 降到 0.1x 甚至衰减到 0。 所以,很多时候我们做不出东西,可能不是因为能力不足,而是因为没有进入正确的状态。

当然,也不是说参与任何大型项目都无法成为独裁者。通常大型项目都是由多个小模块组成的,而每个小模块都是开展独裁的很好切入点。我在 RisingWave 中就尝试过模块独裁,总结出两种路线。一种是从头实现某一相对独立的功能,然后将其作为独立的仓库维护,与shi山主体物理隔离;另一种是清理已经堆成的shi山。这可能需要用几周甚至几个月的时间对已有代码进行重构。一旦重构完成,你也就自然具备了成为他们独裁者的资格。因为重构可以帮你彻底理清代码逻辑,开启上帝视角。不过相对来说,我还是觉得前一种更容易一些。重要的是,你需要在自己独裁的小世界和外面的大shi山之间划出一个明确的边界。这样你便可以专心进行内部治理而不受外界影响。

以上我们讨论了独裁的好处以及怎么成为独裁者。但是,凡事都有两面。独裁的问题在于它过于依赖个人输出,让项目成败与个人意志紧密绑定在一起。当项目做大以后,独裁者会在很多事务的关键路径上,承担越来越多的工作和压力,形成单点瓶颈;一旦不小心负载过大把独裁者打爆,或者独裁者出于个人原因宕机甚至跑路,形成单点故障,那么整个项目可能就此倒闭。说到底,独裁还是在做垂直扩展,并没有解决水平扩展的问题。

假设我们每个人都进化成了独裁者,这些独裁者之间又该如何合作呢?这可不是件容易的事情,因为独裁天然就带有互斥属性。说到这里我又想起了「三个独裁者」的故事。话说,研一那年,我和两个同学组队合作「高级操作系统课」的大作业,目标是实现一个专用操作系统。重点是,我们仨每个人都有独立实现 OS 的能力和经验,而且还有不同的技术偏好。结果,我们每个人按自己的想法实现了三个不同的系统。因为大家都不想参与别人主导的项目。三个独裁者放在一起,诞生了三个项目。这是一个引人深思的现象。

回到原来的问题,一群独裁者如何合作完成一个项目?我自己目前还没有过成功经验。这里只能开一下脑洞。一种可能的方式是组成独裁者联邦,每个人负责一块独立的事情,彼此之间有明确的边界,互不干涉内政。当涉及跨边界的合作时,需要定义好明确的接口,必要时可能还需要签协议。另一种可能方式是共同接受一位大独裁者的领导,由大独裁者来统筹工作。总之,一个分布式系统最高效的运作方式就是「尴尬并行」,每个节点各司其职,节点之间的通信和同步开销应当越少越好。

总结一下,这篇文章的诞生是出于对「10倍程序员」的思考。在个人能力达到瓶颈的情况下,我开始寻求通过团队合作进一步扩展生产力。但是,共同编写代码会不可避免地形成shi山,导致每个人的生产力下降。通过对这一现象的反思,本文提出了「独裁者理论」:开发者应该对自己的代码有深入理解和绝对掌控。要成为项目的独裁者,才能保持高效产出。合作开发时应该划出清晰的边界,避免互相干涉内部实现。简而言之,为了避免成为「0.1 倍程序员」,首先要当「仁慈独裁者」。

当然,这是一个相当政治不正确的论断。在得出这个结论时我也很悲观,因为它再次否定了团队协作的路线。另一方面,它依然没有突破个人能力的瓶颈,没有回答如何成为 10x 程序员的问题。不过,随着大模型时代的到来,Copilot 等编程辅助工具的普及,让我们看到了继续 10x 的曙光。尽管目前 AI 的能力还远远达不到在实际工作中提高 10x 生产力的水平。但我期待着一个仁慈的 10x AI 独裁者早日降临。

所以到底怎样成为 10 倍程序员呢?欢迎一起探讨。


专栏: