写点什么

砍掉百万行代码,这些巨头玩不转超级应用了?

  • 2024-03-06
    北京
  • 本文字数:4194 字

    阅读完需:约 14 分钟

大小:1.97M时长:11:27
砍掉百万行代码,这些巨头玩不转超级应用了?

为谋求生存,Grab 将其应用软件“瘦身”四分之一;而为了提升研发效率,Shopify 一年删除了超 300 万行代码。

 

在马斯克一心要将推特变成微信那样的“超级应用”后,超级应用似乎成了大家追求的应用方向。但是,东南亚超级应用开发商 Grab 却在做相反的事:给自己“瘦身”。

 

“随着应用程序功能的不断扩展,存储空间或者网络带宽有限的新用户,越来越难以获得一致且高质量的体验。”Grab 博文里说道。

 

Grab 应用最初只是一款叫车软件,但在接下来的十年间逐渐将功能扩展到食品配送、包裹快递、移动支付等多个领域,甚至还针对司机端提供贷款服务。截至 2020 年 9 月,Grab 业务已经涵盖了东南亚 8 个国家,共 319 座城市。

 

但并不是每位用户都用得到这么多功能,而冗余代码又继续留存在应用当中,导致 Grab 软件代码如今已增长至 400 万行。

 

早在 2019 年,Grab 就发现了一个现实问题:其应用软件的大小几乎每个月增长 1%,导致已不太适合东南亚地区的普通智能手机,故而降低了用户体验并最终威胁到其吸引更多用户的业务发展愿景。

 

2021 年第三季度,这家总部位于新加坡的公司启动了“盆景项目(Bonsai project)”,希望控制应用软件的下载大小与存储空间占用。在六个月时间内,Grab 成功将性能提高了 26%,并在一定程度上削减了对存储空间的需求。

 

关注每次提交的应用大小

 

Grab 超级应用的布局发展是非常快的:2012 年 Grab 推出打车服务;2016 年 GrabPay 上线;2017 年 GrabPay 衍生到打车之外的支付领域,随后成立 Grab Financial,短短两年完成支付宝到蚂蚁金服十年的旅程。

 

打通支付体系后,Grab 开始为自己的超级应用引入更多服务。2018 年,Grab 还发布面向开发者的应用平台 GrabPlatform,也是达成东南亚唯一超级应用目标的基础。通过 GrabPlatform,合作伙伴可以将 Grab 集成到他们的服务中,也可以将他们的服务集成到 Grab 中。

 

但越来越多的业务板块,带来的挑战也是显而易见的。Grab 主 App 包含很多业务板块,这些业务之间互相独立、又相互依赖。相对其他业务,Grab 的“打车”主业务具有极高的稳定性要求,因为一旦系统出现故障会造成千上万人滞留,可能会演变为社会事件。

 

在盆景项目之前,Grab 一直采用应用捆绑方法,并根据特定设备提供定制化的 APK 安装文件。Grab App 拥有超过 100 名 Android 工程师和多个协作团队,每周发布一次,每次发布都会有数百次提交。因此,团队密切监控每次提交时应用程序大小的变化。

 


监控 APK 大小的变化

 

他们还会监控应用变更,对合并至主分支的每一项提交建立调试 build 进行 APK 文件大小控制,采用 R8/Proguard 作为“代码收缩器”。

 

在资源优化方面,Grab 团队也做了很多努力,包括尽可能使用矢量图像而非像素图像,在需要像素图像的特殊情况下,Grab 采用 webp 格式而不是 png,以便用更好的图像压缩来最小化应用大小。Grab 启用的资源配置仅支持 Grab 应用程序主动使用的语言,其在 resourceConfig 中删除所在地区不使用的语言,从而减少不必要的资源开销。另外,Grab 还为第三方库建立了审查流程,评估其规模对应用程序的影响。

 

