写点什么

知乎 Android 客户端 CI/CD 方面的努力

  • 2020-03-26
  • 本文字数:3378 字

    阅读完需:约 11 分钟

知乎 Android 客户端 CI/CD 方面的努力

前言

伴随着知乎业务的飞速发展,近一年多时间,知乎的 Android 团队由十多人的小团队发展至五十多人的大团队,并且还在不断的壮大中。


虽然我们常常说人多力量大,但是有时候人多也未必是件好事,譬如经典计算机软件著作「人月神话」中就提到在某些情况下 1 + 1 也是有可能小于 2 的。(杜撰的,如有雷同…)


为了让 1+1 大于 2,移动平台团队做了一些工作,不断提升工程师的研发效率,降低各个团队相互干扰,减少重复无用功,支撑业务稳定前行。


下面就就其中 CI/CD 方向跟大家说一下。

组件化方面做的努力

Android 组件化方案 已经运转了近一年半的时间,令人欣喜的是其已经达到了我们当初的预期。即:不同 Android 团队之间,可以通过组件仓库制造代码壁垒,分而治之;


同时其来带的效果也是显著的,即:无论是研发效率还是编译速度都有了不少提升。


但是祸福相依,有得必有失。组件化也不例外,譬如:


  1. 先前代码全在一个仓库,组件化之后,代码跨了多个仓库,代码提交的 CodeReview 很不方便

  2. 一般修改某个组件的流程是去组件仓库提交代码,合入代码后,发布新的组件包,最后在主工程中使用这个新版组件包,打出测试包。也就是代码测试发生在组件代码在合入后

  3. 先前单个仓库的时候,主仓库有轮流的 merge 工程师,定期把 release 的代码 merge 到 develop 上面,多个组件后,仓库数量膨胀,如何不依赖组件管理人的细心程度,确保每个仓库的 release 代码能够合入到 develop 之中,也是一个问题。

跨组件的 CodeReview

知乎 Android 端的组件化,是使用如下的文件控制的:


// versions.gradlecomponent.answer.version = '1.2.3'
复制代码


主工程读取这些 version 信息,然后再依赖这些组件, 使用类似于这样的语句:


 compile com.zhihu.android:answer:${answer.version}
复制代码


一般而言,我们比如升级了某一个组件,在主工程上面看到的改动就只有类似于这样:


// versions.gradle+ component.answer.version = '1.2.5'- component.answer.version = '1.2.3'
复制代码


至于中间带来什么东西,只能靠工程师自己去翻仓库了,这个很不合理的。


其实由于每个版本都有一个 tag 对应,接着 gitlab 上面已经提供了一个方便浏览的页面


https://git.repo.guest.where.zhihu.com/Android/Ad/compare/<from-commit>...<to-commit> 
复制代码


我们直接输出出来即可。效果如下:



过去没有 tag 的时候,真的是一个个 commit 去搜,现在的孩子真幸福 =v=

联合打包

我们需要一个能够在多个组件提交代码之时,就能打出相应的测试包。


gradle 可以通过下面方法源码依赖某一个工程include 'moduleA'project('moduleA').rootDir = '/path/of/module/A'  gradle 版本依赖某一个工程dependencies { implementation 'com.well.zhihu:moduleJoinUs:2.3.3'}
复制代码


我们这里是使用一个配置文件,配置需要源码依赖或版本依赖的组件。


如下图:



可以看到这次打包是联合了 ModuleA 以及 ModuleB 组件提交的代码打包。


这里面有个细节,我们在每次开始编译的时候加了「begin to build」以及 job 版本号(图中的 3537),是为了跟最后生成的包的 job 版本号匹配的。


为了让测试的同学知道,这个包是在哪个代码状态下打出来的(打包所获取的组件代码是当前 MergeRequest 提交的代码,担心在打包的过程中,又提交新的代码,这样生成的包就不是当前代码状态的了,让测试同学误解)

分支合并的问题

世界上最冤的 bug 不是字符串的值为 “null”,而是我已经在 release 上修了,但是代码没有合入到 develop。如下图:



bug 是不存在的



纸还是包不住火 =_=


如果是 bug 不严重的话,可能就只是浪费测试以及开发资源。但是遇上什么 downtime,紧急修复,忘记合入,则会是新的 downtime,又一次紧急修复。而人总有可能犯错。


