Skip to content

四火的唠叨

一个纯正程序员的啰嗦

Menu
  • 所有文章
  • About Me
  • 关于四火
  • 旅行映像
  • 独立游戏
  • 资源链接
Menu

从构建和测试的效率说起

Posted on 09/28/201506/23/2019 by 四火

最近的工作总是在 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 的工作,这大概也是工业界做软件和学校里面搞科研的象牙塔不同的地方之一吧。

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

×Scan to share with WeChat

你可能也喜欢看:

  1. Notes: Spark metrics
  2. 程序员漫画
  3. 工作流系统的设计
  4. Spark 性能优化——和 shuffle 搏斗
  5. 谈谈 Ops(汇总 + 最终篇):工具和实践

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

订阅·联系

四火,啰嗦的程序员一枚,现居西雅图

Amazon Google Groovy Hadoop Haskell Java JavaScript LeetCode Oracle Spark 互联网 亚马逊 前端 华为 历史 同步 团队 图解笔记 基础设施 工作 工作流 工具 工程师 应用系统 异步 微博 思考 技术 数据库 曼联 测试 生活 眼界 程序员 管理 系统设计 缓存 编程范型 美股 英语 西雅图 设计 问题 面向对象 面试

分类

  • Algorithm and Data Structure (30)
  • Concurrency and Asynchronization (6)
  • System Architecture and Design (43)
  • Distributed System (18)
  • Tools Frameworks and Libs (13)
  • Storage and Data Access (8)
  • Front-end Development (33)
  • Programming Languages and Paradigms (55)
  • Testing and Quality Assurance (4)
  • Network and Communication (6)
  • Authentication and Authorization (6)
  • Automation and Operation Excellence (13)
  • Machine Learning and Artificial Intelligence (6)
  • Product Design (7)
  • Hiring and Interviews (14)
  • Project and Team Management (14)
  • Engineering Culture (17)
  • Critical Thinking (25)
  • Career Growth (57)
  • Life Experience and Thoughts (45)

推荐文章

  • 谈谈分布式锁
  • 常见分布式系统设计图解(汇总)
  • 系统设计中的快速估算技巧
  • 从链表存在环的问题说起
  • 技术面试中,什么样的问题才是好问题?
  • 从物理时钟到逻辑时钟
  • 近期面试观摩的一些思考
  • RSA 背后的算法
  • 谈谈 Ops(汇总 + 最终篇):工具和实践
  • 不要让业务牵着鼻子走
  • 倔强的程序员
  • 谈谈微信的信息流
  • 评审的艺术——谈谈现实中的代码评审
  • Blog 安全问题小记
  • 求第 K 个数的问题
  • 一些前端框架的比较(下)——Ember.js 和 React
  • 一些前端框架的比较(上)——GWT、AngularJS 和 Backbone.js
  • 工作流系统的设计
  • Spark 的性能调优
  • “残酷” 的事实
  • 七年工作,几个故事
  • 从 Java 和 JavaScript 来学习 Haskell 和 Groovy(汇总)
  • 一道随机数题目的求解
  • 层次
  • Dynamo 的实现技术和去中心化
  • 也谈谈全栈工程师
  • 多重继承的演变
  • 编程范型:工具的选择
  • GWT 初体验
  • java.util.concurrent 并发包诸类概览
  • 从 DCL 的对象安全发布谈起
  • 不同团队的困惑
  • 不适合 Hadoop 解决的问题
  • 留心那些潜在的系统设计问题
  • 再谈大楼扔鸡蛋的问题
  • 几种华丽无比的开发方式
  • 我眼中的工程师文化
  • 观点的碰撞
  • 谈谈盗版软件问题
  • 对几个软件开发传统观点的质疑和反驳
  • MVC 框架的映射和解耦
  • 编程的未来
  • DAO 的演进
  • 致那些自嘲码农的苦逼程序员
  • Java 多线程发展简史
  • 珍爱生命,远离微博
  • 网站性能优化的三重境界
  • OSCache 框架源码解析
  • “ 你不适合做程序员”
  • 画圆画方的故事

近期评论

  • panshenlian.com on 初涉 ML Workflow 系统:Kubeflow Pipelines、Flyte 和 Metaflow
  • panzhixiang on 关于近期求职的近况和思考
  • Anonymous on 闲聊投资:亲自体验和护城河
  • 四火 on 关于近期求职的近况和思考
  • YC on 关于近期求职的近况和思考
  • mafulong on 常见分布式基础设施系统设计图解(四):分布式工作流系统
  • 四火 on 常见分布式基础设施系统设计图解(八):分布式键值存储系统
  • Anonymous on 我裸辞了
  • https://umlcn.com on 资源链接
  • Anonymous on 我裸辞了
© 2025 四火的唠叨 | Powered by Minimalist Blog WordPress Theme
Menu
  • 所有文章
  • About Me
  • 关于四火
  • 旅行映像
  • 独立游戏
  • 资源链接