5000 万行以上大型代码仓库工程实践

2024-03-23 20:18

本文主要是介绍5000 万行以上大型代码仓库工程实践,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者:marinewu,腾讯 PCG 工程效能平台部专家

腾讯 PCG 工程效能平台部自 2020 年开始进行大仓基本能力建设,并在 2021 年与工蜂合作成立了代码大仓研效联合项目组。在此, 我们想分享大仓/单仓踩过的坑。我们认为这些坑是真实存在且很难避免的,不是小马过河。

单仓并不简单。成功的单仓所带来的效果绝不止简单的代码聚合,但成本是大量的工具支持以及工程实践。单仓像放大镜,可以将优秀的工程实践以极低的成本推广,但同时也会将错误迅速放大。同时,向单仓迁移的过程也有相当程度的风险。本文会详细讨论单仓的益处、挑战,以及我们对挑战的应对之道,以供参考。

单仓/大仓是什么?

  • 单仓:指Monorepo,或单一仓库,是指将多个项目放在同个仓库中的版本控制策略。单仓在实践中可能有不同规模,如中心级、部门级、BG 级、公司级单仓。业界最著名的单仓是Google 的 google3,除一些开源项目,Google 内其它所有代码都放置于其中,有超过 20 亿行代码和超过 86T 的容量。目前公司内部成功应用的单仓大多在部门级及以下。

  • 大仓:指大型规模的仓库。“大型规模”并没有严格的定义 -- 在本文中,我们将大仓定义为“单机已无法承受其容量的仓库”。一个粗略的估计:大于五千万行代码 或 容量超过 100G 的仓库即为普遍认可的大仓。

单仓是我们的目的,而大仓则是(终极)单仓的必然结果。

为什么要发明单仓?

单仓的设计核心起源于"One Version"的哲学,并内化了规模化的思想。

Scalability 可规模化

在软件工程中,我们希望“解决一次,解决全部”。即,任何的一个良好的工程实践,都以自动化、规模化的手段几乎零成本地推广到所有的团队及代码。这样可以减轻开发人员的心智负担,使之将更多的精力放在创造性的工作上。典型的例子包括代码静态检查、自动化测试及持续集成、开发流程标准化、工具统一化等等。

单仓极大地简化了规模化:当所有代码都放置在一处,并且高度统一,则所有的工具都可以规模化地在单仓上作业。

Single Source of Truth ->One Version 从单可信源到单一版本

Single source of truth(SSoT)原则,是指开发人员在任意时间可以确定代码仓库内的哪个分支是唯一可信依赖源(SSoT)。在 CVS 中,单一来源是核心原则;在 DVS 中,如 git,在现代的业界实践中也采取了该原则,即要求永远都只有一条主干,且所有的分支(除了发布分支)最终都会被收拢回主干里。

单一版本(One Version)则更进一步,是指在任意时间,代码库内的每一份组件、每一个依赖只有一个版本。

  • 对内部库而言,这意味着使用主干开发(见下),并且必须在主干 HEAD 上依赖。这是一个非常强的约束——这意味着除了终端制品,任何一个内部被依赖的库都不能通过分支发布,而必须保持自己在单仓的主干上一直是发布状态。

  • 对外部依赖而言,同一个第三方库在单仓中永远只会引入一个版本。

不强制 SSoT/One Version 的版本控制策略往往通过制品/版本分支发布。这意味着在整个依赖关系图之上还有一个版本的维度。这也是在开源社区/SDK 发布商通常采用的策略,其根本原因在于并非完全掌握下游用户的情况。这样除了导致较高的维护成本,还会导致依赖关系难以满足(Dependency hell, 依赖地狱)。

主干开发 Trunk-based development

基于版本控制的协作模式一般分两种:

  • 分支开发:每个分支对应一个功能,开发者在这个分支上开发,直到最后完成功能后合并回主干。这是现在小仓下的主流模式。

  • 主干开发:每个分支只对应一个简单的修改。每个开发者在分支上完成修改后经过 CR 尽快合入主干。这是在单仓下推荐的开发模式。

两者的主要区别在于分支存活时间:保持主干始终健康,将所有的 commits 尽快小批量合入的是主干开发;以 feature 为单位,当 feature 完成之后再重新合入的是分支开发。

虽然听上去差异微小,但从分支开发迁移到主干开发对研发模式的影响深远。请务必确保您的团队深入理解前置需求(挑战)和长期影响(益处)。下文将分别阐述。

Case: API Deprecation

考虑以下常见场景:一个公共库的作者如何 deprecate 旧的 API 并提供新的 API 作为替代品?

小仓场景:这个公共库按版本分支或按制品发布。API 可以在下一个版本直接更新,并强制 API 调用方对 API 进行更新。这样的好处是 API 提供方的责任较简单,坏处是每一个 API 调用方都需要自行更新代码,并且 API 提供方无法保证自己的新版 API 已经被使用。

