维护一个大型开源项目是怎样的体验?

(我认为)大型开源项目包含以下任意一个或多个特征: GitHub star 数量 1000 +每周都可以接收到多个 issues 或 PR有一些公司或其他项目在生产环境中使用任意一个或多个包管理系统中下载量巨大在项目所在领域中拥有较大关注度 可以从以下几个方面进行回答。 先介绍你的项目,用来干什么的? 在开发和维护的过程中遇到过哪些值得一提的事?有没有什么奇葩的 issue 或者 PR?对你的生活或者工作有没有造成影响(好的,坏的)?
关注者
6791
被浏览
327023

30 个回答

加入 Visual Studio Code - Code Editing. Redefined 快一年,趁这个机会聊一聊开发和维护这个项目的感受,如果大家不反对这是一个 大型 开源项目的话。以下为个人理解,不代表公司也不代表团队。

项目

Visual Studio Code 的目标是做一个 Lightweight Editor,通过的扩展 api,让用户在 VS Code 中达到和 IDE 中接近的开发体验(效率)。

不过很多群众对 VS Code 有诸多误解,我先来一一解答

  1. “VS Code 师出 VS,是 VS 找了一群人来重写的,复用了很多 VS 的代码,等等“。很抱歉,并不是这样半毛钱关系也没有。VS Code 的核心代码,也就是 Microsoft/monaco-editor 是 Erich Gamma 2011 年加入微软后,招聘的一支“全新”的队伍进行开发的。Monaco editor 从一开始就是一个 browser based editor,早期一直服务于各个微软系统中(比如 Visual Studio Online,OneDrive online)。招聘的这支队伍对于 Erich 来说并不是新的,因为大部分成员都是原先 IBM 的老部下,其中几位大爷跟着 Erich 撸了二十多年代码了。
  2. "VS Code 是 Atom 的复刻,是对 Atom 的魔改,是 Atom 的一个主题!"。很抱歉,并不是这样,但还是有几毛钱关系的。Monaco Editor 在经历几年的高光期,进入了一个小小的黑暗时代。这时候团队成员开始调研将 Monaco Editor 做成桌面应用,和 Atom 一样,我们首先关注到的就是 node-webkit。必须说 node-webkit 是业界的一缕清风,给这个产业带来了太多的可能性。当然最后我们选用了 atom-shell,也就是后来的 Electron。但就是这个 atom-shell,给大家带来了以上的误导。

最后,我们一定要寻根问祖的话,VS Code 应该是师出 Eclipse(同志们,哎你们怎么扭头走人了,别怕,我话没说完呢)。团队核心的几位大爷,早年就跟着 Erich,在写了几个 Editor/IDE 之后,创造了 Eclipse。正是因为见证了 Eclipse 的兴衰,所以这一次在设计 Monaco/VS Code 的时候,才会如此的克制。Extensibility 不好吗?当然好,但是 Eclipse 的弊端已经在一些竞争对手身上出现啦。

开发/维护

我 13 年加入微软后,就开始接触到 Monaco 了。在使用的过程中踩了一些坑,研究过代码,做过好一些扩展。所以在 VS Code 正式开源后以及上线 Marketplace 后,我就开始动手写一点插件和发 Pull Request。去年五月得空和团队结对编程了两个礼拜后,就加入了 VS Code。

VS Code 的开发几乎完全是公开的。早期我们还通过 User Voice 收集反馈,但我们早就把它关掉了,所有问题的处理都放在 GitHub 上。我们的 Yearly/Monthly plan 都以 issue 的形式呈现 Microsoft/vscode ,而我个人正常的开发节奏是这样的:

计划

在上一个 milestone 快结束、新的 milestone 开始的第一周,和老板沟通新的 milestone 自己想做的功能。以及自己要不要休假。

Debt Week

我们把新 Milestone 的一周当作 debt week,集中处理一些技术债,以及为一些插件做点微小的贡献。我一般会花一点时间在 Vim 插件以及我自己的 Ruby 插件上。

开发

