1、"集成地狱":一个经典的团队噩梦

一个五人团队,各自在自己的分支上开发了近一个月,谁都没合过。到"集成日"才发现:

  • 小王和小李都"新增"了 UserService,重名冲突。
  • 小张升级了依赖 A,和主力升级的依赖 B 版本冲突,编译不过。
  • 每个人的代码单看都能跑,合到一起一下冒出 200 个错误。

这就是 集成地狱(Integration Hell):把"集成"攒到最后一次性做,等于把几十个问题堆在一起爆发。

持续集成(Continuous Integration,CI)的核心思想只有一句话:

频繁地把代码合回主干,每次合入都自动构建 + 自动测试。

把"一个月集成一次"变成"一天集成多次",让问题小步暴露、及时修复。

2、CI 的三条实践原则

CI 不只是"跑个流水线",它是一套纪律:

  1. 频繁提交到主干:至少每天一次,越频繁冲突越小(呼应第 12 课"提交要小步、原子")。
  2. 每次提交都自动验证:构建 + 测试 + 检查,全自动,不靠人记得跑。
  3. 坏了立即修,最高优先级:CI 变红就是全队最高优先级事件,不许"先这样待会儿再修"。
第三条常被忽视,却最关键。一条长期红的流水线等于没有流水线——没人再信它,它就死了。

3、流水线(Pipeline):CI 里跑什么

一次 CI 运行通常按顺序跑这些阶段("流水线"名字的由来):

① 检出代码        git clone / checkout
        ↓
② 装依赖          恢复缓存 or 安装
        ↓
③ 静态检查        格式化检查 + Lint + 类型检查     (第 14 课)
        ↓
④ 构建            编译 / 打包
        ↓
⑤ 测试            单元测试 → 集成测试              (第 15、19 课)
        ↓
⑥ 产出/报告       测试报告、覆盖率、构建产物

关键设计:快速反馈优先。

  • 越早的阶段越快:静态检查几秒钟,就该排在跑几分钟的测试前面。
  • 失败即停:静态检查挂了就别编译了,别浪费时间。
  • 并行:单元测试可以和集成测试并行跑(如果资源允许)。

一个阶段耗时参考(好的体验):

阶段目标耗时
静态检查< 30 秒
单元测试< 2 分钟
整体 PR 流水线< 10 分钟
CI 超过 10 分钟,人类的注意力就散了。 开发者去干别的、忘了这条流水线,反馈延迟就失去了意义。优化 CI 时长是一等一的任务(缓存依赖、并行测试、只测改动的部分)。

4、CI 的落地:工具与配置文件

主流 CI 工具:GitHub Actions(最流行)、GitLab CI、Jenkins、CircleCI 等。

关键理念:CI 配置是代码,进版本库(infrastructure as code)——它和源码一起评审、一起演进。

一个 GitHub Actions 示例(.github/workflows/ci.yml):

name: CI
on:
  pull_request:        # PR 时触发
  push:
    branches: [main]   # 合入主干时也触发

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'
          cache: 'pip'          # 缓存依赖,加速

      - name: 安装依赖
        run: pip install -r requirements.txt

      - name: 静态检查
        run: ruff check . && ruff format --check .

      - name: 类型检查
        run: mypy src/

      - name: 运行测试
        run: pytest --cov=src --cov-report=term

逐段理解:

  • on: —— 触发条件。PR 和推送到 main 时触发("每次提交都验证"的落地)。
  • cache: 'pip' —— 依赖缓存,避免每次重装依赖,这是缩短 CI 时长最有效的手段之一。
  • 各 step —— 就是第 14 课的静态检查和测试,串成自动化流水线。
  • --cov —— 顺带产出覆盖率报告。

结果:这个配置一旦进仓库,每次有人提 PR,GitHub 就自动跑这一整套,结果贴在 PR 上。绿色通过 / 红色失败,一目了然。

5、门禁(Branch Protection):让 CI 真正"卡住"人

