Block,Inc.介绍了一次大规模的从polyrepo架构向monorepo迁移的实践,覆盖其 Cash App 与 Square 工程组,以应对后端系统日益增长的协调与依赖管理挑战。该计划将约 450 个基于 JVM 的仓库合并为单一的代码库,其目标是简化跨服务开发、提升依赖可见性并减少分布式系统的运行摩擦。
据 Block 工程团队称,该 monorepo 目前每周约支持 8800 次构建,在保持 main 分支稳定的前提下,p90 CI 时间约为 10 分钟。
在此前的 polyrepo 模型下,服务与共享库分布在独立仓库中,虽然团队可以独立工作,但随着时间推移,协调的复杂度不断增加。该模型导致依赖版本漂移、重复性的升级工作,以及跨 JVM 服务的运行时不兼容风险,包括典型的钻石依赖(diamond dependency)问题。
Block 的高级工程经理GaborPap曾经提到:
这最初是一次复杂的大规模迁移,但最终在开发者体验上带来了飞跃:一个现代且一致的代码库、优化的 IDE 工作流、显著更快的 CI,并为长期的敏捷性奠定了基础。影响远超工具本身。
在 polyrepo 模型中,依赖不匹配与跨仓库变动常常需要团队间协同部署。monorepo 允许在单次提交中完成跨服务的原子性更新,并优先直接从源码解析共享的依赖,而非依赖独立版本的内部库。
为了支撑这样的规模,Block 开发了一个定制的IntelliJ插件,支持按需加载工程师需要的项目,采用合并队列(merge queue)以在高提交量下保持 main 分支的稳定,并采用了共享 Gradle 插件、基于依赖图的构建范围缩减与 git 性能调优(包括探索 sparse checkout)以应对仓库的增长。
InfoQ 就此迁移采访了Yissachar Radcliffe。
InfoQ:是什么样的扩展或协调挑战使得 polyrepo 模型变得难以持续?在决定迁移到 monorepo 前你们评估了哪些替代方案?
Yissachar Radcliffe:polyrepo 下的依赖管理已经难以为继。我们不断面对破坏性的变更,有时它们会以运行时故障的形式出现。向下游消费者发布库或 API 变更常常需要巨大的努力。我们曾经评估通过增强对破坏性更改的保护来继续保留 polyrepo,但最终认为 monorepo 能更好地解决问题并总体上改善开发者体验。
InfoQ:你们如何构建并利用依赖图来高效地为 monorepo 实现范围化构建、测试与代码变更?
Yissachar Radcliffe:我们会查看 PR 中被修改的文件,并将其与项目依赖图比对,以确定需要构建的项目。整体而言,我们把变更分为三类:直接影响某个项目(例如,项目内部的文件变更)、间接影响某个项目(例如,上游依赖的变更)以及应触发整个 monorepo 构建的全局性变更(特定核心文件的变更)。这种分类能够确保我们会构建所有必要的内容以防止破坏性变更,同时允许针对每类变更调整要执行的构建。例如,对于间接变更,我们可以跳过不可能失败的某些 CI 检查。
InfoQ:定制的 IntelliJ 插件是开发者体验的关键。它如何决定在某个工作流中包含或排除哪些项目?工程师如何在需要时覆盖这些默认配置?
Yissachar Radcliffe:工程师能够指定他们正在处理的项目,插件会只将这些项目加载到 IntelliJ 中。在幕后,我们会动态地让依赖项目使用已发布的 JAR,以替换项目引用,从而保持 IDE 快速且可管理,避免缓慢的 Gradle 配置阶段。类似实现的开源项目可见于spotlight与artifact-swap。
InfoQ:随着 monorepo 扩展,你们如何在确保选择性构建、缓存与变更检测优化 CI/CD 的同时保持清晰的所有权与服务边界?
Yissachar Radcliffe:我们使用 Block 的仓库所有权工具为每个项目定义所有者(owner)。团队负责各自项目的代码,而 monorepo 团队负责通用的构建工具。我们还开发了一套强大的Gradle约定插件,定义常见的模块类型(比如,proto 模块、service 模块、library 模块等)。这些插件不仅有助于保持依赖图可控(例如,service 模块不能依赖另一个 service 模块),也便于我们将改进快速推送到所有项目。
InfoQ:迁移后,AI 辅助开发工具是否改变了工程师在代码库中的导航或工作方式?在这种规模下出现了哪些新挑战?
Yissachar Radcliffe:主要变化是 IDE 不再是唯一的焦点,许多工程师将 AI 辅助工具纳入了开发流程。由于 monorepo 能提供大量上下文,智能体的表现很好。我们对标准化的投入也得到了回报,因为我们为智能体设计了明确的路径。规模化挑战与迁移前大体相同(构建性能、git 可扩展性等),只是现在代码变更率更高。
InfoQ:回顾迁移过程,最困难或最出乎意料的挑战是什么?在什么情况下你会建议团队不要采用 monorepo?
YissacharRadcliffe:迁移耗时比预期更长,因为维持预期的开发者体验需要大量的精力。随着 monorepo 增长,我们不断发现新的 CI 可扩展性问题,这些问题需要在继续合并更多项目之前得到解决。此外,一些 polyrepo 项目构建非常慢或有高度定制的设置,导入前需要大量的优化。尽管这类项目在总数中占少数,却消耗了大量精力。
无论是 monorepo 还是 polyrepo,都需要平台团队的投入才能成功,但 monorepo 在缺乏维护时更容易崩溃。如果你无法承诺为 monorepo 提供足够资源支持平台团队,polyrepo 可能更适合,让团队各自改进自身的代码库,同时避免表现不佳的兄弟项目所造成的影响。monorepo 更适合形态相近的项目。如果你的项目混杂多语言、多框架与多风格,那么 monorepo 带来的收益可能不足以抵消投入的成本。
查看英文原文: Behind the Scenes: Block 450 JVM Repositories Into Monorepo to Reduce Dependency Drift