但事实证明,这一切还不够。Grab 超级应用如今不仅有超过 400 万行代码,还与数百个第三方库集成,应用规模还是变得很大,以至于 Grab 目标市场区域中普遍存在的低端设备和互联网基础设施差异,不足以支撑这样规模应用的运行,进而阻碍了其业务发展。

 

Grab 还引用了谷歌在 2020 年的一项研究结果:应用程序大小对转化率有负面影响,应用程序 APK 大小每扩展 6MB,转化率就会下降 1%。因此,“瘦身”对于 Grab 来说势在必行。

 

400 万行代码怎么来的?

 

在盆景项目中,Grab 希望通过一切必要手段来量化、削减并控制其应用软件的大小。

 

Grab 首先开发了一款定制化工具,用以分析捆绑文件中的二进制文件。他们将这款工具命名为 App Size,并整合进工作流程当中。

 

该工具会将数据发送至 Grafana 实例,借此监控并观察特定设备所需下载的应用软件大小、识别哪些库和模块占用的存储空间最大,并创建出一份大文件清单。Grab 计划在不久的将来对该工具进行开源。

 

为了帮助应用软件有效瘦身,Grab 决定不再添加任何新内容,而是先找到导致软件体量膨胀的“罪魁祸首”。“我们的重点是优化 dex 文件大小、优化资源并消除重复与冗余部分。”Grab 方面解释道。

 

根据分析,Java/Kotlin 代码是这款应用软件的主要体量“贡献者”,因此成为优化工作的重中之重。在这部分代码中,R 类占据主要比例。博文指出,“R 类不仅包含对自身资源的 ID 引用,同时也涉及对所传递依赖项中资源的 ID 引用。”

 


“也就是说,如果模块 A 依赖于模块 B,而模块 B 又依赖于模块 C(模块 A -> 模块 B -> 模块 C),那么即使模块 A 不会直接用到这些资源,模块 A 的 R 类也将包含对模块 B 和 C 中资源的 ID 引用。也正因为如此,模块化项目中的 R 类才经常积累下数百万行代码。”

 

这家超级应用开发商还发现,其应用软件中包含超过 1500 个模块和第三方库,这进一步导致 R 类体量失控。也正因为如此,某些提交尽管没有添加大量资源、库或者代码,也仍然会显著提升应用的整体大小。

 

Grab 开发团队成员回忆道,“这些波动与依赖关系图的变化有关,也进一步凸显出 Transitive R 类的影响。”此外,根据默认规则,R 类还会被长期保留下来。

 

为了修复此问题,开发团队决定在自动化测试完成后更新 AGP 版本,在瘦身的同时避免无意中删除仍在使用的 R 类字段。这项测试的内容,是通过脚本来搜索使用 R 类反射的实例。各第三方库会进行反编译并应用同样的脚本。除此之外,Grab 还修改了 R8 配置规则以查找非必要冗余。

 

进一步控制膨胀

 

在发现大文件时,盆景项目鼓励开发团队在确定不必要时将其删除,包括考虑将其转移至云服务器,或者转化为更加经济的文件格式。

 

Grab 甚至在字体上也做了简化。现在这款超级应用删除了很少使用的字体、并清除了重复字体。Grab 软件目前正努力采用统一字体。Grab 在帖子中解释道,“我们建议采用单一主字体样式,并在编程中灵活融入不同的字体变化,从而立足同一字体实现多种显示效果。”

 

开发团队发现,某个特定库自己就占用了该应用存储空间的 8%。Grab 删除了该库,同时努力清理其他库中的重复函数。

 

Grab 应用还提供了一个附加功能,以开关形式远程禁用某项功能,这同样有助于削减软件体量。“这能帮助我们轻松关闭那些实验性功能,或者可能引发问题的特定功能。”博文作者指出。

 

Grab 还在不断探索更多应用瘦身途径,包括常见的 UI 设计组件及动态交付实验。Grab 还在考虑为各开发部门分配强制性的“应用大小配额”。

 