知乎这边的做法是定期自动提这样的 merge-request: 「次最新 release => 最新 release」以及「最新 release => develop」(也就是上文的 release-1.2 => release-1.3 release-1.3 => develop )我们会在需要合并的时候定期提醒工程师合并代码,尽量减少工程师的工作。

其他

还有一些细枝末节的,譬如:


有些业务组件的发布流程与主工程同步,在主工程拉分支的时候,也会拉出一个对应的 release 分支,一般自动拉分支的组件都会有自动合并分支的功能。


创建 lint 服务,组件工程只要配置一下,提交代码的时候,都会跑一次 lint,报告贴在 merge request 中,作为 CodeReview 的材料。

包大小监控

业务增长很快带来的另一个问题,是包大小也增长地很快。


包大小减少之前组内 Java script 工程师


@Peter Porker 做过一次,效果显著,但是无奈,包内增大席卷重来,所以除了直接减少包大小,一套可以无需人为地遏制包大小的增长,或者监控包大小的增长情况的方案,尤为重要。


我们这里做了两件事,一个是使用 gradle + githook 的方式,限制某些不规范的提交(譬如过大的资源文件等),二,实时监控代码提交的时候带来的包增长,生成易读的报告。

限制不规范的提交

不规范的提交包括:资源过大,提交的资源是 png 而不是优化过的 webp,一些低像素的资源也提交过去(-hdpi,-mdpi 现今的设备基本上不会用到这些资源)


githooks 中,可以往 commit-msg 中写一些脚本,检查当前提交的文件内,是否出现上述问题(可以用下列方式获取到当前提交文件: git diff --cached–name-only --diff-filter=d``)。


这里有一个问题,git hooks 一般不跟版本走,也就是说很难提交到仓库,然后让别人 down 下来,去覆盖本地的 hooks 文件。想要做到这一点,这就需要外界脚本的帮助。


知乎这边 Android 的开发流程很依赖 gradle,我们的做法是 先把 hooks 里面的所有文件存放在某个仓库里面,然后在 gradle 中植入这些代码:download 这些 hooks 文件,然后覆盖复制到本地的 .git/hooks/ 下。篇幅的问题,代码就不贴了 = =)download 的方法,我是用 git archive 。