这之后就是两到三周正常的开发。每天起床得先把自己头上的新 issue 都 triage 一遍,遇到紧急的得先修,不然就继续完成自己的 feature。

Inbox Tracking

我加入团队的时候,我们只有 1700 个左右的 issue,现在已经破 4000 了(大部分都是 feature request)。GitHub Inbox 在这种情况下是无用的,我们的做法是每周会有一名同事,负责 GitHub 的新 issue,assign 给合适的 owner。我已经当过三次 Inbox Tracker,只能用可怕来形容。每天一睁眼就是一百多个 issue 要处理,一点都不想起床。

Endgame

我们在 milestone 的最后一周 endgame 会对新 feature 进行各种花样的测试,对这个 milestone 关掉的所有 issue 进行验证。全部完成后,每个成员书写自己负责部分的 release note。最后 Endgame master 会到后台网站发布新的 Stable 版本。

印象深刻的事

当之无愧就是 VS Code uses 13% CPU when idle due to blinking cursor rendering . VS Code 是基于 Electron 的,而 Electron 则基于 Chromium。这样的话,Chromium 的锅有时候得我们来背。

VS Code 里的编辑区域并不是 textarea ,全都是 mock 的,这也是主流做法,Ace、CodeMirror、Atom 无不例外。理由也很简单,要实现Tokenize、高亮、Partial Render、Line Wrap,自己控制渲染肯定是最方便的。为了尽可能模拟 textarea,我们模拟了光标。最开始这个光标的跳动,是通过 JavaScript 来控制光标的 opacity。后来社区给我们贡献了一个 pull request,使用 CSS animation 来调整 opacity。实现上来说肯定是比 JavaScript 版本更优雅,同时也提供了四五种不同的光标跳动的选项。

但谁知道,Chromium 对于 CSS Animation 是有巨大的坑的。比如你写的 animation 是每秒改变一次 opacity,但是 Chromium 会根据刷新率(比如 60hz)来检测页面上的 animation。虽然我不知道 Chromium 做了什么,但是你可以看到每16ms,Chromium 就会吃掉一点你的 CPU 和 Battery



真的是一点办法没有。我们起初没有发现这个问题,直到 broccoli 的作者 Jo Liss 给我们发了 issue,并且在 Twitter 上爆我们,瞬间就成了 Twitter 上大新闻。连 Miguel de Icaza 都点赞了,真的是。。。

当时我刚吃完晚饭,但是由于这个事情在我的防区,我只好开电脑 troubleshoot。最后发现是 Chromium 的 bug,开了两年多了,我只好告诉 Jo Liss,这锅我们不背,但是我们会修的。

结果之后好事者把事情捅到了 HackerNews,瞬间成了当天大新闻,还上了 TheRegister 小报。所有人都开始讨论使用 Browser 技术做桌面应用是不是正确的选择,撕的不亦乐乎。

你们撕的倒是开心了,我那几天给各种老板解释什么是跳动的光标,忙的跟狗一样。好在后来 Chromium 的 PM lead Paul Irish 留言表示这是他们的 bug,算是完美收官了。

有没有什么奇葩的 issue 或者 PR?

  1. 你们猜大家看到中文写的 issue 会找谁来翻译?
  2. 有些朋友提交了 PR,根本不管你给的建议,自顾自的更新修改。这样的 PR 根本不可能 merge,但是我们给的尽可能 polite 的建议,有些朋友真的把它们只当成建议。。。
  3. 再一次说到跳动的光标,这个始作俑者是社区的朋友,看起来也是非常 neat 的实现,谁知道就踩了 Chromium 的坑呢。。。