Grab 自豪地宣布,“通过优先考虑代码优化、资源管理、模块化与资产捆绑,我们在提高用户体验的同时,也实现了对应用软件体量的显著优化。”

 

但应用软件膨胀的问题恐怕很难快速得到遏制,特别是在东南亚地区,随着智能手机使用量的持续增长,消费者对产品价格的承受能力却没有同步提升。

 

应用到底“做小”还是“做大”?

 

做减法的不只 Grab。

 

Shopify 是一站式 SaaS 模式的电商服务平台,有百万家企业使用其平台创建了在线店铺。“对于商家来说,每一毫秒都至关重要。这意味着我们的应用在保证易扩展的同时,还不能被复杂的架构拖慢运行速度。”Shopify 副总裁、工程部门负责人 Farhan Thawar 说道。

 

因此在做重要更新时,Shopify 都致力于消除复杂性并提升性能。

 

2023 年,Shopify 删除了超 300 万行代码、归档了大约 6800 个未使用或者不必要的 GitHub 仓库、合并了 702 条由机器生成的用于清理僵尸代码的 PR,重要的是将一个用于在线购物网站的后台进程内存使用量从 3GB 左右减少到了 400MB 左右。

 

另外,Shopify 将后台开发人员的反馈机制提速了 20 倍,包括在计算机资源减少了 35% 的情况下,将持续集成的速度提高了 50%。团队还大幅改进了 Storefront Renderer 对 Ruby 垃圾回收机制的使用效率,使得平均 GC 时间减少 56%,GC 的 P99 时间减少了 80%。

 

所有措施也带来了不错的效果:8 万个列表的页面,加载时间从 20 秒左右缩短到 400 毫秒左右;跨境订单关税的计算速度。我们的 p99 从 500ms 左右下降到了 80ms 左右;管理后台搜索结果的响应速度提高了 7 倍以上等,此外 Shopify 的研发效率也提升了 20 倍。

 

但与 Grab、Shopify 相反,微信却在肉眼可见的变大。

 

上个月,微信因为安装包变大上了一次热搜。微信推送了 iOS 平台 8.0.47 正式版更新时,网友发现,软件更新信息显示,本次安装包的大小竟然达到 712.8MB。相较于之前的版本一下增加了几十 MB。当时有网友发文称,自己的微信占用内存达 50 多 GB,其中有 47GB 是聊天记录。可以看出,微信占的内存中,聊天记录占比高达 75%-95%。

 

而在 2022 年时,微信就因“安装包 11 年膨胀了 575 倍”登上热搜。当时有博主扒了微信安装包后发现,lib 文件夹大小为 337MB,占用了该微信版本空间的 54%,里面是 157 个各种第三方动态库。据 UP 主分析,这些库大多是因为“面向复制粘贴编程”:缺少什么功能就去网上找实现这种功能的“轮子”再缝合进 App 里,安装包体积会因为各种动态库的加入变得越臃肿。

 

对比初代微信,8.0.24 版本中各种单元都增加了 500 倍以上,尤其是 string 字符串,从最初的 1845 个到新版中暴涨近 150 万个。UP 主还调侃道:“可见新版微信中有 99.9% 的内容都是垃圾,真正实现聊天部分的代码可能只占 0.1%。”

 

还有一些细节表明了微信的开发非常混乱,如“收款到账”的音频放在 assets\sound 路径下,而同为音频文件的“微信电话铃声”却直接放在了 assets 路径下。

 

“微信把自己当操作系统来做 App,什么打车、快递、外卖、游戏,不管用不用得上都给你塞进去,然后淘宝、支付宝、美团等各种 App 又来占一遍你的手机空间,导致手机提升的性能和增加的内存都用来运行这些垃圾功能的代码,而用户丝毫没有选择权。”这名 UP 主最后总结道。

 

不过,微信里的应用对性能要求没有那么高,用户可以接受适当的等待。同时,微信依托腾讯背后的基础设施能力,可能一时间还不会想给自己做减法。

 

相关链接:

