在一个由50多位开发者、10个特性小队协作的Android项目里,工程模块已经拆到了30个。所有模块之间都用api依赖粘合在一起,原以为拆分越细构建越快,可每次增量编译依然稳稳超过3分钟。Google一位资深软件工程师在最近的分析中一语道破:问题根本不在模块数量,而在字节码ABI被暴露到了什么程度。
要理解这种多模块构建的“经济学”,首先得分清Gradle所管理的两张类路径——编译类路径和运行时类路径。编译类路径上发生的任何变更,都会触发当前模块的重新编译;而运行时类路径上的变动,只会影响最终的打包环节,不会在中途让大量模块一起重跑。
![]()
原文中用一张依赖图清晰刻画出两种边界::feature:checkout‑impl 仅仅通过implementation依赖编译期的 :feature:profile‑api,完全没有编译期的可见性去触碰 :feature:profile‑impl。最后由根模块:app负责把各个实现模块缝合到运行图中。这就相当于在编译期筑起了一道墙,当修改profile‑impl的内部逻辑时,checkout‑impl根本无需重编译——只有到最后链接阶段才会再次把它们揉到一起。
反过来,如果整个工程用api把所有模块串成一张大网,情况就截然不同了。当一个开发者改动模块M的源码,Gradle会找出所有通过编译类路径传递依赖M的下游模块。此时增量编译的总耗时可近似为:T(M) + 所有下游模块重新编译的时间之和。只要一个底层的公共模块被修改,这张api依赖网就会把几十个特性模块全部拖下水,增量构建直接被拖回三分钟起步的恶性循环。
因此,大型团队的模块化设计实质上就是在管理两件事:一是把公共接口收敛进轻量的api模块,二是在实现模块之间坚持使用implementation依赖。这样,每一次代码提交所带来的影响范围都会被锁死在最小集合里。模块越多,反而因为隔离做得更好,重编译的扇出更小。所谓的“模块越多构建越慢”,只有在api暴露失控时才会成立。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.