原文链接:https://segment.io/blog/tips-for-maintaining-an-open-source-library/
作者:Calvin
翻译: 姚立 齐腾飞 马磊

5个月前,我们通过Hacker News发布了一个叫做Analytics.js的小类库。几个小时后,它的点击率就爬升到第一。在短短的一天内,项目的星(star)由20个变为超过1000个。从中我们学到了大量的管理开源类库的经验,因此,我想和你们分享其中的一些小窍门。

一开始,我们对管理开源类库一无所知。我认为,我们中的任何一个人在这之前都没有过合并pull requests代码的经验。因此,我们必须快速学习相关的知识。

现在,Analytics.js已经有超过2000个星了,开源社区中有很多人贡献了很棒的代码。一路走来,我们学到了很多让pull requests保持高质量的经验,以及如何简化贡献者的开发流程。


1. 保持编码风格的统一

新的开发者将会从现有的代码库中学习如何为库增添新的功能,而这才是他们应该做的事情。所有的开发者都想按照代码库的规范去增加新的功能而不是他们自己的规范。你的主要工作就是使这种规范尽可能的简单。新的开发者将会从现有的代码库中学习如何为库增添新的功能,而这才是他们应该做的事情。所有的开发者都想按照代码库的规范去增加新的功能而不是他们自己的规范。作为一个开源项目的维护着主要工作就是使以上情况尽可能的简单。

当你的分支代码和核心代码表意含糊不清时无数的麻烦就来了,如果你在两个不同的地方用两种不同的方式做同一件事情,开发者怎么知道哪一种方式才是推荐的呢?答案是:他们不知道。

更糟糕的是由于你的编码风格不统一,开发者无从决定,那么也会编码不统一(按自己的偏好来)。

解决这个问题你需要花费很多的时间规范代码风格。作为一个准则,你不应该尝试在一个简单的开源库中用两种不同的方式。如果你一定要改变风格,那一定要迅速的在全球都改变。否则新人将无法区分你之前代码和现有代码的约定。

我们一开始用一种很差劲的方式处理这个问题,所有的代码在一个文件里面,函数没有一个良好的结构组织。(并且如果你检查我们的提交,就必须先理清代码)我们在设计代码规范统一上没有花时间,所以库里的代码编写风格混杂不堪。

当pull代码的时候我们每个人都与别人的代码发生冲突,因为每个人都修改了同一个文件,并且在他们想要插入新函数的地方加入自己的功能函数

2. 使用正确的方法,简单的方法

最初我们构建代码的方式,导致在合并 pull requests 的时候遇到了许多问题:换句话说,刚开始我们的代码就没有结构。我们做出的改善代码结构的比较大的改变之一是使用 Component

Component

我们喜欢 Component 因为它消除了编码风格不统一的问题,减少了代码库的规模。Component 使用 CommonJS,所以我们只需要在我们需要的地方,引入(require)我们需要的模块即可。所有的事情都简单明了,这就意味着我们的代码对于新人来说更容易跟进。这是代码库维护者的梦想。

在进行切换期间,我们写了一堆自己的组件来替换已经附在全局对象analytics上的通用函数。现在,组件可以在库的任何地方很简单的包含进来和使用,pull requesters 只是默认使用他们。

自从我们发布了正确的方法,并且使他更加清晰,pull requests 的代码质量获得了显著提升。

为了尽可能保持统一编码风格的延续,当有新的代码提交上来的时候,你必须积极主动。不要害怕给 pull requests 的代码添加注释,即使看起来只是一处很小的更正,也不要害怕拒绝不必要的可能会搞乱你的 API 的 requests。

必须牢记的是,同样要严格要求自己的代码。如果在添加新特性时,自己开小差,懒得统一编码风格,那么为什么项目的贡献者不可以开小差呢?总之。你的代码越干净,对于新手来说就有越多的好的示例学习。

如果说到不偷懒这个话题的话,那就......

3. 写测试,并且连接到 Travis

写非常好的测试覆盖无疑是加速开发最简洁而有效的方法。由于我们 一直 在提交更改,所以我们不能因为担心现有功能遭到破坏而浪费时间。我们写了 很多 的测试,同时得到了很多的收获:更快的开发、对我们的代码更有信心、对贡献者的代码更有信心,还有很多……

这也会吸引更多高质量的 pull requests!

当开发者临摹了我们库的编码风格,会把它延伸到测试中去。在添加相应的测试之前,我们是不会接收贡献者的代码。

好的一面是我们不必过多的强制执行。感谢Travis-CI,几乎所有的 pull requests 是经过完全测试过的,而这些测试都是参考了我们已有的测试案例。既然我们坚信我们已有的测试有很好的质量,自然,由此而衍生来的测试便有了一个更高的起点。

Travis 与 GitHub 有很好的整合,它能显著的简化 pull requests 的合并过程。如果一个 pull request 没有通过所有的测试,你和贡献者都能收到通知。所以这会激励他们完善一个重大的修改。

travis-ci

拥有一个 passing Travis 标记也会增加信任,表明你的库文件正在正确的轨道上运行并仍然在维护。更不用说同行让你感到压力来保持你的测试在好的状态(显而易见这是最难的部分)。

4. 从第一天就开始版本管理