https://www.theregister.com/2024/03/05/grab_downsizes_app/

https://engineering.grab.com/project-bonsai

https://mp.weixin.qq.com/s/GjYOxoSUM2l37_1GjEueJg

https://www.bilibili.com/video/BV1cB4y1b77n?spm_id_from=333.337.search-card.all.click

https://www.infoq.cn/article/rwMNMXHvMg7TtAKu-UOh?utm_campaign=geek_search&utm_content=geek_search&utm_medium=geek_search&utm_source=geek_search&utm_term=geek_search

2024-03-06 14:1310295

评论 2 条评论

发布
用户头像
跟开发者团队的习惯也有关系,开发者都倾向于添加新代码,而不是删除旧代码,即便知道旧代码已经弃用了也不会删除
2024-03-09 16:52 · 北京
回复
用户头像
张"小而美"有恃无恐
2024-03-06 15:31 · 江苏
回复
没有更多了
发现更多内容

阿里的 RocketMQ 如何让双十一峰值之下 0 故障?

阿里巴巴云原生

容器 运维 云原生 k8s 消息中间件

Knative 基于流量的灰度发布和自动弹性实践

阿里巴巴云原生

Serverless 容器 开发者 云原生 k8s

翻译:《实用的Python编程》02_00_Overview

codists

Python

架构实战营模块1作业

半夏

学习 架构实战营

锁仓挖矿系统开发|锁仓挖矿APP软件开发

系统开发

跟单交易系统开发|跟单交易APP软件开发

系统开发

全网最全人工智能专业术语表(中英文对照)

澳鹏Appen

人工智能 大数据 数据 科技互联网 专业术语

Linux ln 命令

一个大红包

4月日更

数字货币期权交易系统开发|数字货币期权交易APP软件开发

系统开发

Fluid — 云原生环境下的高效“数据物流系统”

阿里巴巴云原生

人工智能 云计算 容器 云原生 存储

史上最全的Java面试题库宝典,Github上标星200k,太香了!

Java架构之路

Java 程序员 架构 面试 编程语言

给视频添加雪花飘落特效

老猿Python

OpenCV 音视频 图形图像处理 视频特效 引航计划

秒合约交易系统开发|秒合约交易APP软件开发

系统开发

apk优化,Android高级工程师必看系列,在线面试指南

欢喜学安卓

android 程序员 面试 移动开发

图解云原生应用设计模式

倪朋飞

Kubernetes 云原生

项目优化-代码拆分

Darren

android 组件化 代码优化

安全之路其修远兮,吾将上下而求索

Thrash

微信业务架构图

@oo?金樱子

音频应用类开源 Demo 大盘点

anyRTC开发者

ios android 音视频 WebRTC RTC

二十八分钟,带你用gitlab向企业微信发出灵魂拷问

📿

Java gitlab gitlab ci

查漏补缺!驱动核心源码详解和Binder超系统学习资源,挥泪整理面经

欢喜学安卓

android 程序员 面试 移动开发

七进七出,终获阿里32k*16offer,这就是我悲惨的面试经历~

Java架构师迁哥

金三银四旗开得胜!春招字节正式批4面,顺利拿到offer

Java 编程 程序员 架构 面试

北京天源迪科上线迪科商旅App

DT极客

阿里巴巴开源容器镜像加速技术

阿里巴巴云原生

Serverless 容器 云原生 k8s 存储

聪明人的训练(六)

Changing Lin

4月日更

双非本化学跨专业,投岗阿里/滴滴后端三面,最终拿下offer

Java 编程 程序员 架构 面试

Flink集成Iceberg在同程艺龙的实践

Apache Flink

flink

架构实战营课程1作业

求索

学习 架构实战营

架构实战营模块一作业

冷大大

作业 架构实战营 模块一

模块一课后作业

追随哆咪

架构实战营

砍掉百万行代码,这些巨头玩不转超级应用了?_架构_褚杏娟_InfoQ精选文章