关于中文 issue 的问题,VS Code contribution guide 写的是比较清楚的,请大家用英文提问。但是鉴于中文用户量巨大,加之人总有英文不够用的时候,VS Code 也会经常看到中文问题。我有这样一些想法

  1. 写中文我个人觉得问题不大,毕竟 GitHub 是我们几乎唯一的反馈渠道,不能要求用户必须会英文。
  2. 写中文的确增加了我本人的工作量,所以能写英文,还是尽量写。
  3. 但如果你觉得需要严重的 Google Translate 的帮助,我建议还是写中文,并且 cc 我。不然可能翻译出来最后谁也看不明白,或者误解。
  4. 我老板问我,为啥中文 issue 几乎把所有东西都写在标题里,然后 issue 描述留空。我真的不知道该如何回答。如果用中文写 issue,并 cc 我,请保证把reproduce steps 写好,一步一步用中文写清楚,这总没难度吧?
  5. 如果第四步做不到,还要我解决问题,请考虑请我喝啤酒吧。

生活

大家都喜欢开源,但开源贡献者大部分时候是在做义务贡献。这么来看在微软搞 VS Code 就是一件愉快的事情,毕竟有人给你付工资让你做 open source。而且再也不用上班搞一套代码,回家之后私下自己在 GitHub 上面逛游,搞别的项目,上班和下班后可以在同一块土地上耕耘。

当然这样缺点也很明显,就是生活和工作往往难以分开。工作是一周五天,一天八小时,但是 GiHub issue 从来都是 7*24。遇到棘手的问题的时候,很难放任不管,哪怕已经回了家。不过也正是因为项目的特殊性,我们组还是有比较好的 remote 和自由工作时间的文化的。

---

补充

1. 添加了对中文 issue 的看法。

这次籍着Electron 1.0发布的机会,说说我自己维护两个大型开源项目的经历吧,分别是node-webkit(也就是现在的NW.js)和Electron

前者是几年前自己单打独斗,在公司0资源投入的情况下从两百多star一直做到好几千star,具体数字已经忘掉了,只记得当时在C++项目排行里做到了前十,直到自己另起炉灶。而后者,则是披着GitHub的光环,有着公司热心的投入,毫无障碍一路跑到了现在的三万多star。

(使用Star History生成的star数统计图)

一切从node-webkit开始

如果大家有接触过前端或者桌面端的开发,那么很可能有听说过NW.js的大名,node-webkit就是其改名之前的称呼。

但绝大部分人可能并不知道,node-webkit在最初发布的时候(2011年),并不是面向开发桌面应用程序,而是一个Node.js模块,可以创建一个WebKit窗口。神奇的一点是,你可以在这个窗口的页面里调用Node.js的模块。

Node.js代码:
var nwebkit = require('nwebkit')
nwebkit.init({'url' : 'index.html'}, function () {
  nwebkit.context.runScript('')
})

index.html代码:
<html><body>
<p id="output"></p>
<script>
require('fs').readdir('.', function (err, files) {
  var result = ''
  files.forEach(function (filename) { result += filename + '<br/>' } )
  document.getElementById('output').innerHTML = result
});
</script>
</body></html>

大家可以在NW.js的webkitgtk分支里找到node-webkit的原始实现,甚至尝试重新build一遍。不过这个模块一直未能稳定下来,玩具的味道更多一些。

再后来,原作者rogerwang对其进行了改进,从使用WebKit改成了调用Chromium Embedded Framework(简称CEF),一个可以把Chromium嵌入应用程序的库。这个代码一直没有正式公布,但大家可以在node-webkit的cef分支里找到。代码的另一部分是针对Chromium的几十行补丁,将Chromium的message loop替换为libuv,但是NW.js在开发过程中对代码库进行了很多次rebase操作,原始代码已经找不回来了。

找个实习生来开发

node-webkit的原作者rogerwang在Intel开源技术中心工作,虽然Intel在大家心目中可能更多是个卖CPU的,其实在开源方面也非常热心,甚至提供开源方面的实习工作。

在2012年的夏天,一则Intel的实习信息吸引了我的注意,上面说Intel需要一名熟悉Node.js的学生来进行node-webkit的开发。我投了简历,也很幸运地开始了node-webkit的开发。

Content Shell

我最初的工作是对node-webkit的cef分支进行改进,但是很快就发现很难继续进行开发了。CEF提供了自己的一套API来包装Chromium的内部API,而Node.js则是直接调用V8的API,如果想要把CEF和Node.js合并到同一个项目,困难重重。

