Github 是如何用 Github 撰写 Github 文档的

jopen 10年前

原文:https://github.com/blog/1939-how-github-uses-github-to-document-github
译者:@公子


一份好的文档能够帮助人们理解,使用以及贡献代码到你的项目中,但这只是一个生成文档的方程式的一半。生成文档的底层系统使得人们,无论是你还是一块和你工作的团队,撰写文档变得更加容易。

撰写文档最难的一部分既不是编写配置工具,也不是说明项目应该如何搭建和升级,而应该是文档的遣词造句。Github 文档团队的成员大多都是有使用XML文档生成工具和复杂的CMS系统背景的。正因为他们饱受了这些工具的折磨,所以为了不再使用这些工具我们花费了大量的时间去思考我们自己的文档生成流程和设置。

我们之前已经讨论过我们如何使用 Github 建立 Github 了。在这里我们将着重讨论一下我们如何使用 Github Page 服务运行 Github 帮助文档 (目前每月有上百万的访问量)的。

我们以前的流程

几个月前,我们把帮助文档的地层从 Rails 程序迁移到 Jekyll 托管在了 Github Pages 上。之前我们的帮助文档需要两个相互独立的项目仓库:

  • 用于托管维护网站、管理网站所用资源和文档搜索增强的 Rails 应用程序
  • 用户托管由一大堆 Markdown 文件组成的网站具体内容

我们的 Rails 应用程序托管在一个第三方平台上。随着对代码的日益升级,我们将它部署在了 Hubot ,这些都是我们在维护 Github 主站的闲暇之余完成的。(译者注:Hubot 是 Github 开源的一款自动化智能化执行命令的机器人项目,具体刻参考 Hubot 的主页。)

我们正常的撰写流程可能是这个样子的:

  1. 当有新特征开发出来的时候文档团队首先编写好文档内容
  2. 创建一个新的 issue 去追踪这个特征
  3. 当文档更新完毕一切就绪之后,我们会发起一个 pull request 去迭代更新文档内容。
  4. PR 发起成功后,我们会使用 @ 方式提醒团队(比如 @github/docs )并会让队友们审查一下我们的内容。
  5. 当这个特征开发完毕已经上线的时候,我们会合并之前创建的 PR。 使用 webhook 能够帮助我们在 内容仓库 快速激活我们部署的 Rails 应用程序。webhook 承担了负责更新数据库的任务。

下面是一个简单的示例给我们展示了一下我们正常的工作流程:

e65dc512-94eb-11e4-8fff-8e02f9bed3d4.png

使用 PR 进行工作是非常神奇的,因为它正好和我们在团队中使用的 Github 工作流程是一致的。并且我们喜欢用 Markdown 语言书写,更因为 Markdown 的语法能让我们不用花费多少时间就有效的描述新特征的所有内容。

然而,我们的 Rails 增强程序安装设置起来却非常的麻烦:

  • 由于我们依赖外部主机,所以我们需要专门的员工在我们的工程,运维和安全团队中监控站点和他们发起的响应事件。
  • 我们的文档团队并不能方便的在本地观察内容的变化。虽然我们使用的是 Markdown 编写的内容,可以实时预览,但是我们能忍需要配置一个本地的 Rails 应用服务去运行脚本将内容导入到数据库中然后观察其在网站上的最终效果。
  • 虽然我们不断的调整 Rails 的服务器,但是我们注意到用户的请求依旧使得网站访问变得非常缓慢。由于 HTML 页面是动态生成的,这就需要对数据库进行请求,这就耗费了很多时间。为了加快访问速度,我们还需要找寻更强大的缓存策略。

我们知道我们是时候做出改变做的更好了。

我们的新流程

Jekyll 2.0 发布的时候,我们看到了曙光,是时候该把我们这套该死的流程换成纯静态站了!特别是新增加的 Collections 文档类型能让你定义你需要的文件结构。另外,Jekyll 2.0 还增加了 SassCoffeeScript 的支持,这将使得编写前端代码变的更为简单便捷。

开源的好处在于它是开放的。我们迁移到 Jekyll 后,我们也向 Jekyll 发起了很多 PR 使得它能更好的服务 Github Pages 的用户。

使用了 Jekyll 之后,我们的工作流程发生了小小的变化。我们仍然使用 Markdown 并且我们仍然需要将内容 PR 到仓库以便其它人审查。但是当我们发起的 PR 被合并之后,Github Pages 网站将会在几秒内自动快速创建并部署。

下面是我们就如何使用 Jekyll 的核心功能以及我们使用的一些强化 Github 帮助文档站点的插件列了一个简单的纲要。

我们使用的 Gems

我们尽可能的依赖 Jekyll 代码本身的功能去尽可能减小我们依赖自己维护的自定义插件,这样可以减少我们的额外压力。

Jekyll 2.0 内自带的新的插件 Converter 使得用户可以将任何 标记语言书写的文件转换成 HTML。这样用户可以随便创作它的内容,Jekyll 只负责运行最后生成的 HTML文件就好了。举个例子,只要你会,你甚至可以使用 AsciiDoc 语法书写你的内容。

