I. 基准代码

大多数编程语言都会提供一个打包系统,用来为各个类库提供打包服务,就像 Perl 的CPAN或是 Ruby 的 。通过打包系统安装的类库可以是系统级的(称之为 “site ”),或仅供某个应用程序使用,部署在相应的目录中(称之为 “” 或 “”) 。
12-规则下的应用程序不会隐式依赖系统级的类库 。它一定通过依赖清单,确切地声明所有依赖项 。此外,在运行过程中通过依赖隔离工具来确保程序不会调用系统中存在但清单中未声明的依赖项 。这一做法会统一应用到生产和开发环境 。
例如,Ruby 的使用作为依赖项声明清单,使用 exec来进行依赖隔离 。中则可分别使用两种工具 –Pip用作依赖声明,用作依赖隔离 。甚至 C 语言也有类似工具,用作依赖声明,静态链接库用作依赖隔离 。无论用什么工具,依赖声明和依赖隔离必须一起使用,否则无法满足 12- 规范 。
显式声明依赖的优点之一是为新进开发者简化了环境配置流程 。新进开发者可以检出应用程序的基准代码,安装编程语言环境和它对应的依赖管理工具,只需通过一个构建命令来安装所有的依赖项,即可开始工作 。例如,Ruby/ 下使用,而 /则是lein deps 。
12- 应用同样不会隐式依赖某些系统工具,如或是curl 。即使这些工具存在于几乎所有系统,但终究无法保证所有未来的系统都能支持应用顺利运行,或是能够和应用兼容 。如果应用必须使用到某些系统工具,那么这些工具应该被包含在应用之中 。
III. 配置 在环境中存储配置
通常,应用的配置在不同部署(预发布、生产环境、开发环境等等)间会有很大差异 。这其中包括:
有些应用在代码中使用常量保存配置,这与 12- 所要求的代码和配置严格分离显然大相径庭 。配置文件在各部署间存在大幅差异,代码却完全一致 。
判断一个应用是否正确地将配置排除在代码之外,一个简单的方法是看该应用的基准代码是否可以立刻开源,而不用担心会暴露任何敏感的信息 。
【I. 基准代码】需要指出的是,这里定义的“配置”并不包括应用的内部配置,比如 Rails 的/.rb,或是使用时代码模块间的依赖注入关系 。这类配置在不同部署间不存在差异,所以应该写入代码 。
另外一个解决方法是使用配置文件,但不把它们纳入版本控制系统,就像 Rails 的/.yml 。这相对于在代码中使用常量已经是长足进步,但仍然有缺点:总是会不小心将配置文件签入了代码库;配置文件的可能会分散在不同的目录,并有着不同的格式,这让找出一个地方来统一管理所有配置变的不太现实 。更糟的是,这些格式通常是语言或框架特定的 。
12-推荐将应用的配置存储于环境变量中(env vars,env) 。环境变量可以非常方便地在不同的部署间做修改,却不动一行代码;与配置文件不同,不小心把它们签入代码库的概率微乎其微;与一些传统的解决配置问题的机制(比如 Java 的属性配置文件)相比,环境变量与语言和系统无关 。
配置管理的另一个方面是分组 。有时应用会将配置按照特定部署进行分组(或叫做“环境”),例如Rails中的,test, 和环境 。这种方法无法轻易扩展:更多部署意味着更多新的环境,例如或qa 。随着项目的不断深入,开发人员可能还会添加他们自己的环境,比如joes-,这将导致各种配置组合的激增,从而给管理部署增加了很多不确定因素 。
12- 应用中,环境变量的粒度要足够小,且相对独立 。它们永远也不会组合成一个所谓的“环境”,而是独立存在于每个部署之中 。当应用程序不断扩展,需要更多种类的部署时,这种配置管理方式能够做到平滑过渡 。