循序渐进 · 教学 · 函数(六)

函数版本管理:语义化版本与兼容性

函数版本号由发布者选定,一经创建不可更改。这一篇讲清:什么算破坏性变更、SemVer 三段号怎么选、平台如何自动做兼容性检查。

全部目录 ← 上一篇 函数版本管理:语义化版本与兼容性 下一篇 →
本文来源 · Source 内容整理自 Palantir Foundry 官方文档:
https://www.palantir.com/docs/foundry/functions/functions-versioning/
原始标题:Function management > Function versioning

先记住这几条

① 版本不可变
发布后版本号固化,不能改,只能发新版本。
② 破坏性 vs 向后兼容
删参数、改类型算破坏性;加可选参数通常兼容 —— 这决定版本号怎么跳。
③ SemVer 三段号
主版本.次版本.修订号,配合平台的自动兼容性检查。
④ 0.y.z 阶段特殊
初始开发阶段(0.x)的版本选择有单独约定。
0

写在前面

本文档描述函数所使用的版本管理系统。函数发布的版本由其发布者选定,且在创建后不可变。应用合适的版本,对于为函数的使用者提供稳定可靠的体验至关重要。

1

什么算破坏性变更

什么算破坏性变更

要点:先建立判断标准:哪些改动会让老调用方崩掉。

函数的版本系统区分向后兼容的变更破坏性(breaking)变更向后兼容的变更是不会干扰你函数现有使用者的变更。不向后兼容的变更可称为向后不兼容破坏性变更。

向后兼容变更的一些例子:

  • 为函数签名增加一个可选输入。
  • 在不改变预期行为的前提下优化函数性能。
  • 在不改变预期行为的前提下修复函数中的一个 bug。

破坏性变更的一些例子:

  • 为函数签名增加一个必填输入。
  • 将函数签名的输出类型从整数改为字符串。
  • 删除一个函数。

在判断对现有版本的变更是否向后兼容时,问问自己:该变更是否会给现有版本的使用者带来中断,或需要其显式关注。

请记住,最终由你来决定函数的预期消费模式。

2

语义化版本体系

语义化版本体系

要点:三段号怎么选、平台如何自动校验、能否限制 stable 标签。

函数按照 语义化版本(Semantic Versioning)↗ 系统来版本管理。

在语义化版本中,版本形式为 X.Y.Z,其中 XYZ——分别称为主版本、次版本、修订版本——是非负整数(例如 1.2.3)。版本也可以包含一个预发布标识符,由字母数字字符组成,紧跟在修订版本之后加连字符(例如 1.2.3-rc1)。

本页简要总结了语义化版本。我们鼓励你阅读完整规范 ↗,因为遵守规范是发布可被其他应用可靠消费的函数的重要一环。

Choosing a release version

发布函数的新版本时,请考虑语义化版本规范中的以下几点:

  • 主版本 00.y.z)用于初始开发阶段。在初始开发期间,函数可能随时变更,使用者不应认为你的函数是稳定的。
  • 当你做出向后不兼容的变更时,应递增主版本。
  • 当你以向后兼容的方式新增功能时,应递增次版本。
  • 当你做出向后兼容的 bug 修复时,应递增修订版本。
  • 预发布版本表示该版本不稳定,可能不满足其关联正式版本所表示的兼容性要求。

Backward compatibility checks

在你发布新版本之前,会对你的函数执行向后兼容性检查。具体而言,遇到以下任何破坏性变更时你会收到警告:

  • 弃用一个函数。包括在 Python 或 TypeScript 函数代码仓库中删除一个函数。
  • 移除函数签名上的某个输入(即便是可选输入)。
  • 重排函数签名上的输入顺序。
  • 为函数签名增加必填输入。
  • 错误的输入类型变更(例如整数改字符串)。将数值输入类型放宽(如整数改浮点)也会触发警告。
  • 错误的输出类型变更(例如字符串改可选字符串)。

如果这些检查因任何原因失败,建议发布一个主版本。但这不适用于你仍处于初始开发阶段(即主版本仍为 0)的情况。

Palantir 的内置检查并未穷尽所有类型的破坏性变更。例如,你的内部实现所带来的破坏性变更可能不会被检测到。仅根据这些检查的成功结果就发布次版本或修订版本是不安全的。

Caveat: Custom types

函数数据类型内部的表示目前缺乏关于自定义类型字段可选性的足够信息。因此,你可能会注意到,对于自定义类型的输入与输出,向后兼容性检查会在移除或新增任何字段(包括可选字段,例如 TypeScript 中的 quantity?: Integer 或 Python 中的 quantity: Integer = 0)时发出警告。

我们目前正在做出改变,以便今后在移除输出自定义类型上的可选字段、或新增输入自定义类型上的可选字段时,不会再对你发出警告。

移除输入自定义类型上的可选字段时,你仍会收到警告。忽略使用者提供的任何字段通常被认为是不好的做法,因为他们很可能期望所提供字段能够决定你函数的行为。

Restrict stable version tags

稳定语义化版本发布(非预发布版本)在下游生产应用配置为按版本范围引用函数(例如 >=1.2.3 <2.0.0)时,可能被立即消费。这使得在发布新的稳定版本之前审查并测试代码变更变得很重要。

可以通过在受保护分支的仓库设置中启用一个开关,来强制限制函数稳定版本的发布。

3

常见问题

常见问题

要点:0.y.z 阶段怎么选号、误把破坏性变更当补丁发出去怎么办。

Choosing release versions in the 0.y.z initial development phase

常见的做法是:任何破坏性变更都在次版本中发布,任何向后兼容的变更都在修订版本中发布。这是许多开发领域(例如 Node/NPM 生态)中使用者所做出的假设,其广泛使用插入符范围(caret ranges)↗即为例证。

Accidentally releasing a backward incompatible change as a patch or minor version

一旦你意识到发布了一个破坏性变更,就应立即纠正问题,并在一个新的次版本中恢复向后兼容。

考虑以下例子。

  1. 你有一个名为 myFunction 的函数,版本 1.0.0,它接受一个字符串输入。
  2. 你为 myFunction 新增了一个必填输入,并不慎以次版本 1.1.0 发布了这一变更。

为了补救,你可以撤销该签名上的破坏性变更(即移除你在 1.1.0 中新增的必填输入),并以版本 1.2.0 发布这一变更。

Checking backward compatibility when a release fails or has not yet been published

对于 TypeScript 或 Python 函数,你的函数可能发布失败或需要几分钟才能发布。在这两种情况下,内置的向后兼容性检查都无法运行。如果你想在发布新版本前看到这些检查结果,有以下选项:

  • 如果上一次发布失败,应使用「custom tag(自定义标签)」选项,与上一个成功的标签进行比较。
  • 如果上一次发布尚未发布,应等待它完成。

延伸阅读 · 相关页面

按主题横向跳转,不必顺着目录一篇篇读。

常见问题速答 · FAQ

关于「函数版本管理:语义化版本与兼容性」,读者最常问的几个问题。

什么算破坏性变更?
先建立判断标准:哪些改动会让老调用方崩掉。函数的版本系统区分向后兼容的变更与破坏性(breaking)变更。向后兼容的变更是不会干扰你函数现有使用者的变更。不向后兼容的变更可称为向后不兼容或破坏性变更。
语义化版本体系是什么?
三段号怎么选、平台如何自动校验、能否限制 stable 标签。
还有哪些问题?
0.y.z 阶段怎么选号、误把破坏性变更当补丁发出去怎么办。