编者按:本文是张亮在高可用架构群新年聚会暨架构开源研讨会上的分享。转载请注明来自高可用架构公众号「ArchNotes」。
张亮,当当网架构师、当当技术委员会成员、消息中间件组负责人。对架构设计、分布式、优雅代码等领域兴趣浓厚。目前主导当当应用框架 ddframe 研发,并负责推广及撰写技术白皮书。
“我们认同马丁福勒这位代码沟通大师的理念,任务代码是给人看的,不是仅仅给机器编译用的。维护一个有缺陷但是代码清晰的项目,远比维护一个代码混乱但暂时未发现缺陷的项目要更加容易、更加受欢迎。” —— 张亮
大家好,我是张亮,目前任职当当架构部架构师一职,也是高可用架构群的一员。
首先我介绍一下项目背景。当当在 2015 年 9 月开始开源了内部使用的分布式作业调度框架——elastic-job,然后又于 2016 年 1 月 18 日开源了数据库分库分表中间件——sharding-jdbc。
当当后端使用 Java 开发较多,所以这次做的开源项目也是基于 Java 开发者而非产品型。目的是让 Java 程序员能够顺畅使用,对于非 Java 用户可能未必友好。这两个开源项目的背景不太一样,elastic-job 是先于公司使用,基本成熟之后再开源于社区。而 sharding-jdbc 是先开源至社区,再于公司内部同步推广落地。(小编:点击文末链接了解 elastic-job 10 大特性介绍)
截止到目前,我们做了 4 个月的开源相关的事情,虽然经验并不丰富,但是也想和大家分享一下与开源相关的经验和问题。
1. 开源初心
1.1 为什么要做新项目?
在做新项目之前,我们做过大量的调研。
分布式作业调度这块,quartz 可做到依赖于数据库的高可用,但无弹性调度功能。tbschedule 这样老一些的项目在时间调度方面又不如 quartz 强大。
分库分表的数据库中间层方面,虽然有 cobar、tddl、mycat、compass、oceanus、kingshard、atlas 等一系列开源产品,但目前确实无法完全覆盖我们的需求。
1.2 做成什么样?
我们选择做一个面向开源,且不与业务系统耦合的纯技术组件。也就是说,底层的这些组件,并不是从业务系统分离出来的,而是完全从技术组件的角度去开发,然后再向业务系统发起落地。所以,这两个组件可以在只做很少改动的情况下开源。
1.3 标准
既然已经决定开源,项目的质量要求即是以开源的标准来要求。
公开给所有人的并不只是功能和文档,而是全部代码,这样的质量要求和做一个内部项目是不同的。我们认同马丁福勒这位代码沟通大师的理念,任务代码是给人看的,不是仅仅给机器编译用的。维护一个有缺陷但是代码清晰的项目,远比维护一个代码混乱但暂时未发现缺陷的项目要更加容易、更加受欢迎。
测试用例的覆盖率是另一项重要标准,我们要求测试覆盖率尽量达到 80% 以上。如此才可以放心的重构和完善新功能。目前我们两个开源项目的测试覆盖率均超过 90%。
代码要完全掌控,不能允许有谁都不敢碰的黑箱存在。
1.4 目的
1.4.1 反馈社区。每个开发者都或多或少的使用过开源产品。在使用开源的同时尽量的反馈社区,让开源成为良性循环。
1.4.2 吸取社区精华。使用的人越多,看代码的人越多,项目的缺陷和风险就会越小。而且众多社区成员的使用,有助于疑难问题重现。比如:我们公司内部的 ZooKeeper 环境比较快,延迟低,一些分布式的问题就较少发生。但有的公司网络环境稍差,就会产生 ZooKeeper 延迟导致的一些问题。发现问题的途径越多就越有利于项目的健康发展。而且社区人员确实反馈了一些关键问题,贡献了关键代码,这些代码也解决了当当内部的一些部分使用问题。
1.4.3 提升公司技术品牌。开源之后收到越来越多的人询问当当是否还招人,也更多收到了讨论技术问题的邮件和 QQ。这些影响都是潜移默化的,会渐渐的让公司的技术影响力提升。对于不发出技术声音的互联网公司,可能会越来越难招募到优秀的开发者。
2. 经验分享
2.1 文档问题
文档要清晰,代码不能代替文档。代码写的再清晰漂亮,很多使用者也是通过文档来了解并使用项目的,通读代码的使用者毕竟是少数。但文档绝不是越多越好,一定要适中,信息量爆炸不利于信息的吸收消化和检索。
2.2 信任度问题
项目是否靠谱,是否稳定,是否可以拿来即用,是开发者选择使用开源项目要面对的问题。以下三点可能会有助于开发者选择这个开源项目信心的提升。
2.2.1 公司案例
只要自己的公司在大规模使用,则至少证明在某些场景下,项目是稳定的。公司案例的推广和分享有助于开发者选择。
2.2.2 测试数据
需要通过公布疲劳测试的稳定性,性能测试的对比场景等数据提升使用者信心。
2.2.3 通过代码展现实力
代码需精雕细琢。举个例子,sharding-jdbc 一共开发了三个月多一些,核心代码一个月左右就开发完成了,剩下两个月都是在打磨。主要包括整体流程梳理、模块拆分规划、代码可读性重塑、封装粒度缩小等。开源项目是否可持续发展的关键点即在于此,这是对一个项目负责的态度。
我看到过的一个开源的项目,使用的 SQL 解析完全是从第三方的 SQL 解析包中复制过来,除去修改包名,大段大段的英文注释都没有改。而 SQL 解析一般使用 javaCC 这样的技术生成的代码,这种代码动辄上万行,难于维护。这等于是将引用第三组件的技术债放到了自己的项目中,这种做法是不太负责任的。
2.3 沟通问题
我们更倾向于需要一个 QQ 群,用于轻便和愉快的沟通,也便于头脑风暴。部分开发者属于内向型,如果是 issue 或者邮件这种沟通方式,他们未必会采用。QQ 群的另一个好处是提升亲和度和社区粘性。QQ 群中最好有一个活跃的组员是项目主导人员,及时沟通和反馈项目情况。
2.4 版本问题
开源项目一旦更新,是首发于 github 还是先于公司内部发布。有些公司内部的比较着急的需求,需要在内部改完直接使用,长久下去会导致公司内部代码和开源版本混乱,不易维护。个人倾向于维护统一版本,先于社区开源,再拉取到公司的 maven 私服。这样做的好处是优秀的想法不会滞后,而且可利用社区活跃度规避一些潜在风险。
2.5 技术难度问题
开源项目一般难度会大于业务项目。这里以 elastic-job 和 sharding-jdbc 举例。两个项目的难度展现在不同的地方。elastic-job 属于分布式框架,代码编写并不难,难点在于分布式环境下的调试和问题重现。sharding-jdbc 刚好相反,调试难度不高,一条 SQL 能否正确执行,这个环境非常容易重现,但编码难度却较大,SQL 解析、路由、归并的难度远远大于一般项目。
针对于这样的问题,为了可以让更多的人参与项目贡献,我们考虑把任务分级,分为简单型、长期型、讨论型、缺陷型和技术难点型。
- 简单型例如运维页面由中文专为支持多语言,这样的任务可以让有兴趣的社区人员参与开发,并无太多门槛。
- 长期型属于核心任务,最好由资深的开发人员或者项目的主导人员完成,比如:作业系统增加任务依赖。分布式数据库增加柔性最终一致性的事务。
- 讨论型一般会在 QQ 群,wiki,issue 等平台讨论,比如 roadmap 先做哪些,某个具体任务的取舍等,最终会转化为其他的任务类型,当然,一般不会转化为简单型。
- 缺陷型属于快速响应的任务,在下个升级版本就会发布。
- 技术难点型需要做调研,调研明白之后才决定如何做,有这方面技术经验的社区人员可以提供更多的帮助。
3. 未解决问题
3.1 时间分配问题
开源之后必然会吸引一些爱好者关注。有些爱好者因为时间关系,并未阅读代码,甚至未阅读文档,就直接问一些基础问题。有些爱好者因为经验尚浅,会问一些和项目不直接相关的问题,比如:maven,zookeeper 怎么用之类的。可能会导致项目 master 浪费一定时间。
3.2 技术反馈问题
很多爱好者将项目用于自己公司的系统,也确实做了一些改进。但是限于时间原因,未能将代码质量控制的很好,或者未能完全剥离公司的业务场景。这样就很难再将有意义的更新反馈至社区。
3.3 多人合作质量保障问题
项目小团队集中开发时,这个问题并不明显。一旦贡献者多了,代码评审,质量管控,处理 pull request 等就会比较难。
总的来看,以上当当开源的经历主要介绍了初创开源项目从 0 到 1 的过程,在以后肯定需要进一步完善并面对新的问题,以后的问题和上面说的也会有很大差别。但我们也相信,更多同行面临的是我们上面碰到的新的项目从 0 到 1 的过程,希望通过以上的分享,吸引更多感兴趣的同行一起加入到开源的大家庭,共同推进技术的进步。
4. 参考阅读
新一代分布式任务调度框架:当当 elastic-job 开源项目的10项特性(点击图片进入)