Monorepo:Bazel和Cocoapods混和使用

背景

移动端开发现状

在组件化的浪潮下,公司引入多仓开发对工程架构进行解耦、跨业务技术能力复用,并辅以组件(混合)二进制化进行编译提速。不过随着工程规模增长、业务复杂度提升,多仓二进制的弊端日益凸显:

  1. 合码效率低下:多仓的引入使开发流程变复杂,最有代表性的合码环节一次合码涉及到主仓和多个组件,每个组件要跑 Pipeline 流程进行版本发布。这种模式提升了 CI 复杂度,降低了合码效率。
  2. 依赖管理衍生问题:稳定性差,多仓使环境依赖度变高,稳定性变成多个仓库稳定性的乘积。需要手动识别依赖层级,先发版被依赖的库,多版本并行开发时,经常发版失败需要写死依赖版本。
  3. 代码的可视性和可控性降低:跨组件重构困难,全量静态检测无从入手,并且很难统一架构规范;本地开发体验差,工程代码可信度低,无法直接对代码进行开发调试,本地开发需要更多的工具和流程来保证代码的可视性和可控性。
    诚然,多仓方案很好的落实了组件化思想,但为解决上述多仓体系的问题,公司衍生了大量的优化和效率工具,其从结果看仅聚焦于解决局部问题,难以进一步提升优化空间。
目前头条、抖音、B站、谷歌等公司采用了Monorepo的方案解决上述问题。

● 代码复用:Monorepo 可以让不同的项目或模块共享代码和依赖项,避免重复编写和维护相同的代码。
● 依赖管理:Monorepo 可以让不同的项目或模块共享依赖项,避免依赖冲突和版本管理问题。
● 统一构建:使用 Bazel 可以统一管理 Monorepo 中的构建规则和依赖项,提高构建效率和可靠性。
● 版本控制:Monorepo 可以让不同的项目或模块共享版本控制系统,简化版本管理和发布流程。

Monorepo 全源码概念和优缺点

Monorepo(Mono Repository)指的是将多个相关项目或模块的代码集中管理于一个仓库的软件开发模式。具体来说,Monorepo 将所有的源代码和配置文件等存储在一个版本控制仓库中,并使用相同的构建和部署系统来管理和交付代码。
全源码(Full Source)是指将整个软件系统的源代码均存放于一个仓库中,源码为单一可信源。
全源码的概念通常与 Monorepo 联系在一起,将概念定义为 Monorepo 全源码解决方案,是区分于当前流行的组件二进制化开发模式。下图中 MULTI-REPO 为前多仓开发模式,每个组件独立 git 存储;MONO-REPO 为单仓模式,组件同主仓合并,只保留一个 git。


image.png
优点:

● 便于代码复用:所有项目代码集中于单一仓库,相似的功能更便捷地抽象为公共库,并直接由项目引用。提高代码的可维护性和开发效率。
● 简化依赖管理:无需依赖管理器,所有引用的依赖项都存在于同一代码库中,更加方便地进行构建和管理。
● 原子提交:可以原子性地更改多个项目以避免多仓下不同版本依赖同步的兼容性问题。
● 大规模代码重构:开发人员可访问整个项目,从而更加容易地进行代码重构,并确保每个部分都能正常工作。
● 跨团队协作:通过源代码依赖改进其他团队正在开发的项目,从而实现代码所有权的灵活性。
● 工程质量提升:Monorepo 倡导开放,透明,共享的组织文化,有利于开发者成长,代码质量的提升。

缺点

● 版本信息丢失:Monorepo 使用相同的版本号,无法对每个项目进行单独的版本控制。(多端同仓)
● 缺乏权限控制:无法根据需要授予对代码库的访问权限,所有代码都在同一个项目中可能存在安全问题。
● 磁盘空间占用:默认情况下需检出所有项目,需要更多的存储空间。

为何选择Bazel

参考Bazel中文网站

Bazel 是一种快速正确可扩展的构建工具,具有集成测试功能,可在行业领先的生态系统中支持多种语言代码库平台

Bazel 速度快

