向前兼容:在需要使用某个库时,可以使用旧版本的某个库替换其新版本,而不会引发问题。通常我们需要使用SchemaRegistery等来达到目的(比如旧版本还可以读取新版本写入的数据),向前兼容使我们提供的客户端库可以独立服务器端进行多版本演进。还有一些则是为了生态平滑升级做出的努力:Forward Compatibility for the Scala 3 Transition
在上图中,产物 A 依赖了库 B ;如果可以使用 B V1 代替 B V2 ,则说 B V1 是向前兼容的;如果可以使用 B V3 代替 B V2 ,则说 B V3 是向后兼容的。
上图中,应用 A 同时依赖了库 B 和 库 C;而库 B V1 依赖库 D V1 , 但是这些方法在 D V2 中被删除了,而在 C V2 中又开始使用了仅存在于 D V2 的一些方法。这个时候, D V2 相对于 D V1 不具备向后二进制兼容性。作为应用 A来说,就陷入了困境,无论排除掉库的 V1 还是 V2 版本,都会引发错误。唯一的办法是让 B 迁移到 依赖 D V2 ;或 B 和 C 都升级到的另一个共同兼容版本进行编译发布,然后 A 再升级。
有时候,新功能开发需要引入一个新的依赖,但是新的依赖又会引入二进制不兼容性,这个时候开发新功能,就会破坏旧功能;保留旧功能,就不好开发新功能。通常把这种情况叫做“依赖地狱”(dependency hell)。如上图,如果我们需要引入一个新的功能需要用到库 F ,而 F 依赖了库 D V3 , 如果此时 D V3 相对于 D V2 不是二进制兼容的,那么我们就必须要 升级 B V2 和 C V2 ,使它们依赖于 D V3 进行开发,从而才可以安全地引入 F 。
由上可见,保持一个二方包在各个 minor 和 patch 版本之间的兼容性对于一个普通的开发同学的幸福感来说是多么的重要。通过尽可能地保持二进制兼容性,库的消费者在遇到依赖冲突时,可以排除掉旧版本的包,直接使用新版本的包,而不会陷入进退维谷的境地。
推荐阅读
Revapi is a tool for API analysis and change tracking.
japicmp is a tool to compare two versions of a jar archive:
japi-compliance-checker — a tool for checking backward binary and source-level compatibility of a Java library API.
binary-compatibility-validator ——The tool allows to dump binary API of a Kotlin library