CI 跑得再全,如果红了也能合并,就形同虚设。所以要结合第 13 课的分支保护:

PR 提交
    ↓
CI 自动运行
    ↓
    ├── ❌ 失败 → 「合并」按钮被禁用,无法合入 main
    │
    └── ✅ 通过 + 至少 1 人批准 → 允许合并

在 GitHub 上配置 main 的 branch protection:

  • ✅ Require status checks to pass(CI 必须绿)
  • ✅ Require pull request reviews(至少 1 人批准)
  • ✅ Require branches to be up to date(分支要先跟上主干)

这才是完整的闭环:规范(约定)→ 自动化(CI)→ 门禁(强制)。人可以不自觉,机制不会。

6、CI 之外:持续交付与持续部署

CI 是"持续"家族的第一步,后面还有:

术语含义关键差别
CI 持续集成每次提交自动构建+测试保证代码随时可集成
CD 持续交付(Delivery)CI 通过后自动部署到测试环境,人工点一下才能上生产软件随时可发布
CD 持续部署(Deployment)通过后全自动上生产无人工干预,风险更高
写代码 → 提交 → CI(构建+测试) → 部署到预发 → 人工审批 → 上生产
         └─持续集成─┘   └──────持续交付──────┘
                                  (持续部署则去掉"人工审批")

持续部署的前提:

  • 完善自动化测试(不然自动上线等于自动出事故)
  • 灰度发布 / 特性开关 / 蓝绿部署(先小流量验证,出问题能秒回滚)

一步步来:先把 CI 做扎实(本课),再谈 CD。没有 CI 的 CD 是灾难。

7、常见坑

坑后果应对
流水线太慢(>15 分钟)没人等,失去反馈意义缓存依赖、并行测试、只测改动
随机失败的测试(flaky)团队开始"重跑一下就好",不再信 CIflaky 测试必须当天修或删,不许留
流水线红了没人管CI 形同虚设红了全队最高优先级,或自动回滚
在 CI 里用真实生产密钥泄露/误操作用 CI 的密钥管理(secrets),只读权限
CI 配置散落、不评审没人懂怎么改.yml 进版本库,走 PR 评审

flaky 测试是 CI 的慢性毒药:一个测试"有时候过有时候不过",团队会养成"重新跑一次"的坏习惯,然后真 Bug 也被当成 flaky 忽略掉。见到 flaky,立刻修或隔离,不许放养。

8、动手实验 🎯

任务:给你自己的 GitHub 项目配一条完整 CI。

  1. 创建 .github/workflows/ci.yml,实现:安装依赖(开缓存)→ 静态检查 → 测试。
  2. 故意提交一个会失败的测试,观察 CI 变红、PR 上出现红叉。
  3. 修好它,观察变绿;确认整个过程无需手动跑任何命令。
  4. 配置 main 的分支保护:要求 CI 通过 + 至少 1 人批准。然后试试直接往 main push,验证被拦住。
  5. 优化速度:记录优化前后的 CI 耗时,至少用一招(开依赖缓存 / 只跑改动相关测试 / 并行)。
  6. 写一段 200 字的 CI 使用约定:流水线红了怎么办、多久必须响应、flaky 测试怎么处理。
  7. (挑战)思考你项目的"持续交付"还差什么:缺自动化部署?缺回滚?缺灰度?列出来。

做完这步,团队就有了自动质量守门人——下一课把视角拉高,讲敏捷实践怎么把这些工程实践串成一套工作方式。

9、今天你带走的三句话

  1. CI 的核心是"频繁集成 + 自动验证",把"一个月集成一次"变成"一天多次",消灭集成地狱。
  2. 流水线要快(<10 分钟)、红了要立刻修;配上门禁,把规范从"口头约定"变成"机制强制"。
  3. fiaky 测试是慢性毒药,见到就修或删;先做扎实 CI,再谈持续交付/部署。

下一课讲敏捷开发实践——把前面这些工程手段放进一套迭代、协作的工作方式里。

标签: 软件工程, 项目管理, 开发流程

添加新评论