关于语义化版本规则(Semver)的领悟

前言

以前一直忽视了版本号规则的重要性,这两天改了一个bug让我深刻的领悟了遵守语义化版本规则(semver)的重要性。尤其是当自己需要造轮子给别人用的时候,如果没有遵循语义化版本规则,是很容易给别人留坑的。。。

简述

首先稍微解释下语义化本本规则,这套规则其实在网上也是到处被搬运(吐槽一波,非常讨厌这种搬运语法啊规则啊这些知识点而不说明出处的行为)。其实这套规则的出处是来自semver的官网。具体的概念文档里解释的很清楚,这里就不赘述了。

问题

问题来源于我对node里ejs的一次错误使用。
ejs包里有一个 renderFile 的方法,这个方法原本是设计成同步的,因此我们可以直接从返回值里获取render之后的结果。
但是最近一次更新,他修改了这个函数的实现,使他支持了异步操作,同时也取消了同步返回结果的功能,导致我在使用的时候出现了没想到的bug。
程序员还是直接看代码比较习惯,直接上一张操作流程图吧:
@asciinema
在2.5.6版本中,他是支持返回值获取结果的,但是在2.5.8中,他突然就取消了这个功能,造成了向下不兼容的情况出现。
当然,引入新功能导致向下不兼容本身并没有错,但是问题就在于新发布的这个版本只是修改了次版本号,根据npm的语义化版本规则,默认的'^2.5.6'版本号会自动升级为'2.x.x'的更新的包。这就导致npm在更新的时候会自动升级到这个向下不兼容的版本,从而使原本可用的代码变得不可用。这样类似的bug相当难以被发现,尤其是当依赖一层套一层之后,谁知道是哪一层引用了这样的包。。。

解决&教训

  • 作为包的使用者而言,如果我们不信任某些包以后的版本,我们可以不使用^前缀自动更新版本,而是采用确定版本号的方式,这样可以保证即使今后这个包打了坏补丁也不会影响到之前的版本。
  • 作为轮子的制造者,在发布一个向下不兼容的版本时,一定要注意修改major version,保证低版本不会因为自动更新导致bug。
  • 作为一名普通的码农,也要有一点意识,就是尽量不要使用 'undocumented functionality' 这样的功能很有可能被后续版本淘汰;同时,要学会正确编写异步代码,不能总想着用同步的方式来调用异步api。
    嗯,大概就是这些。

参考资料

Semver
The issue that I raised in gayhub