<audio id="audio" title="15 | 开源：从Phabricator的开源历程看开源利弊" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/51/ec/51eda8d146f754b71d079de417605bec.mp3"></audio>

你好，我是葛俊。今天，我来和你聊聊开源这个话题。

从克莉丝汀· 彼得森（Christine Peterson）1998年提出“开源”这个名词，到今天已经21年了。可以说，在这些年里开源改变了软件开发世界。如今，开源覆盖了IDE、移动端开发、前后端开发、运维、服务治理、AI等众多领域的项目。比如，[GitHub上2018年最流行的前十个项目](https://octoverse.github.com/projects#repositories)，包括VSCode、React Native、Angular、Ansible、Kubernetes、TensorFlow等，对这些领域都有覆盖。

<img src="https://static001.geekbang.org/resource/image/a7/ad/a75f98e91a355d48be5f95e3ac4373ad.jpg" alt="">

从使用者的角度看，开源软件的价值不言自明。可以说，99%的科技公司都在使用开源软件。

从贡献者的角度看，前十个项目中有8个项目的背后都有公司做支撑。毫无疑问，开源对公司来说也有吸引力的。但是，很多公司并没有开源，尤其是国内做开源的公司更是比较少，原因是什么呢？其实，就是因为开源有很多坑。

我在Facebook时参与了Phabricator开源的全过程，见证了其为公司带来的好处，比如因为模块化带来的代码质量提升、从开源社区获得的资源支持，也见证了开源的一些弊端，比如因为和开源社区目标不一致而带来的运维成本增加，以及最终导致的项目Fork。

## Phabricator的整个开源过程

一般来说，开源一个项目的流程包括以下九步：

1. 公司/员工对某项目有开源的意愿；
1. 权衡利弊决定是否开源，以及后续的维护计划；
1. 法律和信息安全方面的审核；
1. 选择License；
1. 选择Contributor License Agreement；
1. 选择版本控制代码服务商（比如，GitHub、GitLab、BitBucket等）；
1. 代码模块化，与公司代码分离；
1. 正式开源，发布信息；
1. 项目维护和持续开发。

接下来，我就以Phabricator的开源过程为例，帮助你理解公司进行开源的利弊，以及使用它来提高研发效能的一些原则和实践。

### Facebook决定对Phabricator进行开源

Phabricator源自Facebook内部对代码审查的需求，后逐渐发展为软件开发的一个Web工具套件，包括代码审查、代码仓托管、缺陷跟踪、项目管理、团队协作等应用程序。

开源之前，Phabricator主要由开发工具团队维护并增加新功能，其他开发人员也会向其贡献代码。它发展得非常快，为Facebook的开发和质量保障提供了很大帮助。但，Phabricator有个问题就是，经常会出现严重的性能问题。具体来说就是，Phabricator的速度会随着时间推移而逐步下降，每隔一年左右，就会达到让开发人员无法忍受的地步。

导致这个性能问题的主要原因有两个：

- 第一， Phabricator和Facebook.com在同一个代码仓，共享Facebook.com的底层代码库，但开发人员对Phabricator的响应速度要求比用户对Facebook.com要高。
- 第二，非开发工具团队的开发人员在增加功能的时候，因为不了解全貌，所以在贡献代码的同时，往往会降低Phabricator的速度。一个功能降低的速度看不出来，但累积起来，总体速度的下降就很明显了。

所以每隔一年左右，我们就需要对Phabricator做一次重构，来提高响应速度。

2010年年中的时候，这个性能问题再度爆发了，开发工具团队决定认真思考有没有更好的解决办法，从根本上解决这个问题。经过仔细分析，我们得出的解决方案就是和 Facebook.com解耦。

正好这个时候，开源社区对Phabricator的代码审核功能非常感兴趣。我们认为开源Phabricator或许是一个可行的办法，同时调研结果显示开源Phabricator有以下好处：

1. Phabricator是一个内部工具，不是面向用户的产品，开源非但不会影响公司的核心竞争力，还可以提高影响力。
1. 开源自然而然地就会把它从主代码仓剥离出来，实现与Facebook.com的解耦，实现提速。
1. 开源意味着代码从此要公开出去，更多的人可以看到。这就给Phabricator的开发人员带来压力，让他们更关注产品质量。这样一来，Phabricator的性能就会更有保障。
1. 可以利用开源社区的开发资源。

当然，开源Phabricator也有缺点：

1. 开源之后，Phabricator势必要支持更加通用的开发场景，这可能就会影响对Facebook特有场景的支持。
1. 开源之后，代码不会像在内部那样容易管控，灵活性会降低。

经过分析，我们认为可以使用插件的形式，从技术上解决对Facebook特有开发场景的支持问题。也就是说，在Facebook内部创建一个单独的代码仓作为插件，集成到开源的Phabricator之中。

而对Phabricator的代码管控问题，我们可以把它放到Facebook组织之下，从而保留比较强的管控力。

所以综合分析，内部工具团队以及上一级的基础平台团队，决定这一次的重构目标是开源Phabricator。

### 开源准备工作

在确认了开源Phabricator之后，我们还要完成一些非开发的准备工作。

第一，法律和信息安全方面的审核。

这一步主要是确认此项目的开源，会不会使公司面临法律和信息安全方面的风险，由公司的律师团队和安全专家操作。一般来说，法律风险重点关注是否会泄露自己公司以及第三方公司知识产权；信息安全方面关注是否会暴露公司的安全漏洞。

第二，选择授权协议。

授权协议包括开源软件授权协议（Open-source License）和开源贡献协议两种。

其中，开源软件授权协议，指的是使用者享有的权利和受到的限制，比如GPL、MIT、Apache等协议。Phabricator选择的是Apache 2.0。这里，有两个工具可以帮助你做出选择，分别是“[怎样选择开源协议？](https://choosealicense.com/)”和“[开源指南](https://opensource.guide/)”。

开源贡献协议，指的是对软件贡献者权力的限定，目的是赋予开发者对开源项目贡献代码的权力，并赋予项目管理者按照软件授权协议去发布软件。它包括 CLA（Contributor License Agreement）和 DCO（Developer Certificate of Origin）两种。Phabricator选择的是CLA。关于这个协议的选择，你可以参考“[CLA和DCO的区别](https://opensource.com/article/18/3/cla-vs-dco-whats-difference)”这篇文章。

因为具体选择哪个协议与法律有关，所以我只给出了参考链接，如果你的公司需要开源项目，推荐你去咨询律师。

第三，选择版本控制代码服务商。当时我们选择的是开源方面最流行的GitHub。

### 开源具体步骤

完成了准备工作之后，剩下的就是正式的开发工作了。这部分工作主要包括以下三步。

第一步，把Phabricator代码和Facebook代码解耦。

我们做了一次比较彻底的重构，把分散在各处的代码，集中到5个代码仓里，分别是底层的API库Libphutil、网站应用集Phabricator、客户端Arcanist、文档系统Diviner以及Facebook内部功能插件模块，完成了Phabricator的模块化。

第二步，进一步优化性能。

针对代码的性能，尤其是底层的API库，我们进行了很多优化。因为开源以后只需要支持通用的开发场景，所以我们不必考虑原来在Facebook代码仓的复杂调用，更容易去针对性地提高性能。

第三步，支持功能定制。

功能定制是开源的主要难点。除了解耦，我们还需要保证在解耦之后，仍然能够灵活地添加Facebook开发人员需要的定制需求。主要有以下三种方法：

- Phabricator提供对象的字段（Field）、类、库3个级别的扩展，我们主要采用库级别的扩展实现对Facebook的定制功能。
- Phabricator提供接口，供Facebook内部工具调用。
- Facebook内部工具代码提供接口，供Phabricator调用。

这样一来，我们就实现了Phabricator和Facebook其他内部工具的无缝集成。

除此之外，为了把Phabricator的部署从Facebook内部工具拆分出来，我们还需要完成以下工作：

- 数据库的迁移，即把Phabricator的相关数据从Facebook的数据库中迁移出来。
- Phabricator的部署。开源前Phabricator属于内部工具网站的一部分，所以不需要单独部署，但开源后我们需要给它重新设计和实现一套部署系统。

完成这些开发工作后，Phabricator不仅从Facebook中剥离了出来，还显著提高了代码质量，比如模块化更好、注释更清晰、性能更好等。这些正是开源为Facebook带来的重要好处。同时，因为参与开源项目可以回馈社区并提升个人影响力，所以公司内部的Phabricator开发人员也都热情高涨。

但开源也意味着，我们需要投入额外的精力去实现Phabricator与其他内部工具的无缝集成，才不会影响Facebook开发者的使用体验。这，也是开源要付出的代价。

### 开源初期发展

完成开发工作后，Facebook正式对外宣布了Phabricator的开源，同时正式切换到新部署的Phabricator集群。整个切换过程比较顺利，只是在一开始的时候，Phabricator和其他工具间的联动出现了一些Bug，修复之后就稳定下来了。

于是，Phabricator也就开始进入开源的代码仓和内部的插件代码仓同时开发的阶段。针对Facebook的内部需求，我们尽量把它通用化，放到开源的代码仓中实现；实在需要定制的，才会放到Facebook的插件代码仓中。

这时，我的一位同事从Facebook离职，去了开源社区全职为Phabricator工作。他还创立了一家公司，致力于Phabricator的商用。于是，我们在开源社区也有了更强大的资源支持。

从2011年年初开源到2013年年底我离开Phabricator项目，Facebook和开源社区对Phabricator的发展目标是一致的，所以一直在合力增加Facebook需要的功能，合作得非常好。总的来说，我们的确充分利用了开源社区开发者对Phabricator的贡献。同时，业界的很多著名公司开始使用Phabricator，包括Uber、Pinterest、Airbnb等，提升了Facebook的声望。

### Fork

2014年开始，开源社区支持的公司越来越多，而它们的使用场景和Facebook不太一样，也就是说Facebook要想继续使用Phabricator的最新版本，就必须花费较大成本进行版本更新及维护。

而因为Facebook在Phabricator的使用上累积了非常多的数据，所以每一次数据库的Shema变动，都会带来非常麻烦的数据迁移工作，常常需要DBA的帮助才能实现不中断服务的版本更新。

考虑到这些新增功能对Facebook用处不大，而维护的成本又很高，所以2014年下半年Facebook决定停止使用外部开源的Pabricator，重新在公司内部自己维护一套Fork的Phabricator代码。这样一来，开源版的Phabricator引入新功能的时候，Facebook只在需要的情况下，才会参考外部的实现在内部引入。

其实，公司和开源社区目标不一致的现象比较普遍。在我看来，这可以算是开源项目的第一大坑。Facebook对Phabricator采取的措施是内部Fork，让开源社区继续自由发展，既然不能从开源社区得到资源，就把代码挪回公司内部获取完全的管控和自由度。这是处理目标不一致问题的第一种方法，你也可以借鉴。

第二个办法是，对代码仓强管控，但结果往往是开源社区Fork一个新项目重起炉灶，和第一种方法的结果其实差不多。

除了Fork之外，还有第三种办法，就是采用不同的分支来支持不同的目标。这样的好处是，公司依然可以获得开源社区的资源支持，坏处是分支管理、版本管理繁琐，也缺乏Fork的灵活性。

以上，就是Facebook开源Phabricator到最终Fork的全过程。我在这其中讲述了Facebook处理具体开源问题的一些方法，你也可以借鉴到自己的项目中。

## 开源对公司的利弊

这里，为了帮助你加深理解，我把开源对一个公司的利弊做了总结整理，如下表所示。

<img src="https://static001.geekbang.org/resource/image/56/f4/56a63f7c3ba5022c50ceeb1e1e481ff4.jpg" alt="">

总的来说，我认为开源在以下两种情况下最为有利：

- 第1种情况是大公司。不难发现，上面列举的各种好处对大公司比较明显，提高公司声誉就是典型例子。所以，2018年GitHub前十名开源项目中，除了NPM和Ansible外，其他的8个项目都是由Microsoft、Facebook、Google三个大公司支撑。
- 第2种情况，需要通过开源获取影响力从而扩展业务的公司。比如，Docker公司在开源Docker项目之前，名气并没有多大，但是把Docker项目开源之后，一下子就变成了明星企业，在改变了Pass发展格局的同时，也改变了自己的命运。

另外，从适合开源的项目的角度来看，平台、基础设施、工具等（比如，Phabricator以及2018年GitHub前十名开源项目）适合开源，而业务层的项目因为通用性不强，不适合开源。

## 小结

开源正在改变软件开发的格局，选择开源自己的项目对公司来说也是有利有弊。所以，今天我以Phabricator的开源过程为例，和你分享了开源一个项目涉及哪些步骤，在这其中获得的好处以及需要付出的代价。

开源对公司的好处，主要表现在提高代码质量、得到开源社区的免费帮助、提高开发者的积极性、提高公司声誉、回报社区等。而缺点和挑战，主要包括定制困难、内外协调，以及版本维护等。如果你的公司或者团队在考虑是否开源，可以将这些利弊作为参考。

在我看来，Phabricator算是开源的一个成功案例。因为在整个过程中，我们充分利用了开源带来的好处，而且在开源过程中投入的开发资源，即使不开源也是需要的。

一定程度上讲，开源Phabricator的过程，也体现了Facebook的实用主义。在需要开源的时候，放手去开源；在发现维护的性价比不好时，就果断Fork。虽然从个人情感的角度说，我不愿意看到Phabricator在Facebook内部最后Fork了，但理智地看这的确是一个很好的决定。

## 思考题

跟硅谷相比，国内公司参与开源的非常少。你觉得主要原因是什么，将来的趋势又会是什么样的呢？

感谢你的收听，欢迎你在评论区给我留言分享你的观点，也欢迎你把这篇文章分享给更多的朋友一起阅读。我们下期再见！