最后把这些逻辑写入到 gradle plugin 中。由于所有组件工程都会依赖这个 plugin,这样所有组件工程都会装上 hook,所有的代码的提交都会被你限制到(我给他取名 Ozymandias =v=


安装 git hooks 的效果图:(其实 文字都是自己打印出来的,所以 「效果图」谈不上 = =)



美术有点差,见谅 - -


commit-msg 代码检查:



欲擒故纵 =v=

实时监控代码提交,生成相应报告

实际上,这些是不能 cover 住很多情况的,而且有些加入的资源,最后不一定会加入到 apk 包中(譬如 proguard 掉的部分)检查包增长,打个包出来,自然就知道了。


我们这边做的是:


  1. 每次合并代码之后,记录一下最新包的包大小以及包内信息,譬如 develop.detail release-1.2.3.detail

  2. 每次提 merge-request 往 develop/release 合的时候,打一个「假设已经」合入之后的包,获取它的包大小以及包内信息,跟历史纪录对比一下,即可以知道这次改动带来的变化


实现的效果如下:



确实细粒度到类或者包,可能会更好


包内信息我是 unzip 之后,逐一用 du 生成大小以及文件名的信息,交给 python 脚本进行比对的。大致的代码是:(由于文件过多,取最大的前 100 个)


// 统计包大小信息TOTAL_SIZE=`stat -c %s ${package}`SIZE_IN_MB=`echo "scale=2;${TOTAL_SIZE} / 1024 / 1024" | bc`    // 统计包内文件信息unzip "$package" -d "build/apk"find build/apk -type f | xargs du -k | sort -n | tail -n 100 \ | tee "$file_info"// 生成的包内信息如下:28  build/apk/res/raw/how.mp332  build/apk/res/drawable-night-xxhdpi-v8/are.webp32  build/apk/res/drawable-xxhdpi-v4/you.webp
复制代码


至于对比,只要写个 python 脚本读取该文件,以 name 为 key 的字典即可。

特殊团体的监控

移动平台团队维护的代码,由于调用方过多,稍有不慎,就出问题。所谓不受监督的权力容易滋生问题,所以平台组的成员需要出一套机制监督平台组的运转 ╮(╯_╰)╭


目前的是:


平台组内的 CodeReview 由另一个平台组成员 + 其他团队人员组成。CodeReviewer 是随机指派的,当然为了 CodeReview 效果更好(总不能把做想法的工程师 review 首页的代码 领域不同 CodeReview 效果可能不大好 (


  1. @李明亮等100万人: 诶 会有问题吗) ( = =)泥奏凯)这边就是通过看这次改动里面的文件的修改记录(git log), 查到最新的经办人是谁,交给他。

  2. 平台组的代码提交 MergeRequest Open - Merged - Close 事件都会通知到群里面的人

  3. 定期每一个迭代都会生成「在这个迭代内平台组的所有提交」的报告,供业务方查看。


就酱. Thanks for reading.


2020-03-26 19:001317

评论

发布
暂无评论
发现更多内容

数据驱动与并行策略:用 JUnit 5 让软件测试更高效

测试人

软件测试

第三代指标平台相较于前两代的显著优势分析

Aloudata

指标管理 指标平台 指标开发

CSA GCR 2024 | 百度安全DDoS防护服务荣获安全磐石奖等多项殊荣

百度安全

如何使用 NocoBase 构建应用程序?

NocoBase

开源 零代码 无代码 应用程序 宠物追踪

揭秘1688商品详情关键字搜索API接口:精准定位,高效营销

代码忍者

API 接口 pinduoduo API

淘宝商品描述优化与拍立淘API接口探索:开启智能购物新时代

代码忍者

API 接口 pinduoduo API

支付能力用小程序实现并非最佳技术方案

FinFish

小程序容器 超级app 小程序技术 app支付能力

天润融通携手挚达科技:AI技术重塑客户服务体验

天润融通

天润融通解决方案:如何避免门店投诉升级为消费者维权

天润融通

探索OS升级迭代的兼容性和安全性!龙蜥社区走进中科方德MeetUp开始报名

OpenAnolis小助手

操作系统 龙蜥社区 龙蜥meetup

【JIT/极态云】技术文档--组织架构简介

武汉万云网络科技有限公司

低代码

Redis大Key问题如何排查?如何解决?

王磊

存算分离的过去、现在和未来

Databend

软件测试丨全面解析 Allure 2 的安装与运用

测试人

软件测试

万字长文带你深入Redis底层数据结构

不在线第一只蜗牛

数据库 redis

开放原子校源行(天津大学站) 即将启幕,龙蜥技术专家分享开源技术与实践

OpenAnolis小助手

操作系统 龙蜥社区

舍得酒业×奇点云|最佳大数据平台供应商

奇点云

大数据

全域数据整合下的数据治理:提升数据开发管理效率与质量的策略

Aloudata

数据仓库 数据分析 数据开发 数据集成 数据编织

洞悉数据,守护安全!和鲸助力2024年浙江省交通投资集团数字化主题活动圆满闭幕

ModelWhale

人工智能 交通 数据竞赛

构建真实可靠指标平台:五大核心特征助力企业深度数智化

Aloudata

指标管理 指标平台 指标开发

如何绘制产品架构图?盘点9个产品架构图模板!

职场工具箱

在线白板 架构图 办公软件 绘图软件 产品架构图

探索1688拍立淘API接口:图像搜索技术引领电商新潮流

代码忍者

API 接口 pinduoduo API

终于能随时解决信息焦虑了

最新动态

倒计时1天!龙蜥社区开源软件供应链及操作系统安全MeetUp即将在广州召开

OpenAnolis小助手

操作系统 龙蜥社区 龙蜥meetup

如何选择合适的数据集成工具或平台来实现全域数据的高效整合

Aloudata

数据仓库 数据分析 数据开发 数据集成 数据编织

软件测试丨JUnit5动态测试与生命周期解析

测试人

软件测试

Python脚本消费多个Kafka topic

不在线第一只蜗牛

Python kafka

中小企业如何优化业务流程和充分利用ERP系统?

积木链小链

企业管理 数字化 ERP 中小企业

快递员上门取件API接口接口Domo下载

快递鸟

快递

知乎 Android 客户端 CI/CD 方面的努力_文化 & 方法_郑小则_InfoQ精选文章