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

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

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

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

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

Phabricator的整个开源过程

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

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

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

Facebook决定对Phabricator进行开源

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

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

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

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

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

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

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

当然,开源Phabricator也有缺点:

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

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

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

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

开源准备工作

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

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

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

第二,选择授权协议。

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

其中,开源软件授权协议,指的是使用者享有的权利和受到的限制,比如GPL、MIT、Apache等协议。Phabricator选择的是Apache 2.0。这里,有两个工具可以帮助你做出选择,分别是“怎样选择开源协议?”和“开源指南”。

开源贡献协议,指的是对软件贡献者权力的限定,目的是赋予开发者对开源项目贡献代码的权力,并赋予项目管理者按照软件授权协议去发布软件。它包括 CLA(Contributor License Agreement)和 DCO(Developer Certificate of Origin)两种。Phabricator选择的是CLA。关于这个协议的选择,你可以参考“CLA和DCO的区别”这篇文章。

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

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

开源具体步骤

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

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

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

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

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

第三步,支持功能定制。

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

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

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

完成这些开发工作后,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处理具体开源问题的一些方法,你也可以借鉴到自己的项目中。

开源对公司的利弊

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

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

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

小结

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

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

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

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

思考题

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

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

评论