最后,我们开发了 jekyll-html-pipeline 插件,是我们之前开源的 html-pipeline 在 Jekyll 上的增强版。这个确保了我们的帮助站点的内容在 Github 上的任何地方看起来都是一样的。我们同时也开发了我们自己的 Markdown filter 插件去提供一些语法扩展使得我们编写文档更方便。

搜索

老流程的 Rails 网站中,我们使用了 ElasticSearch 对我们的数据库进行索引并增强了 Github 帮助文档的搜索系统。

现在,我们使用 lunr-js 提供一个更快速的客户端搜索体验。当然我们也通过筛选分析发现绝大多数用户都会依赖外部的搜索服务进入我们的文档。所以,在新流程迁移完成之后,维护一个服务端的搜索引擎的解决方案看起来已经没有多大的意义了。

内容引用

文档团队希望在编写文档的时候使用“内容引用”。内容引用允许你书写一次某大段文字然后在网站的任何地方直接复用它。(这个灵感来自于 the DITA standard。 )

旧的 Rails 系统并不能允许我们书写可复用的内容,但是现在我们有了强大的 Jekyll,它支持用户自定义 data files 。举个例子,我们已经创建了一个叫做conrefs.yml的文件,并且我们有一系列字符串形式的键值对集合像如下这样:

repositories:      create_new:          1. In the upper-right corner of any page, click {{ octicon-plus Plus symbol }}, and then click **New repository**.             ![New repository menu](/assets/images/help/repository/repo-create.png)

此时我们的键为repositories.create_new,其对应的值为下方的 Markdown 源代码(及 "In the upper-right corner...")。我们现在只需要简单一步就能在多个页面内容中复用这段内容:

To start the process:    {{ site.data.conrefs.repositories.create_new }}  2. Do something else.  3. You're done!

随着 Github UI 的变化,我们也许需要修改图片或者重新定义某些地方的指向。这个时候,我们仅仅只需要修改一个地方就能完成我们的变化,比起以前需要修改所有的地方简直不知道方便了多少倍。

版本化显示文档

另一个随着此次变化带来的好处就是我们现在能够显示多版本的帮助文档。随着 Github 企业版 2.0.0 的发布,我们对之前的 11.10.3 版本现在的 2.0 版本这两个不同版本提供了不同的帮助文档内容。为了达到这个目的,我们在 Jekyll 站点内容使用了一个特别的audience变量,并在我们的 Pages 仓库生成 HTML 的时候检查这个变量。

例如,在我们的config.yml文件中,我们设置了一个键叫做audience其值为11.10.340。如果某个特征存在在新版本的 2.0 中但是不存在于老版本的 11.10.340 中,我们会使用如下语法标记上这一部分:

{% if site.audience != '11.10.340' %}    This new feature...    {% endif %}

当然更使我们高兴的是,以上的实现都是基于 Jekyll 的核心功能,我们不需要为此创建或者维护任何其它的东西。

测试我们的站点

静态站点并不意味着我们可以不为它开发测试驱动。

我们的第一个测试内容的工具是 html-proofer。这个工具通过测试我们网站的每一个 URL 帮助我们核实我们的链接和图片都是正常的。

Ruby 的使用者们更熟悉使用 Capybara 在他们的测试中模拟网站的交互。在我们的静态站点实现一个类似的工具这个主意看起来很疯狂?并不! Github 的 bkeepers 4年前的一篇文章 已经谈论过这个问题了。当时,我们创建了更强大的测试工具,它涵盖了我们的内容测试和网站行为测试。举个例子来说,我们通过检查 YAML 文件中的键是否存在来确认某个内容引用是否有效,又或者说我们会测试我们的 JavaScript 代码是否运行良好。

我们的帮助文档在 CI(译者注:持续集成系统)上运行,这样确保了用户不会拿到损坏的内容。

7adf83be-84a3-11e4-8c41-1b3448a2f7df.png

速度

正如我们之前提到的,新的流程使得我们的 Pages 服务比之前使用 Rails 系统的时候有了标志性的加快。这其中一部分原因当然是因为新站点是一堆静态的 HTML 文件的集成——我们不需要向数据库获取任何内容。更值得注意的是,我们花费了大量的时间配置我们的 Pages 服务使得任何人运行它都是一样的快速。我们有的好处,比如使用 CDN 分布式部署站点资源等,这些对每一个 Github 用户来说也同样是可用的。

576d7e46-849d-11e4-8986-0bb86c2a58d5.png

让 Github Pages 为你工作

文档团队通过 Github 利用 Github 的工作流程(译者注:即前文提到的 Markdown 编写内容,PR 提交等),Jekyll 以及 Github Pages 服务来提供一个高质量的文档。Github Pages 提供给我们文档团队的好处同样对每一个运行 Github Pages 的站点都是可用的。

随着我们将文档迁移到 Pages,我们再也不用重建任何新的组件了。我们花费了更少的时间建立一些东西并且更多的时间去讨论我们的团队和公司应该有什么样的工作流程。通过使用和 Github 用户一样的托管系统,我们能够提供更好更快的文档系统。我们内部的工作流程是的我们变得更有成效,并且是的我们从未如此方便的提供版本特征,例如版本化内容。

如果你对 Github 文档流程的简历有任何的疑问,无论何时,Github 都非常乐于帮助大家