86163250 2019-06-27
因为业务需求,有赞自己造了很多轮子,组件库尤其多,React,Vue,小程序都有涉及,其他开源项目有 zan-proxy 代理,PHP 的框架 zanphp 等。有人可能会觉得奇怪,为什么有赞要造这么多轮子?其实原因真的很简单,就是因为现有的替代品无法满足我们自身业务的需求,可能是不满足我们的定制需求,也可能是功能不符合我们要求。根据业务需要,我们总结了一套适合自己的套路、规范,并把这些套路、规范做成了工具、组件库或者框架。
这大概便是有赞内部启动这些项目的缘由了。后来,随着这些项目的逐步完善,一个自然而然的想法就是把它们开源了,也许别人也有类似我们的需求。
慢慢的,有赞的 Github 上就有了好多开源项目。在维护这些开源项目的过程中我们总结了一些经验教训,在此跟大家分享。
Github 有一定的社交属性,维护好一个开源项目除了代码写得好,有一些使用姿势也是很重要的,我们总结了几点跟大家分享。
README 文件是项目给人的第一印象,所谓人靠衣装马靠鞍,开源项目有个好的脸面是很重要的,尤其是当这个项目还是一个前端项目的时候。针对 README 文件我们给出以下几点建议:
统一 README 格式的好处是让别人一眼就认出这个项目是某某公司或者某某人的,有赞内部就维护了一份 README 的规范。模版内容很简单,但是它保证了我们的项目有一定的识别度。
英文版的 README 不是为了装逼,如果你笃定自己的用户都在国内,那就只需要中文版的 README 就可以了。但是大部分情况下,项目维护者都希望自己的代码能够帮助到更多人,包括国外的用户,这时候英文 README 的价值就体现出来了。
开发指南很容易被忽略,它存在的目是帮助那些希望加入项目开发的开发者们快速上手。作为参与开源项目的开发者,他们对开发指南有哪些期望?我觉得无外乎几点:
如果开发指南能够回答这几个问题,有经验的开发者就可以比较快的参与进来。
相信很多人都遇到过这样一个尴尬的事情:有人在 Github 上提了一个 Issue,但是你看不懂这个 Issue 的描述,也不知道如何重现这个 Issue。
Github 提供了一个机制让项目维护者能够预先写好 Issue 或者 PR 的模版,其他人过来提 Issue 或者 PR 的时候就可以在这个模版上修改。模版里可以有针对性的告诉提 Issue 的人需要填写那些信息,这样子大部分时候都可以避免上面提到的尴尬场面。
创建这些模版也很简单,常见的方式是在仓库的 .github 隐藏目录下创建对应的模版 Markdown 文件。最近 Github 刚刚更新了模版机制,允许同时创建多个 Issue / PR 的模版。
例如 babel 仓库的 Issue 模版就有多个模版,每个模版对应不同的 Issue 类型,具体配置文档可以看这里。
Github 的 Labels 功能主要是用来给 Issue / PR 做分类的,方便索引和搜索。这里主要想说的一点是 Github 默认建好的 Labels 其实并不好用,我们推荐将 Label 分成几个正交的唯独,每个维度对应几个不同的 Label,可以参看这篇文章。
很多新手容易忽略 Label 这个功能,配合适当的 Label 分类,每个 Issue 都可以有一个很直观的状态展示。
Github 和 CI 系统的整合非常紧密,个人觉得体验做的很好。CI 系统可以用来做一些单元测试,代码风格检查等。很多仓库里 README 文件上的代码覆盖率数据都是在 CI 系统中生成提交的。
CI 除了用来运行单侧,还可以用来做其他必要的代码检查。例如 Zent 仓库中有一个脚本会在 CI 上检查提交的代码有没有按规范书写,如果发现代码格式不对,那么很有可能开发者没有在本地安装我们的 git 钩子,这时我们会提示开发者在本地安装钩子,格式化代码然后重新提交。
#!/bin/bash # Ensure everyone installs the git hook. # The result is a guess, but false positive # is not an issue here. RED='\033[0;31m' basepath=$(dirname $0) fail () { printf "${RED}$@\nAborting\n" exit -1 } pushd $basepath/.. >/dev/null 2>&1 yarn prettify git diff-index --quiet HEAD -- rv=$? popd >/dev/null 2>&1 if [ $rv -ne 0 ]; then git diff-index HEAD -- fail 'Git hooks not installed. Follow these instructions on your local machine:\n1. yarn install\n2. yarn prettify\n3. Commit your changes and push.' fi
这里顺带说一下 Github 上常用的两个 CI 系统使用感受:
Github 最近又上了一个新功能 Checks API,这个功能可以看成是原来 PR 和 CI 集成的一个升级版本,可以看见更加详细的测试以及 Lint 报告。
GitHub 有两个项目管理的工具,Milestone 和 Project。Project 可以显示一个类似看板的功能,而 Milestone 的定位更加轻量,类似一个任务集合的 deadline 管理工具。对大部分开源项目而言,可能 Milestone 更加合适。
上面介绍了一些 Github 的使用技巧,这里再分享一些项目开发、发布以及维护过程的一些小技巧。一个开源项目决不仅仅是一串代码而已,它更是一个技术产品,这就要求我们以产品的要求来看待这个问题。
以前端为例,NPM 的生态中绝大部分包都是使用 Semantic Versioning 的,如果我们项目的包不按照这个规则做,那么很容易给使用者一个 “surprise”。对于版本号不必恐惧它的数字越来越大,它仅仅是一个数字而已。
相信只要是个成熟的项目肯定都有自己的编码规范,有些项目可能提供了文档,告诉代码贡献者应该如何编码,同时也会有相应的 review,确保代码是符合规范的。但是,如果仅仅是代码样式方面的规范,我们建议通过工具来确保规范的落地。我们不提供编码规范的文档,但是我们有脚本来格式化所有提交过来的代码。效果就是代码随你怎么写,但是最终提交到 master 分支上都肯定都是按相同的规范书写的。
这类格式化工具有很多,例如前端领域用的比较多的 Prettier,Go 语言自带的 gofmt,以及 Reason 的 refmt 等。花点时间 Google 一下,找一个适合你项目的格式化工具。
Github 针对 PR 提供了三种 merge 选项,这里推荐只开启 squash merge 这一种。所谓 squash merge 是指将 PR 分支上所有提交合并成一个新的 commit,然后将这个 commit 通过 fast-forward 的方式合并到目标分支,我们认为这种方式是最适合走 PR 的项目的。当然,如果你希望保留 PR 上的每一个提交记录,那么建议使用 rebase 的方式,不管是通过 Github 操作还是自己本地 rebase 后再提交。
为了减少每次发布的工作量,我们以前的更新日志是脚本根据 Github 的 Issue 以及 PR 记录自动生成的。但是我们慢慢发现由于 Isssue 以及 PR 的标题规范性不是那么好,导致更新日志的可读性变得比较差。另外一个问题是机器生成的更新日志它没法做到把同一组件的修改归类整理到一起,这也是可读性较差的一个原因。
我们现在的更新日志是通过脚本先生成一份“草稿”,然后由包的发布者在这个基础上总结提炼出一份方便阅读的更新日志。这种方式增加了一些发布者的工作量,但是更新日志的可读性有较大提升,投入产出比还是可以接受的。
“售后服务”是做开源项目的时候最容易被忽视的一点,如果我们以技术产品的要求去维护一个开源项目,那么我们就有责任给用户提供必要的支持。这些支持包括:完善的产品文档,答疑的群组以及一些产品技术博客。有了这些“售后服务”我们才能形成一个完整的技术产品闭环,通过用户的反馈不断完善。
本文从 Github 的使用姿势切入,在项目开发、发布、维护以及文档生成等方面分享了一些我们认为正确的开源项目维护心得。我们始终保持开放的心态,欢迎各位给我们提建议,一起改进开源项目的管理方式。
一些可能有用的工具链接: