TensorFlow 团队如何管理开源项目
社区服务
当一个新项目发布出来时,该项目唯一的专家就是编写这个项目的人。他们是唯一可以撰写文档和回答问题的人,而且他们可以最有效地改进软件。因此,我们这些 TensorFlow 团队中的核心成员也成为了项目扩大的瓶颈:毕竟我们无法马上完成任何事情。我们知道如何编写代码和文档,因为这些任务是我们日常工作的一部分。但另一方面,回答大量来自社区开发者的问题不是我们应该做的事,尽管我们也知道这对于项目的成功至关重要。
为了保证用户可以获得所需要的答案,核心工程师团队的所有人都加入了轮流回答问题。团队成员可以选择解决 Stack Overflow 上带有 #tensorflow 标记的问题、在 GitHub 上审查 pull requests,分类 GitHub issues,处理同步外部和内部代码或追查测试失败的原因。
通常,每个工程师每次对一个特定领域负责一个星期,以循环的方式轮流负责。因此,轮值的工程师在本周正常工作中的生产力会低很多,不过至少每个人工作被打断的频率降到了几个月一次。
Pull requests
我们开源 TensorFlow 部分的目的是希望通过社区的贡献来改进它。到目前为止,我们已经拥有超过 400 个外部贡献者添加了代码,从小的文档修复到大型的添加,如支持 OS X GPU、OpenCL 的实现或 InfiniBand RDMA。首先,轮值的核心工程师必须对每项贡献都进行审查,以确定是否有价值。如果贡献通过初始审查,会触发一组 Jenkins 测试,以确保其不会导致任何故障。如果这些行为也通过审查后,值班的工程师可能会希望其他对这个领域更了解的工程师来看一看,所以这将会被转交给该专家进行审查。
GitHub 全新的详细的代码审查工具在这个过程中提供了很大的帮助;没有它们之前,处理所有的个人意见是一件痛苦的事情。通常,大的 PRs 会在工作中保持一段时间,核心工程师会和一个或多个外部贡献者协同工作,在大家都满意后,PR 将会在 GitHub 中被合并,然后在下次运行同步时合并到我们的内部代码库中。
代码许可协议
作为我们自动的 pull request 的一部分,我们会将贡献者的 GitHub 账号与我们在 cla.developers.google.com 上的记录相匹配,以确保任何的外部贡献者都拥有代码许可协议(CLA)。我们的目标是确保整个代码库可在 Apache 2.0 协议下准确无误地分发。当 pull request 的轮值工程师要对出现的所有问题进行整理时,如果一个 pull request 内部关联了不同的邮箱,或是贡献者需要以公司的身份登录,情况可能会变得复杂。
GitHub issues
目前已经有超过 5000 个 issues 提交到 TensorFlow,对于有些人来说,这看起来似乎有点让人沮丧。但这是我最喜欢的指标 —— 它说明了用户有在真正使用这个项目!为了确保能对每个提交的 issue 都进行回应,值班的工程师会时刻关注新出现的信息,并尝试使用标签对它们进行分类。如果是一个我们内部不太可能在短期时间内实现的特性,我们会将其标记为“Contributions Welcome(欢迎贡献)”,对于 bug,我们会尝试优先考虑。这段时间以来,随着外部用户自己也成了某些领域的专家,我们看到越来越多的问题无需我们的帮助也能够被解决了。特别是在像 Windows 这些我们不是每天都使用的平台上。
如果某个 issue 通过社区没能找到答案或者解决方案,而且它的优先级也比较高,值班工程师会将其分配给对这个领域更了解的工程师。整个 TensorFlow 团队都有 GitHub 账号,所以我们可以使用常规的 GitHUb issue 跟踪器来分配问题。我们考虑过把用户提交的 bug 复制到我们的内部系统,但为相同的信息同步两份副本的代价实在是太高了。因此,我们的工程师除了要关注内部的跟踪器之外,还需要打开 GitHub 上有人提交了 bug 的邮件通知,以便及时看到属于自己的分配。
Stack Overflow
Derek Murray 是 Stack Overflow 值班小组的负责人。我十分敬畏他回答问题的能力,根据他的个人资料页,他发表过的帖子已经被超过 130 万人浏览。他还设法建了一个由 RSS 源驱动的自动化电子表格。开始的时候,我们每周轮流负责,但后来需要处理的问题的数量变得十分庞大,一个人难以处理。所以后来在轮流的基础上,我们采用了自动分配问题的方式来代替之前的做法。
目前我在这个小组里,因此每天早上浏览完自己的的邮件后,我会通过查看电子表格来看一下自己被分配到了什么问题。很遗憾,我们做不到自己回答所有的问题,但我们会审查每一个进来的问题。如果问题相对比较简单,我们会自己回答。
值班的工程师是一个“前线”的角色,但有时候回答问题需要更多的时间或专业知识。如果问题看上能被解答,但社区里却没人回答,我们就会研究一下代码(通常使用‘git blame’)来看一下团队里有谁可能会对这个问题有一些想法。然后值班工程师会发送一封电子邮件,询问我们找到的内部专家是否可以提供帮助。
邮件列表
我们设置了一个邮件列表,起初我们不太清楚该用它做什么。但很显然,用它来跟踪问题或回答一般的问题是十分糟糕的方式。
后来,我们把它当做讨论区来使用。但在实际使用中我们发现,即使对于架构问题,GitHub issue 也比它更适合。
因此现在我们使用邮件列表来发送信息和分享通知,这还是值得订阅的。
代码同步
很多和我聊过天的人都会对这样一件事感到惊讶:我们在谷歌内部使用的代码库和我们在 GitHub 上提供的几乎完全相同。然而它们之间还是有一些区别的:例如,对谷歌专用的基础设施的支持是分开的,路径也不一样。但同步过程是完全机械化的。我们至少每周推送一次内部变更,并且也会经常从 GitHub 上拉取。
棘手的问题是我们要进行双向同步。在 GitHub 公共项目和我们的内部版本中,有很多更改是同时发生的,我们需要反复把它们全部进行合并。由于没有现成的基础设施可供使用,我们创建了一系列的 Python 脚本来处理这些问题。脚本可将 GitHub 上的改动拉取到我们内部的资源存储库,并转换所有的头部路径(header paths)和其他小的更改,将它们与最新的内部代码合并并创建一个内部副本。然后我们就可以进行另一方向的同步,我们会将所有内部代码装换成外部格式,并使用相同的脚本将结果合并到最新的 GitHub 上。
对于内部的更改,我们也会尽力确保每次check-in 都会以单个的 git commit 呈现,并把作者的 GitHub 账户和对这些更改的注释也包括在内。我们在 GitHub 上有一个特别的“tensorflow-gardener”账号用于管理这个流程,点此查看一个内部的 commit 迁移到 GitHub 会变成怎样。
确保在代码更改的情况下,转换流程依然有效是十分具有挑战性的。为了验证有效性,每个内部改动通过脚本转换成外部版本后仍可运行,而且与初始的内部版本没有任何差别。在任何涉及到 TensorFlow 代码库的每个内部更改上,都需要运行这个测试,不能通过测试的修改将被拒绝。对于那些发送 pull request 的人,我们有时候会要求他们进行奇怪的更改。通常,这样做的原因是我们必须确保他们的代码能与这个同步基础设施正常运行。
测试
因为我们需要支持很多平台,所以我们希望拥有一个适用范围广的测试基础设施。TensorFlow 在 Linux, Windows, OS X 桌面, 和 iOS, Android, Android Things, 以及 Raspberry Pi 上运行。同时我们还有为 GPU 提供不同的代码路径,包括 CUDA 和 OpenCL 支持,以及 Bazel, cmake, 和 plain makefile 构建过程。
让每个开发者在更改后把上面这些东西手动测试一遍是不可能的,因此我们有一套能在大多数受支持的平台上运行的自动化测试系统,所有这些都由 Jenkins 自动化系统控制着。保持这样的工作需要大量的时间和精力,因为总是会存在操作系统更新、硬件问题以及其他一些与 TensorFlow 无关的问题导致测试失败。我们有一个工程师团队,专门负责保证整个测试系统正常运行,这个团队曾多次帮助我们,让我们幸免于难,所以这个投资是值得的。
开发者关系
在谷歌,我们在开源领域工作不孤单。我们从像 Kubernetes 和 开源计划办公室”(Open Source Program Office)这样的项目中学到过很多东西。我们还有一支非常努力的开发者关系专家团队来协助我们,他们还处理了很多围绕文档、代码示例以及其他一些开发者经验问题而产生的体力活。我们的长期目标是将关键的专业知识传递到核心开发者之外,以便更多 Google 内部和外部的人员能对社区做出贡献。
让核心工程师“兼职”承担客户服务工作的一大好处是可以直接了解用户所遇到的问题。参与客户服务也驱动着我们去改进常见的错误并增加文档,因为它在减少工作量方面让我们看到了直接的回报。
展望未来,我们希望可以将这项工作更广泛地进行下去,也希望更多人可以熟悉框架的细节、文档的改进,我们创建了更多的“指导手册”以帮助人们处理常见任务(如错误分类)。在此之前,我为有机会和如此多的外部开发者进行互动而感到幸运,也希望通过帮助他们使用机器学习创造新的令人惊叹的应用,从而产生积极的影响。
关于作者:
Pete Warden 是 TensorFlow Mobile 团队的技术主管,之前是 Jetpac 的首席技术官,该公司于 2014 年被 Google 收购,主要工作是优化其在移动和嵌入式设备上的深度学习技术。他曾在苹果公司工作,负责图像处理的 GPU 优化,并为 O’Reilly 撰写过关于数据处理的书籍。