第2章:SDK版本管理基础

版本号,不只是三个数字

很多刚入行的同学觉得,版本号嘛,不就是1.0.0、2.1.3这种三个数加点。嗯,表面上看确实是这样。但如果你真这么想,后期回归测试会踩不少坑。

我之前在一家做IoT SDK的公司待过。有一次内部SDK从1.9.9升级到1.10.0,集成方死活不认这个版本,说你们怎么跳了这么多?后来发现,人家把版本号当成浮点数来处理,1.9.9到了1.10.0系统直接崩掉。

这种破事,你经历一次就记住了。版本号不是随便写的,它有规范,有讲究。

语义化版本——业界的通用语言

现在几乎所有正经SDK都遵循语义化版本规范(Semantic Versioning)。说白了,就是三个数字各代表一层含义:

版本段 名称 变化时代表什么
MAJOR 主版本号 不兼容的API变更
MINOR 次版本号 向下兼容的功能新增
PATCH 修订号 向下兼容的问题修复

举个例子:3.2.1 → 主版本3,次版本2,补丁1。

如果下个版本改了API签名,那得升主版本到4.0.0。如果只是加了个新接口,不影响老的调用,那就升次版本到3.3.0。假如只是修了个野指针崩溃,那就升修订号到3.2.2。

核心原则:主版本号变化,意味着回归测试必须全面覆盖。次版本号变化,要做好向下兼容检查。修订号变化,通常只做局部验证。

我踩过的坑:版本号与APR(应用编程接口)关系

你可能会问,这有啥难的呢?照搬不就行了?

我见过不少团队,把主版本号当成大版本Release号。比如从2.0.0升到3.0.0,其实只是内部重构了数据库,对外接口一个没动。

这种搞法,害死集成方。人家一看主版本变了,以为API全废了,吓得不敢升级。我也因为这个吃过亏——有一次我就因为漏了主版本升级,导致APP发布后一半用户闪退。

从那以后,我坚持一个原则:只要破坏了任何一条外部API的签名、行为或默认值,主版本必须升。

版本兼容性的两种类型

测试必须搞清楚,向下兼容并不等于「所有功能都还能用」。咱们聊几个关键词:

  • 前向兼容(Forward Compatibility):新版本SDK能够处理老版本客户端发来的数据或请求。说白了就是「新能吃旧」。
  • 后向兼容(Backward Compatibility):老版本客户端能够正常工作在新版本SDK环境中。也就是「旧能吃新」。

我归纳了一张表,方便你理解两者的差异:

兼容类型 核心要求 回归测试重点
后向兼容 老接口不变,参数/行为不变 所有历史接口的回归用例
前向兼容 新格式可被旧解析器理解 老版本下的序列化/反序列化

警告:前向兼容往往被忽视。我自己的经验是,一旦SDK暴露了可扩展的数据结构(如JSON、Protobuf),新字段加得不小心,老版本解析会直接抛异常。这种事情出一次,客户信任就掉一截。

版本演化与测试策略的关系

讲到这里,我想给你画一张图。这张图是我自己总结的版本管理知识体系,能帮你在做回归计划时快速定位需要多大的测试范围。

版本管理知识体系 版本号结构 MAJOR.MINOR.PATCH 语义化版本 变更规则与含义 兼容性定义 前向 vs 后向 主版本 ↑ 破坏性API变更 需全量回归 次版本 ↑ 新增功能 向后兼容 修订号 ↑ Bug修复 局部验证 回归验证策略制定依据 ⚠️ 每个版本变更都对应不同的测试深度

个人习惯:我每次做版本回归之前,会先看一眼主版本号。如果从2.x.x跳到3.0.0,我会立刻拉一个所有接口的覆盖清单,并标记哪些是外部SDK暴露的方法。这一步,能省掉至少30%的无用回归。

版本兼容性定义——别小看它

在公司里写SDK,你跟服务端、客户端、QA都对着版本号沟通。如果你用的是自定义版本号(比如V2024.03.01这种),大家根本分不清这次改动有没有破坏兼容。你想想看,那你回归测试怎么分配资源?

我一般这样定义兼容性:

  • 二进制兼容:老编译产物直接替换新SDK,不需要改代码、不需要重编。大部分库(如DLL、.so)必须做到这一点。
  • 源码兼容:老代码不需要修改就能编译通过。虽然接口签名没变,但头文件可能动了。
  • 行为兼容:同样的输入,在新版本下输出跟老版本一致。这个最难测——因为结果一样不代表行为一样,有些边界条件可能触发新代码走不同的路径。

我做测试的时候,这三条优先级是:行为兼容 > 二进制兼容 > 源码兼容。为什么?因为用户感知的是行为。你改了内部实现,即使接口完全一样,如果某个边界情况处理有差异,集成方一样会骂娘。

避坑指南

这里给几点我自己摔出来的教训:

  1. 别在补丁版本里加新功能。这违反了语义化版本。我见过有人嫌麻烦,在2.3.5里塞了个新接口,结果集成方升级后编译不过——因为头文件多了个参数。修了个补丁,却把自己搞成了大版本升级的兼容问题。
  2. 外部API添加可选参数也要谨慎。有些语言(比如C++)默认参数行为变了,也会破坏源码兼容。
  3. 版本号的预发布标签,比如4.0.0-alpha.1或4.0.0-rc.2,这部分不要出现在正式对外发布的SDK里。我一般只在内部CI阶段用这些标签,对外统一发正式版本号。

曾经有一次:我把预发布标签2.1.0-beta直接发给了客户,客户集成后遇到一个Bug,问我们是不是正式版。我们说不是,但人家已经在线上跑了,最后不得不紧急发一个2.1.1修掉。从那以后我再也不把包含-alpha、-beta、-rc标签的版本号发给外部。

小结一下

版本管理这件事,看上去简单,实际上决定了整个回归策略的骨架。你版本号怎么定义,兼容性怎么划分,直接决定了你要测多少东西、测多深、选什么测试策略。

记住:版本号是契约,不是标签。

我的做法:每次在SDK的README里加一张版本与兼容性对照表,把每个主版本对应支持的API版本、依赖库版本写清楚。集成方一看就明白,回归组也能直接拿它来做测试计划。