于是我干脆将node-webkit推倒重写。新的代码基于Content Shell,一个Chromium代码库内的最小化浏览器实现。

重写后的结果非常不错,我得到了一个可以调用Node.js模块的浏览器实现。基于这套代码我发布了node-webkit v0.2.1

把node-webkit进化成桌面开发利器

至此node-webkit已经变成了一个独立的浏览器,而不再是Node.js模块。为什么不把它变成一个使用JavaScript和HTML开发桌面应用的工具呢?后面几个月我开始对这个想法进行尝试。

首先我模仿游戏框架LÖVE framework为node-webkit实现了一个打包系统,可以把应用直接附加到exe上:

(node-webkit的打包系统,来自我自己的PPT

这个打包系统一直沿用到NW.js,但是因为性能方面的种种原因,后来在开发Electron时我并没有使用这套系统。

接着这是各种细节上的完善:比如利用package.json文件来描述应用;给窗口加工具栏;拓展DOM来提供API;取消浏览器的安全系统;等等。当然还有无休无止的bug修复。

其中最有挑战性的一点是支持Node.js的native module,我对Chromium打上各种补丁来暴露V8和OpenSSL的API,给Node.js打补丁好解决OpenSSL和NSS之间的符号冲突,提供自定义的node.lib来支持Windows,最后还要提供适用于node-webkit的编译工具。

完成这些工作以后我发布了node-webkit v0.2.5

提供构建GUI的API

这时我的绝大部分工作都在围着浏览器转,而由于浏览器自身的局限性很多功能我都没法提供。比方说浏览器里就没法创建系统原生的菜单。(当然今天已经有了HTML5 Menu标签,而当时是2012年。)

于是我想到增加一个新的内置模块,用来提供对窗口、菜单等系统API的绑定,也就是:
require('nw.gui')

如果你有使用过NW.js的话,你应该很熟悉这一套API。

经过几个月的完善后,我发布了node-webkit v0.3.6,这也是由我维护的最后一个版本。

node-webkit的推广

虽然node-webkit属于Intel,但其更多属于rogerwang的个人项目,那时候这个项目在GitHub上也还挂在rogerwang的账户下。所以当时除了我自己一个人,没有其他任何来自Intel的资源投入。

而像node-webkit这样的框架类项目,只有拥有用户,才会有生存下去的意义,所以在开发node-webkit的半年时间里,我也一直有在积极推广。

首先是到处发帖子宣传node-webkit的好处,一大阵地是Node.js的邮件列表。每次有新版本我就会过去发布公告,回答问题,与人撕逼。其次则是编写范例应用,让新手快速入门,让其他人相信node-webkit的能力。最后则是去技术会议宣传,让大家知道node-webkit这个东西。

当然最重要的还是认真回答Issues里的问题,努力修复bug增加功能。

我的努力最后也得到了非常好的回报,在我结束node-webkit开发的时候,项目在GitHub上获得了数千个star,排到了C++项目排行的前十。

第一个用户

另外值得一提的是node-webkit的第一个用户,Light Table editor。这个编辑器的作者ibdknox很大胆地使用了node-webkit来进行开发,当时为node-webkit迎来了非常多的关注,也给大家吃了一枚定心丸,为项目推广助力巨大。

几年后Light Table又从node-webkit迁移到了Electron,当时好似好友重逢,感触良多。

工作的转移

在我为node-webkit工作半年之后,2012年底,这个项目开始吸引越来越多的注意力,也开始引起Intel一定程度的注意。rogerwang得到了机会放下其他的工作,开始全职维护node-webkit。

(GitHub的代码贡献表)


大家如果有在比较大的公司工作过,之前可能会奇怪,为什么一个实习生能如此随意地修改代码,发布新版本。其实正是因为这个项目当时在Intel内部无人关注,无人管理,我才得以随心所欲地尝试各种想法。

但之后正当node-webkit冉冉升起之时,我却彻底失去了node-webkit的自治权,开始收到命令去完成指定的开发工作,被禁止随意去增加功能,也不允许去随意修复bug,而发布新版本、和客户交流的工作也被转移给更高级别的工程师手上。正如一个大公司里的螺丝钉。

可能这种开发方式才是大公司的常态,我也不想抱怨任何人,但是抱歉,我只是一点也忍不了。

为GitHub而战

在我进行node-webkit开发的同时,GitHub正在秘密开发Atom编辑器。我了解到GitHub正在寻求一种使用HTMl和Node.js来开发桌面应用的方式,于是联系到Github
的工程师nathansobo,表达了为GitHub工作的意愿。

所幸node-webkit已经为我自己博得了足够的名气,在一面未见的情况下,我们敲定了协议,我需要将Atom迁移到node-webkit之上,并且提供支持工作。

于是2012年底,我结束了在Intel的实习,开始为GitHub作为contractor工作。

一个更好的桌面应用框架

在我加入Atom的开发时,项目还基于CEF。我们尝试了将Atom迁移到node-webkit上面,但是最终效果并不是很好,node-webkit当时并不稳定,而且API有太多的坑。

于是我开始重新考虑node-webkit的API设计,发现如果想要支撑大型应用,我不得不做出很多结构性的改变,而这些改变与其修改node-webkit,不如重写更加实际。在和GitHub讨论之后,我开始编写一个新的桌面应用框架,当时的名称叫做atom-shell。

有兴趣的同学可以去了解一下我们究竟做了哪些改变

左右互搏

后来,经过长时间的开发,atom-shell最终开放了源代码,而与此同时node-webkit 已经吸引了非常多的注意力和用户,我开始了和自己的竞争。

再之后node-webkit改名为NW.js,而atom-shell则改名为Electron。

(Electron 1.0)


维护开源项目的生活

说完了从node-webkit到Electron进化的历程,最后说说维护开源项目的体验吧。

和普通项目不同,开源项目几乎所有的用户都来自公司外部,取决于项目的受欢迎程度,每天都会受到相当大数量的邮件。就我自己而言,来自GitHub的通知邮件每天数量在50封左右,需要花1到3小时左右一一消化回复。很多issue要去仔细重现,一些话题也需要大量的讨论,很费神。甚至会有troll过来破坏所有人的心情。

其中最让人无奈的一个troll,最爱跑到issue下面留言,指摘Electron抄袭NW.js的代码,剽窃NW.js的理念,还到处劝人转用NW.js。简直了。

维护项目的另一项工作,是审核pull request,和维护node-webkit时不同,Electron的用户群要大很多,所以每天都会收到pull request,其中不乏高质量的代码。但多数时候代码都不能直接合并,要么设计不合理,要么代码不合规范,更多地则是引入新bug。所以每个pull request都需要细心查看,还少不了和贡献者大量的讨论。

于是,做完这些工作以后,留给写代码的时候反而少了很多,也是没有办法。但对于一个开源项目而言,这些琐碎的工作其实非常重要,只要让人感觉你的项目在被精心维护,才能不断吸引更多用户。一个维护不善的项目,哪怕初期因为种种原因吸引了很多用户,一旦更好的替代品出现,用户马上会飞速流失。

生活上,因为是全职做开源,影响反而非常小。GitHub的远程工作氛围非常浓厚,我的大部分工作时间也是在家里而不是办公室里,所以多数时候是想写代码了便开始工作,不在状态就把工作放在一边去做做喜欢的事,以此用有限的时间维持非常高的工作效率。

但开源会给自己带来另一个问题,责任感。一个没人用的项目,弃坑不过是一转念的事情,但是当越来越多人开始用你的项目,甚至有创业公司把未来压在你的项目上,责任感会越来越重,你唯一的选择就是将项目继续维护下去,无法弃坑,直到更好的技术出现。

不知道我未来还会维护Electron多久,不过就过去几年来看,还挺开心的,应该还会继续做下去吧。
为什么?