单仓/主干场景:公共库只提供源码依赖,并不按版本发布。这样,我们需要保证公共库在主干上始终是正确的。API deprecation 时,API 提供方可以查找所有 API 调用方,并且发动大规模自动修改,原子性地将所有的旧 API 调用更新至新的 API。这样的好处是 API 调用方的责任更简单,但是这种修改只有在能够查找 API 的所有用户、并且整个持续集成水平较高时才有可能。

从上面的例子可见,在单仓/主干的场景下,很多代码的维护工作可以左移并规模化。减少重复劳动、大规模的工业化,是我们启用单仓的原动力。

益处

以下的益处基于开发者视角和代码维护者视角。

再次提醒, 单仓想要达成预期效果需要工具、流程和文化三方面的准备,以及长期大量持续维护。贸然迁移到大仓不但不会带来收益,反而会导致项目和代码管理彻底混乱。请确保您对挑战部分有所准备。

主干开发

主干开发是为了进行持续集成。频繁地、小批量地构建/测试是持续集成的关键。通过主干开发可以:

  • 避免较长的稳定期,使持续集成可以持续运行,均摊每次合入的风险

这篇关于5000 万行以上大型代码仓库工程实践的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/839411

相关文章

SpringCloud集成AlloyDB的示例代码

《SpringCloud集成AlloyDB的示例代码》AlloyDB是GoogleCloud提供的一种高度可扩展、强性能的关系型数据库服务,它兼容PostgreSQL,并提供了更快的查询性能... 目录1.AlloyDBjavascript是什么?AlloyDB 的工作原理2.搭建测试环境3.代码工程1.

Java调用Python代码的几种方法小结

《Java调用Python代码的几种方法小结》Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Pyt... 目录引言Java core使用ProcessBuilder使用Java脚本引擎总结引言python

Java中ArrayList的8种浅拷贝方式示例代码

《Java中ArrayList的8种浅拷贝方式示例代码》:本文主要介绍Java中ArrayList的8种浅拷贝方式的相关资料,讲解了Java中ArrayList的浅拷贝概念,并详细分享了八种实现浅... 目录引言什么是浅拷贝?ArrayList 浅拷贝的重要性方法一:使用构造函数方法二:使用 addAll(

JAVA利用顺序表实现“杨辉三角”的思路及代码示例

《JAVA利用顺序表实现“杨辉三角”的思路及代码示例》杨辉三角形是中国古代数学的杰出研究成果之一,是我国北宋数学家贾宪于1050年首先发现并使用的,:本文主要介绍JAVA利用顺序表实现杨辉三角的思... 目录一:“杨辉三角”题目链接二:题解代码:三:题解思路:总结一:“杨辉三角”题目链接题目链接:点击这里

SpringBoot使用注解集成Redis缓存的示例代码

《SpringBoot使用注解集成Redis缓存的示例代码》:本文主要介绍在SpringBoot中使用注解集成Redis缓存的步骤,包括添加依赖、创建相关配置类、需要缓存数据的类(Tes... 目录一、创建 Caching 配置类二、创建需要缓存数据的类三、测试方法Spring Boot 熟悉后,集成一个外

Docker集成CI/CD的项目实践

《Docker集成CI/CD的项目实践》本文主要介绍了Docker集成CI/CD的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录一、引言1.1 什么是 CI/CD?1.2 docker 在 CI/CD 中的作用二、Docke

轻松掌握python的dataclass让你的代码更简洁优雅

《轻松掌握python的dataclass让你的代码更简洁优雅》本文总结了几个我在使用Python的dataclass时常用的技巧,dataclass装饰器可以帮助我们简化数据类的定义过程,包括设置默... 目录1. 传统的类定义方式2. dataclass装饰器定义类2.1. 默认值2.2. 隐藏敏感信息

opencv实现像素统计的示例代码

《opencv实现像素统计的示例代码》本文介绍了OpenCV中统计图像像素信息的常用方法和函数,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 统计像素值的基本信息2. 统计像素值的直方图3. 统计像素值的总和4. 统计非零像素的数量

IDEA常用插件之代码扫描SonarLint详解

《IDEA常用插件之代码扫描SonarLint详解》SonarLint是一款用于代码扫描的插件,可以帮助查找隐藏的bug,下载并安装插件后,右键点击项目并选择“Analyze”、“Analyzewit... 目录SonajavascriptrLint 查找隐藏的bug下载安装插件扫描代码查看结果总结Sona

Python开发围棋游戏的实例代码(实现全部功能)

《Python开发围棋游戏的实例代码(实现全部功能)》围棋是一种古老而复杂的策略棋类游戏,起源于中国,已有超过2500年的历史,本文介绍了如何用Python开发一个简单的围棋游戏,实例代码涵盖了游戏的... 目录1. 围棋游戏概述1.1 游戏规则1.2 游戏设计思路2. 环境准备3. 创建棋盘3.1 棋盘类