Build系统介绍
好的IDE做Build工具的Wrapper,Build平台也应只做Build工具的Wrapper,大量散乱的Build脚本应被组织起来,演变为Build工具
10000公里俯瞰Build
Build体系中包括Build平台,Build工具,Build脚本。大量散乱的Build脚本,只会导致各种Build工程师的产生,它应进化为一种Build工具。Build平台应该最大力度的发挥Build工具的能力,至于Build脚本,交给用户(开发者)吧,只有他们有责任和欲望演进构建脚本代码,我们应致力于Build平台体验和构建工具的引入与研发。
当代Build平台,它应该能提供规范统一,集中的构建分享舞台,加快构建的生产与消费。
Build工具本质上,是对文件的处理,加工,构建出目标容器可以运行的软件。构建的过程就是输入,输出,处理的有向无环图。Build工具的优化,就是对这个有向无环图的优化,单个节点处理,多个节点输入输出的缓存/增量处理,图流向的优化,并行处理等。
Build脚本,自然就是对输入,输出,处理的描述,从一开始用文本,xml,再到DSL,到代码,是工程师对Build脚本认知的成熟体现。
SCM
Build的原材料来自VCS,但它依赖的中间产物,产生的中间产物,不应该被上传至VCS。Build脚本应视作代码。
Configuration Manager System
虽然仅仅是flavor,可以抽象为独立的服务,并且最好抽象为独立的服务
Profile
- 平台的独立性
- 不同的调料,当发现api传递很多参数时,应该考虑这些参数是否需要暴露,然后分组,只暴露profile。
Script/DSL
DSL是通用语言发展到一定阶段的必然产物,Build DSL的产生意味着Build工具的描述能力不再受限制
Repository
提供了构建消费者和提供者的舞台,这也是一个平台繁荣的必要条件。它利于模块化的实践,在facebook专门开发工具,鼓励代码小模块的实践,加速构建速度。
仓库管理的中心化,布局的标准化,让开发者专注于构建的使用和集成
结合git的tag管理,充分利用scm和代码密切联系,可以减少二次存放
本地缓存,局域网代理,缓存,高可用。
生产构建的格式应该与行业标准可适配,否则就意味着自造车轮,至少是封闭的,不利于引入第三方构建,是与开源的对抗
Artifact
Version
具体参考sem。
通常在集成初期为了开发方便,可以设置一种Time Changing版本,每次构建都会获取最新的版本,显然它应该限制在生产环境,在maven中体现为Snapshot机制
在集成趋于稳定时,可以用Dynamic Changing版本,并最终到Final版本
版本应该直接体现在构建的文件名字当中,避免不必要的错误。
依赖
没有依赖的项目,通常是没什么用的,Martin Fowler如是说。
大型的互联网系统,依赖图也将非常复杂,它至少支持,依赖传递与中断或排除,以及版本冲突的选择策略定制。
Lifecycle
生命周期的定义,意味着某种构建的抽象可能性,尤其对于DotNet,Java等平台,构建本身是一种标准,比如Java中war,ear等,它可以帮助把约定胜于配置的理念发挥到极致,同时Lifecycle也通常意味着不变,对于灵活性要求极高的构建,则需要更强大的DSL来帮忙。
构建任务合理的组织,文件夹结构分类明确,自包含。
Task Graph/Goal
对于构建有向无环图的抽象,可以看成Gradle中的TaskGraph,在Maven中则对应为Lifecycle和Goal。
Build系统引擎的优化,则是这TaskGraph的优化。调度系统如此,试框架TestNG也是如此。
Best Practices
- Build Script 由开发维护,作为代码的一部分。
- 一致性,本地,server端的构建行为要一致,可以方便验证。
- 关注点分离,self-contained的完整的输入输出及处理周期。
- 根本上关注构建体验,分而治之。
- 引入构建仓库。
Cbuilder’s Anti Pattern
- SCM项目源码依赖–>SCM目录依赖–>SCM文件依赖 中间仓库,源码依赖意味着依赖的交付为源码,JDK的开发中比如jshell,http2
- BuildScript过重,没有转给开发,Build Engineer的出现
Develop Build Tool
- Build 是严肃的,稳定
- Build 应该被合理的组织