Bazel 可以确切知道每个构建命令需要哪些输入文件,从而仅在一组输入文件在每次构建之间发生更改时重新运行,从而避免不必要的工作。 它会在同一计算机或远程构建节点上以尽可能高的并行性运行构建命令。如果构建结构允许,它可以同时运行数千个构建或测试命令。

这受到内存、磁盘和远程构建农场(如果有)的多个缓存层支持。在 Google,我们通常会将缓存命中率达到 99% 以上。

Bazel 正确

Bazel 可确保您的二进制文件仅基于您自己的源代码构建。Bazel 操作在单独的沙盒中运行,Bazel 会跟踪构建的每个输入文件,并且只会在需要时重新运行构建命令。这样可以使您的二进制文件保持最新状态,以便相同的源代码始终生成相同的二进制文件

对无休止的 make clean 调用,以及追寻实际上在从未被构建的源代码中解决的幽灵 bug 的说辞。

Bazel 具有可扩展性

自行编写规则和宏,针对各种项目的特定需求自定义 Bazel,从而充分发挥 Bazel 的功能。

Bazel 规则是使用 Starlark 编写的,Starlark 是我们的内部编程语言,是 Python 的子集。Starlark 让大多数开发者能够使用规则编写功能,同时还能创建可在整个生态系统中使用的规则。

迁移构建系统Bazel

参考Build an iOS App

  1. 迁移至 Bazel 体系,配置BUILD和WORKSPACE
  2. 兼容同时使用cocoaPods和Bazel
  3. .podspec转BUILD 开源方案
  4. install.sh 脚本改造

最终目录如下:


image.png

cocoapods生成的工程叫Test1Bazel.xcworkspace,Bazel生成的工程叫:xxxxxBazel.xcodeproj

Build文件:

load("@build_bazel_rules_apple//apple:ios.bzl", "ios_application")
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")

swift_library(
    name = "lib",
    srcs = glob(["Sources/Delegate/*.swift"]),
    data = [
        "Resources/Main.storyboard",
    ],
    deps = ["//Sources/Network:AFNetworking"],
)

ios_application(
    name = "xxxxxxBazel",
    bundle_id = "com.wuwei.swift",
    app_icons = glob(["Assets.xcassets/AppIcon.appiconset/**"]),
    families = [
        "iphone",
    ],
    infoplists = ["Resources/Info.plist"],
    launch_storyboard = "LaunchScreen.storyboard",
    minimum_os_version = "14.0",
    visibility = ["//visibility:public"],
    deps = [":lib"],
)

load(
    "@rules_xcodeproj//xcodeproj:defs.bzl",
    "top_level_target",
    "xcodeproj",
)

xcodeproj(
    name = "xcodeproj",
    build_mode = "bazel",
    project_name = "xxxxxxBazel",
    tags = ["manual"],
    top_level_targets = [
        ":xxxxxxBazel",
    ],
)

管理工程依赖
CocoaPods 在多仓模式下除去自身的依赖管理能力外,承担了非常多的非自身功能,
如组件二进制集成、hmap 的编译优化,混编能力的支持。
迁移 Bazel 构建系统后这些优化能力名正言顺的通过构建系统来承担。
在 Monorepo 生态中我们也应该设立相应的组件依赖关系验证及组件模块分层服务。Bazel 可以设置所有 target 的可见域,开发者可以将 target 标记为私有,以防止被其他项目错误地依赖,这种约束帮助我们规范代码仓库之中各个库之间的依赖关系。

优化本地体验
在本地开发中通过开源工具 Tulsi、BuildService、IndexImport 的定制化开发,补齐 Xcode 体系中索引、高亮、日志、进度条等语言能力,使 Xcode 体验与之前无异。通过这些工具我们把 Xcode 的优化牢牢把握在自己的手上,也很好的提升了 Xcode 易用性。
Tulsi已经不维护了,官方推荐rules_xcodeproj

最后

Bazel生成的Xcode工程里面的Build settings配置项需要额外的脚本快速配置,因为Build文件改动后Xcode工程每次需要重新生成,手动修改不现实。

最后的最后,我想说:我最大的愿望是世界和平!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容