为谋求生存,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
评论 2 条评论