4.2 Build的演进之路
沿 Build 从手工命令、自动化脚本、Java 与 XML 到声明式依赖图的演进,理解可重放构建如何产生可信产物。
学习目标
- 能沿项目模型、依赖解析、生命周期阶段、验证和产物五个节点解释一次可重放 Build
- 能比较手工 Build、自动化 Build、Java 与 XML 配置和消除重复各自解决的边界与新成本
- 能在正常、边界和故障场景中定位未声明输入、依赖漂移或跳过验证造成的首个不可复现节点
4.2 Build的演进之路
本页依据刘欣《码农翻身》(2018 年第 1 版)及出版社公开书目信息,独立重构 4.2 Build的演进之路。正文、图示、实验和练习是本课程重新设计的教学材料,不复制原书正文、插图、练习答案或代码。
Build 的问题不是“能不能在我的电脑上编译”,而是输入、依赖、步骤、验证和产物能否被另一台机器按同样规则重放。手工命令靠记忆,自动化脚本把步骤固定下来,Java 与 XML 让项目模型可描述,进一步消除重复后,构建系统可以根据声明的依赖图复用阶段并暴露真正的输入变化。
三个会让构建结果失真的陷阱
五个目录节点到构建证据
4.2 Build的演进之路
总合同是:读取项目模型确定输入,解析依赖得到闭合图,按生命周期执行阶段,运行验证确认行为,再生成带清单的产物。构建成功的证据不只是一个文件,还包括模型、依赖、工具链、日志、测试结果和产物摘要。
手工Build的烦恼
手工Build的烦恼 来自命令、顺序和环境都藏在人的记忆里。少执行一个生成步骤、切错目录或忘记复制资源,结果就可能“看起来成功”却不能部署。手工方式适合探索,但不能成为长期的发布合同。
↡依靠个人记忆逐条执行编译、复制、测试和打包命令的构建方式;反馈快但输入、顺序和环境难以审计。自动化Build
自动化Build 把步骤写进脚本或流水线,并能在干净环境执行同一序列。它消除了忘记命令的风险,却可能把隐含路径、机器环境和重复逻辑原样固化;自动化不等于可复现。
↡把构建步骤交给脚本或流水线按固定顺序执行的方式;减少人为遗漏,但仍需声明输入、依赖、工具版本与验证。Java 与 XML
Java 与 XML 代表把项目模型从命令细节中抽出来:Java 提供可执行工具与插件生态,XML 描述坐标、生命周期、插件和依赖。模型让构建系统能读懂项目,但配置层级、默认值和插件版本仍需被审计。
↡用 Java 构建生态执行插件与生命周期,并用 XML 声明项目坐标、依赖和构建配置的组合;提高约定复用,也引入模型解析边界。消除重复
消除重复 不是把所有配置藏到一个神奇默认值里,而是把共同生命周期、插件约定、依赖坐标和产物规则抽成可复用模型。复用减少复制粘贴,也要求清楚记录默认值、继承关系和覆盖来源。
↡把重复的命令、插件和依赖规则抽成共享模型或约定的构建改进;减少维护面,但必须能追踪默认值和覆盖来源。Lab
Build 可重放与发布门禁实验
只改变一个输入或依赖,观察阶段日志、验证结果和产物摘要怎样变化。
模型、依赖、阶段和验证闭合,产物摘要稳定
model → lock graph → lifecycle → tests → artifact sha
判定
accept:输入与过程证据足够重放
当前样本:干净构建;保存模型、依赖树、阶段日志、验证结果、产物摘要和复位轨迹。
五步重放一次 Build
1. 读取项目模型并固定输入
记录项目坐标、源目录、配置文件、Java 与 Maven 版本及环境变量。正常样本来自干净工作区,边界样本只改变一个配置,故障样本移除一个未声明的本地文件。
正常、边界与故障证据矩阵
| 样本 | 只改变的变量 | 预期判定 | 必存证据 |
|---|---|---|---|
| 正常 | 干净环境与锁定依赖 | 阶段、验证和产物摘要可重放 | 模型、依赖树、日志、摘要 |
| 边界 | 改一个配置或插件版本 | 只影响相关节点并能解释差异 | 配置 diff、阶段输入、测试结果 |
| 故障 | 移除隐含文件或让测试失败 | 拒绝产物并保留首个失败节点 | 输入清单、失败日志、复位轨迹 |
故障诊断:先找未声明输入
- 项目模型:查坐标、源目录、配置、工具链和环境变量;干净环境失败时先比较输入清单,不要先重跑缓存。
- 依赖解析:查直接依赖、传递依赖、版本冲突、仓库和锁定状态;依赖树不同就是独立输入变化。
- 生命周期阶段:查哪个插件、阶段或资源处理第一次偏离;自动化脚本成功不代表每个阶段合同都满足。
- 验证与产物:查测试、清单、摘要和发布门禁;没有验证证据的压缩包不能被称为可发布产物。
如果本地通过而 CI 失败,先删除缓存并重建输入清单;如果同一提交产物摘要变化,比较依赖树和工具链;如果测试失败但产物仍上传,修复阶段门禁并重新验证。每次只改变一个构建输入,再从干净基线重放。
术语与边界
本页四个术语都绑定到实验中的模型字段、依赖节点或阶段状态:
- 手工Build的烦恼:命令和环境依赖个人记忆。
- 自动化Build:脚本固定步骤,但仍需声明输入。
- Java 与 XML:执行生态与项目模型描述的组合。
- 消除重复:抽取共享约定,同时保留可追踪默认值。
名词解释
本章出现的专业名词,用大白话再讲一遍。
- 手工Build的烦恼
依靠个人记忆执行构建命令,输入、顺序和环境难以审计。
- 自动化Build
让脚本或流水线按固定序列执行构建步骤,但必须继续声明输入和验证。
- Java 与 XML
以 Java 插件生态执行生命周期,以 XML 描述项目坐标、依赖和配置的组合。
- 消除重复
把共同插件、生命周期和依赖规则抽成共享模型,并追踪默认值与覆盖来源。
练习
练习
问题 1: 同一提交在本地和 CI 生成了不同产物摘要,应该先查哪里?
问题 2: 为什么把所有命令写进脚本仍不一定得到可复现 Build?
问题 3: 修改实验让一个测试失败;写出发布门禁应保留的三类证据。
本页小结
- 手工 Build 依赖记忆,自动化 Build 固定步骤,Java 与 XML 形成项目模型,消除重复则复用生命周期与插件约定。
- 可重放构建必须同时保存输入、依赖树、阶段日志、验证结果和产物摘要。
- 诊断要先找未声明输入或依赖漂移,再判断阶段与发布门禁,不能只看“目录里有一个压缩包”。
读完后的自测问题是:面对“我的机器能编译、CI 不能编译”或“同一提交产物变化”,你能否指出首个未声明输入,并用干净基线重放修复?