从构建和测试的效率说起

最近的工作总是在 EMR 上跑 Spark 的 job,从代码完毕到测试完毕的过程是这样的:

1. 本地测试:

    构建 -> 本地 UT -> 观察分析结果,这一阶段可以发现逻辑问题

2. EMR 上执行测试:

    上传最新构建到 S3 -> 准备 EMR 资源(包括计算资源和数据)-> 在 EMR 上执行 Spark job -> 观察分析结果,这一阶段可以发现在数据量较大的情况下才出现的问题

3. Workflow 集成测试(这个 workflow 是公司内部的一个管理 job 的工作流系统):

    启动 workflow -> 观察 job 状态 -> 等待 workflow 调度和资源分配 -> 等待 workflow 执行结束 -> 观察分析结果,这一阶段可以发现在 workflow 配置、参数等环境上的问题

现在回过头来看整个过程,基本上思路还是清晰的,但是,一开始不是。开始的时候我没有做第二步,直接从 UT 跨越到 workflow 上的测试,结果就是效率低下,大量的时间都在等待 workflow 的调度和资源分配,跑一次任务得等上一个半钟头以上才能看到结果。所以,经验教训就是,测试要有层次,简单的东西写了跑很方便,但是异步 job 这样的东西,特别是数据量大的时候,根据不同的测试成本分成不同的阶段,尽可能在测试成本最小的时候把能覆盖的待测试项全部覆盖了。跳过一个大的步骤多数情况下并不能节约时间。

有的问题能够通过良好的习惯和方法减轻痛苦,但是有的却很难。我联想到一个这样的问题,把新的 package merge 到已有的某一个 version set(一个 version set 定义了一系列的 package 和版本)里面去,比方说,一个 package 的版本升级,这里面的构建和测试简直痛苦不堪,主要是需要大量时间的等待。就算有了自动构建和测试的流程,也只能在一定程度上帮助发现问题,分析和修复问题还是需要大量的时间精力。一种参考做法是:

1. 某一天自动化构建的 pipeline 上出现了构建 failure,发现是某个 package 版本更新所致

2. 把对应的 version set 同步到本地开发机,然后下载那个需要更新版本的 package,更新那个 package 到需要的版本,构建

3. 本地过测试用例,包括原 pipeline 上导致构建失败的用例

4. 问题解决以后上传修改,触发 pipeline 回归测试

这样的步骤说说简单,但是实际操作起来坑和疑问也不少。比如在开发机上要选择那个待更新版本的 package,选哪一个,需要去调查;比如说这个 package 的构建出问题怎么办,因为它大多数情况下都不是自己 team 维护的;再比如有 jar 冲突问题、不兼容问题怎么办(比如 a 依赖 b,a 也依赖 c,b 更新了以后,c 和 b 不兼容,需要更新 c,c 一更新又和某个新冒出来的 d 不兼容,有时候如此反复,简直是地狱)等等。一个 version set 里面可能好几千个 package,真正对 version set 的完整的构建和测试很难在本地开发机上完成,即便使用那些通用的工具,也需要大量的等待时间。对于 jar 包管理的问题,我经历过的两家公司各有不同的解决办法,但是都难说令人满意。

再说一个争论,产品开发的过程中,code branch 有两种典型的运作模式:

  • 一种是 single branch,只有一个主线版本,程序员需要开发功能或者修复问题的时候,在本地编码、构建、测试、提交、审查之后,直接 push 到主线中;如果这个修复工作非常大,有时会自己 cut 一个新 branch 来工作,完成以后 merge 到主线版本中。
  • 还有一种是两个 branch,一个叫 development,用来开发;还有一个叫 release,用来发布版本,这样的话发布的内容可以完全和开发的内容分离开,而对于紧急问题的修复可以直接 patch 到 release 上面去,而在 development 上面可以用最合适的办法慢慢修复。

看起来似乎第二种能够解决更多的问题,不存在特别难受的“ 死角”,事实也确实如此。但是只要产品不是特别大,不是特别 critical,我是第一种的坚定支持者,原因就在于使用第二种方式会大大降低效率,具体原因不细数,但是肯定是和大量的和无趣的 code merge 相关。当然,这两者的选择上总是充满争论,我最近经历的两个 team,前一个是号称要使用第二种,但是用着用着大多数人都不自觉地退回到第一种去;而现在这个 team 则是完全倒向第一种方式。

我记得 有这样一则漫画 ,说的是“ 为什么这些人总是很闲”:

cartoon

这种“ 闲” 是无奈的“ 闲”,程序员当然可以在 compile 等等各种等待时间做别的事,但是这意味着大脑中的工作线程需要反复切换,不但效率低下,而且还很容易疲劳。在一个产品刚刚开始的时候,东西相对简单,维护的成本就比较低,但是到几年以后就变得庞大无比。但是却很少见到团队把“keep it simple” 放到一个特别重要的位置。关于构建效率的问题,根据这些年的工作经验,我觉得这是一个很有价值的话题,能节约程序员大量的时间,重要性不比许多技术本身低,但是却很少有人讨论和感兴趣。事实上,我见到过很多团队,天天 configure and build,无奈地做着辛勤而无趣的 operation 的工作,这大概也是工业界做软件和学校里面搞科研的象牙塔不同的地方之一吧。

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》

3,067 次阅读

发表评论

电子邮件地址不会被公开。

back to top