Linux从诞生到现在已经快30年了。在此期间,Linux一直延续着提交修改、审查、讨论、最后通过邮件批准的研发过程。这个过程非常费时费力。它不仅成为新手的进入壁垒,也成为可持续生产的障碍。那么为什么Linux坚持要遵循这个过程,它有什么好处呢?缺点是什么?有什么解决办法吗?早期,Linus自己手动管理贡献的代码,没有任何版本控制系统。而现在,使用了git。然而,有一点在整个过程中从未改变:代码被发送到一个(或多个)邮件列表,然后在做出最终裁决之前进行一系列的审查和讨论。尽管Linux取得了成功,但该过程受到了很多批评。微软的SarahNovotny最近在社交媒体上发文称,如果社区要吸引新鲜血液,Linux使用的协作工具已经过时,最好更换。我想我对此有一些发言权:近十年来,我一直在为Linux和其他具有类似工作流程的项目编写代码。在RedHat期间,我为核心x86基础架构、KVM管理程序和QEMU、Xen管理程序和其他系统做出了贡献。虽然,因为我主要关注SeastarC++框架和ScyllaDB数据库,我在大约7年的时间里没有太多接触Linux,但它们采用与Linux非常相似的开放方法。现在我是Datadog的一名工程师,这家公司遵循与其他网络公司几乎完全不同的流程。那么我站在哪里呢?首先,我的立场很明确:我不喜欢Linux开发过程。我坚信这个过程不仅是进入的障碍,可持续生产的障碍(虽然不是因为电子邮件),也是挫败感的来源。如果我可以决定如何做,我不打算在任何项目中遵循这个过程。但与此同时,许多Linux进程的批评者似乎认为,它的捍卫者如此顽固地停留在过去只是因为Linux充满了不愿做出改变的坚持者。虽然我相信这样的人确实存在,但真正的原因并不存在。Linux遵循的开发过程提供了一些独特且重要的优势,这些优势也将有益于任何其他组织。除了电子邮件之外,任何自以为是的工具都会迫使Linux放弃这些好处,而人们愿意放弃的正是这些好处,而不是电子邮件。工具应降低进入门槛并纠正过程中令人沮丧的方面,同时使组织能够实现真正推动软件开发的Linux优势。这样的优点还有很多,但是由于时间关系,我会重点说一下我认为最重要的。我将尽我所能向您解释它是什么,为什么尽管它有好处却如此令人沮丧,以及为什么它只对其他组织有益但对Linux至关重要。1.提交消息和补丁Linux有一条规则,要求将代码更改拆分为单独的补丁。每个补丁都必须做一件事,而且只能做一件事,每个补丁都应该有自己的描述性提交信息。提交消息比代码更改本身长得多的情况并不少见。通过这个例子,可以看出大多数组织往往会忽略什么。在GitHub上,我看到大多数现代项目都带有提交消息,例如“8月25日,检查点”,或者稍微好一点(但只是稍微好一点)的“实现X函数”。如果其他人以后需要查看代码,他们将无法理解为什么要按照当时的方式进行更改。有些缺陷非常微妙,很容易重复出现。只看简短的、非描述性的提交消息,不一定能判断错误是在什么条件下发生的。举个简单的例子,看看我的好朋友JohannesWeiner的Linux提交,不难想象其他一些项目可能只是潦草地写下“删除警告”之类的东西。再次查看此消息,阅读它我可以明白为什么删除这些警告是安全的(它解释了为什么在当前情况下它是安全的),以及如果将来更改此代码我该怎么办。我相信很多组织也会这样做。但由于Linux进程是强制执行的,我100%确定阅读提交消息将了解有关更改的所有相关信息。如果我们谈论一个错误,我知道它在哪些系统上,在什么条件下,为什么它没有影响其他系统,以及我应该怎么做才能避免再次犯同样的错误。这对任何组织来说都是值得的:它让其他人(包括未来的你)更容易理解为什么要进行更改,为什么代码会按照它的方式运行,它可以让新人更快地成长,它可以防止重复相同的错误发生,降低了因偷偷不相关的代码而造成损害的风险。对于Linux,这很重要,原因有二:许多人来自不同的背景,来自不同的公司,有着不同的动机和议程。公司内较大的项目可能会使用其他机制来传达信息并确保问责制。很少有开源项目像Linux这样规模大、寿命长、受到这么多人的影响。Backport:鉴于其规模和重要性,fork一直是Linux中的常态。即使是现在(2020年),一些发行版也可能会在他们认为的LTS中添加自己的补丁。即使现在这种情况比2000年代初少了,但这只是因为Linux本身已经开始拥有自己的LTS系列,发行版可以基于这些系列。许多现代在线公司不需要维护产品线兼容性,通常不存在反向移植问题。他们只关心交货。但是当涉及到Backport时,事情就变得更加复杂了。开发人员(很可能不是作者)可能必须选择如何针对略有不同的旧代码库微调代码。为了最大限度地降低风险,您可以仅向后移植重大变更的某些部分,这是每个人通常所做的。比方说,2,000行代码更改中的5行修复了一个错误。同样,此错误的修复可能在API重构之后进行。你愿意基于一个大的变化向后移植,还是你想要基于一个有据可查的、完整描述的、合理分割的补丁来向后移植?作为做过无数次反向移植的人,我很清楚我的选择是什么。不管是否向后移植,它都有好处,但也会带来分层成本。现在程序员不仅要关心代码,还要关心如何重组和调整这段代码。其中一些重组很容易:您可以使用gitadd-p选择将哪些部分添加到每个更改中。当您开始发现代码片段之间的循环依赖时,它会变得有点复杂。假设有一个返回对象类型的函数,后面介绍了。然后你必须添加一些代码来处理这种情况,这些代码不会最终出现在这个项目中,它们只是临时粘合剂。所有这一切都令人沮丧,但并非不可避免。假设,你把所有的工作都完美分解了,好办了。当人们进行代码审查时,真正的问题开始出现。代码审查对于任何组织来说都大同小异。人们阅读代码并建议(或请求)更改。假设地,评论是我在第一个更改中添加的方法应该有一个额外的参数。还假设我在所有未来的补丁中都使用这种方法。现在我必须回到第一个补丁添加参数,因此所有后续补丁都不起作用。现在我不仅要动脑筋想出原因,还要手动修正所有的错误。如果我之前测试过某个补丁,那么该测试现在无效,我必须重新测试。重组只是一个小问题。但是重新设定现有工作的基线是一件大事。希望Linux社区和朋友们明白:显然,这不是不可能的。但如果这不是进入障碍,我不知道什么才是。人们不得不花费时间、精力、脑力和计算机来重组、重写、返工,这些都是没人愿意做的事情。我还发现,有时人们会争辩说:“……但这对优秀的程序员来说很好”或“但它会迫使你以这种或另一种方式思考,而优秀的程序员应该那样思考”,这样的断章取意的观点是没有用的:天哪,我刚刚承认了这种方法的所有好处,并发现重新组织这段代码绝对是折磨人的灵魂。以打扫卫生为例:总能宣扬保持房屋清洁的好处(我完全同意),并且完全有能力吸尘(我也完全同意),但通常我不会.原因很简单,我还有其他我认为更重要的事情要做。这就是为什么我对我的Roomba很满意,它让我无需自己动手就能获得保持房间清洁的所有好处。这让我想到了以下几点……但我也希望Linux社区以外的人能够理解Linux所遵循的过程具有真正的优势。没有一种工具可以完全胜任这项任务。以GitHub为例,它的工作流程非常好。原则上,总是在现有代码的基础上添加新代码。但它可以强制推送分支,使对提交的评论变得毫无意义,并使讨论变得毫无意义。现代开发工具使很多事情变得更容易:您可以触发操作、集成CI/CD管道、向负责更改的人员发送通知等等。但客观上,它们让我们更难分工。纯文本电子邮件使很多事情变得困难,但它并不妨碍实现预期结果的过程。即使有可能客观准确地说明Linux将获得多少收益以及放弃该过程将失去什么,仅此一点就已经是完美的并且证明继续运行一直运行良好的过程是合理的。2.有解决办法吗?我坚信,如果我们拥有能让组织在Linux流程中实现同样优势的工具,那对每个人来说都是一个巨大的胜利。有了这样的工具,即使是Linux也可能不再使用纯文本电子邮件。我不知道这样的工具会是什么样子。但也许我可以冒险想象一下:Git是一个源代码控制系统,本质上源代码控制系统想要添加到历史中,而不是重写历史。然而,GitHub中的开发过程将两者混为一谈,开发和审查发生在git提交中,而纯文本Linux开发人员在他们自己的本地git树中开发,不断改写历史。也许我们需要将它一分为二,允许在不同的工具中进行开发和审查,这样周期自然更短,代码更容易处理。Git用于存储结果。一个很好的类比是CSS允许HTML开发人员将表示层与逻辑层分开。还记得CSS之前的HTML吗?不,我是不是在暴露我的年龄……扩展上面的内容,也许逐行描述补丁差异会使一切都变得困难。我们能否拥有一个系统,在其中我们可以在高层次上描述我对代码所做的更改,并明确说明这些更改适用于哪些其他地方?例如,我可以说“将create_bar()函数移到create_foo()之前”或“将一个名为y的整数参数添加到create_bar()参数列表的末尾”。即使随后的更改向代码环境添加了一些破坏逐行差异的内容,系统仍将能够将更改应用于修改后但略有不同的代码库版本。也许我太天真了,这是不可能的,但GPT-3已经取得了一些令人大开眼界的进展,我认为它可能不会那么遥远。或者,如果它不是那么雄心勃勃,也许有一个中间解决方案,即始终对附加代码进行代码审查。如果所有部分都得到承认,那么此时此地,也只有现在,历史才会被改写。更简单、更易于使用的工具可以帮助维护人员确保与批准的代码没有差异,以验证是否围绕重组进行了更改。
