CategoryResourceRepost/极客时间专栏/geek/研发效率破局之道/工程方法/15 | 开源:从Phabricator的开源历程看开源利弊.md
louzefeng bf99793fd0 del
2024-07-09 18:38:56 +00:00

15 KiB
Raw Blame History

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

从克莉丝汀· 彼得森Christine Peterson1998年提出“开源”这个名词到今天已经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和Facebook.com在同一个代码仓共享Facebook.com的底层代码库但开发人员对Phabricator的响应速度要求比用户对Facebook.com要高。
  • 第二非开发工具团队的开发人员在增加功能的时候因为不了解全貌所以在贡献代码的同时往往会降低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。这里,有两个工具可以帮助你做出选择,分别是“怎样选择开源协议?”和“开源指南”。

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

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

第三选择版本控制代码服务商。当时我们选择的是开源方面最流行的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处理具体开源问题的一些方法你也可以借鉴到自己的项目中。

开源对公司的利弊

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

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

  • 第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了但理智地看这的确是一个很好的决定。

思考题

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

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