良好的版本管理,就像测试一样,需要约定规范并很值得这么去做。当开发者遇到问题时就会马上去检查运行的是不是最新的版本。如果不是,他们会更新代码并解决这个bug。如果没有版本管理,你仍然会收到提交的 bug 甚至是你早已解决了的bug。

我们开始的时候,都完全不知道如何控制版本;我们的代码仓库基本上只是一堆提交。如果你频繁的上传更新,就会导致使用你的代码库的开发人员不必要的困扰。

一开始,你的版本控制需要如下三样东西:

  1. 一个 Readme.md 文件来描述你的代码库是干什么的。
  2. 添加版本号到源代码和 git 的标签中。
  3. 一个 History.md 来记录版本更改的日期和描述等信息。

拥有一个 changelog 对于开发人员跟踪 issues 很有必要。开发人员在任何时间发现了一个潜在的 bug,changelog就会成为开发人员第一个去查看并解决这个 bug 的地方。

给代码仓库添加标记也被证明是非常有用的。每个版本都有一个定义良好且已经稳定的代码的包。如果你正使用一个前端打包工具比如 Component或者Bower,你也能得到非常好的自动打包。

不要忘了把版本控制添加到你的源代码中去,放到使用它的开发人员能够接触的地方。因为当你在远程给别人 debug 的时候,就能快速的通过源代码来查看他们使用的版本来节省时间。

对了,还有使用semver。这是开源项目的标准。

5. 添加Makefile文件——黑客的指导手册

偷偷告诉你一个小秘密:我们几乎没有为那些想向这个类库贡献代码的人准备任何文档(这是另一个我们需要解决的问题)。但是我仍然很惊讶地发现,即使在没有任何构建或者测试手册的情况下,我们仍旧收到了很多的pull requests。

回过头来看下我们的代码库,那些新开发者是怎么知道如何构建脚本的呢?

正如我刚刚提到的,我们选择在Component上面构建流程。它远远领先我们老的构建流程,可惜并没有被广泛的接受(但是我们打赌终究会有那一天的)。

想象一下,大多数人之前并没有见过基于Component的代码库,我大胆猜测,他们是通过我们的Makefile文件学习的。make命令就是天然的入口点(译者注:make命令中的伪目标),从而了解整个新项目是怎样运行的。因此,它就成为既成事实的用户手册了。

我们在脚本中使用长标识(long flags),并且给每一个命令一个描述性的名称。因为使用Component构建我们的类库,我们可以首先参照他们的文档,然后再写自己的文档。一旦你理解了Component是如何工作的,你就会明白所有基于Component的代码库是如何构建的。

在不断 过程中,我们做了很多工作来使我们的Makefile文件更加简洁明了。记住,你的构建和测试脚本也是你代码的一部分。它们也需要保持干净和可读性,因为它们是新来者最先接触到的东西。

6. 不断迭代流程

注意我所提到的所有技巧是如何精简流程的吗?这是因为维护一个流行项目必须如履薄冰,否则后果不堪设想。每当新的isuues出现时,你会不断地做小的修复工作,如果你不优化开发流程的话,你将会疲于奔波。

不仅如此,你的类库质量也会出现问题。如果没有一个好的构建系统、自动化测试和干净的代码库,修复小的bug就会像打扫家务一样繁琐,你需要花越来越多的时间去解决问题。当然没有人想要这样!

我们已经学到了很多管理像我们代码库这样大小的代码库的经验,但是面对管理一个真正大的项目时,我们还有很长的一段路需要走。管理一个大型的开源项目需要花费很多的功夫。随着代码量的增加,想要进行一次大的代码重构将会变得愈加困难。当越来越多的人依赖这个项目的时候,随之而来的pull requests也会开始增加。

我们还有一个些TODO事项,希望可以让管理Analytics.js更加容易:

  • 我们想要把测试文件拆开来以尽可能方便管理。目前而言,文件的大小有点超出可控范围了,这就意味着对新来的人来说,很难一次性记住所有的东西。

  • 给贡献者提供更好的文档——听起来有些荒诞,我们竟然还没有做这件事。我们也很惊讶我们竟然能在没有文档的情况下处理所有的pull requests,因此,这是我们亟需要完成的。

  • 我们自己也开始采用pull requests的方式修改代码,这样我们就有机会互相审核彼此提交的代码,而其他的贡献者也可以加入到我们的讨论中来。

我们的很多策略都是沿袭了Node.js源码的管理策略,对于新的贡献者来说,它拥有很多很棒的指导方针。

每一个Node.js的提交都会首先被拉过来,在合并到主干之前都会经过核心贡献者的严格审核。每一个新的特性都会先在issues或者pull requests上讨论,所以不同的提议都会被考虑。Node的提交日志也非常清晰翔实。他们为新的贡献者准备了全面的指导手册,并且使用jslint做一个大致的代码风格检测。


金无足赤,没有一个项目工程是完美的。但是吸收这些第一手的经验教训,可以帮助我们更好地实践我们其他的类库。希望,这些小窍门同样对你有帮助!

你们有没有自己管理开源项目的经验教训或者在某些项目上做的非常的棒?如果有,我们将很荣幸能够听到这些经验。或者在Hacker News上把这些经验留言给我们