在对软件进行版本管理时应考虑哪些因素

132 阅读8分钟

我记得很多年前,当我发布我的第一个开源项目时,每当我准备好一个新的版本,我总是不确定新的版本号应该是什么。

当你没有丰富的经验时,软件的版本管理并不像看起来那么简单。

在这篇文章中,我将尝试解释SemVer版本软件的方法,以及在此基础上你可能要考虑到的一些事情。

语义版本管理

你首先需要的是一套坚实的规则,帮助你决定下一个版本应该是什么。

我记得我在想*"这个版本是否足够大,可以从1.0跳到2.0?"或者"我见过一些项目使用三个数字来表示版本,X.Y.Z,我是否也应该这样做?"*

如果你坚持采用某种标准,告诉你应该怎么做,那么这些问题就比较容易回答,而这也会帮助其他人更容易理解你的意图。

我的建议是使用语义版本学(Semantic Versioning),因为它定义了一个坚实的起点,而且它已经被社区所采纳。

语义版本学(Semantic Versioning)指出,你应该使用三个数字来标识版本,MAJOR.MINOR.PATCH ,并遵循这些规则,以决定增加哪一个版本。

  • PATCH:新版本只包括错误修复。我们鼓励人们更新到这个版本,并且不需要对他们的代码库进行修改。
  • MINOR: 新版本包括新的向后兼容的功能。人们可以在不改变他们的代码库的情况下更新到这个版本,如果他们愿意的话,可以在之后使用这些新功能。
  • MAJOR:新的版本包括向后兼容的中断。在更新到这个版本时,需要对代码库进行修改。

这些规则适用于库和框架比适用于应用程序和服务要容易。稍后会有更多关于这方面的内容。

尽量保持向后兼容

好了,我们现在有了一些规则。然而,我经常看到人们把可以做的事情和应该做的事情搞错了。

是的,如果你引入了一个破坏性的变化,你可以更新主要版本,仅此而已。但是,如果你做得太频繁,人们就会不高兴,最终你会有一个分散的用户群,停止更新到新的版本。

我记得用一个库来部署东西,每隔几个月就有一个新的主要版本,改变了一些东西,比如 "host 函数现在叫server"。是的,好的,但是为什么我必须如此频繁地改变我的东西。

通常更好的做法是尽量以向后兼容的方式实现东西,并记录下你想改变的东西,一次做完。

你也可以废除一些东西,并记录下你希望这些东西向前发展的方式。这样你就给人们机会开始改变他们的代码,并简化假设的即将发布的主要版本。

提供清晰的升级路径

如上所述,过于频繁的主要版本变更是不可取的,但你迟早会因为不同的原因想要发布一个新的主要版本。

  • 摆脱那个难以维护、引入很多bug、提供很少价值的功能。
  • 支持一些新的东西,这些东西在不破坏向后兼容性的情况下很难实现。
  • 移除那些你已经拖了好几个月的废弃方法。
  • 修复设计问题,即某些东西的架构是错误的,在一段时间后才被发现。

在这种情况发生时,你会希望你的用户升级到较新的版本,因为你不希望人们报告只影响旧版本的bug,或者期望你向旧版本回传修复,因为他们还没有升级到新版本。

实现这一目标的最好方法是提供清晰而简单的升级路径。

  • 为将来的事情准备好你的版本。如果你想引入新的做事方式,就在主要版本之前做,并废除旧的。例如,你可以有一个新的方法被一个旧的方法所调用,而你把旧的方法标记为废弃的。

    人们会更愿意在之后更新和改变他们的代码。等到主要版本发布时,他们的代码就可以升级了。

  • 在你的项目中包括一个CHANGELOG文件,解释每个版本中引入的变化。记录变更日志的一个非常好的方法是Keep a changelog倡议。

    你也可以使用一些其他的平台来记录变更日志,比如GitHub发布。

  • 包括关于如何升级到主要版本的文档。这可能是最重要的一条。记录所有需要遵循的步骤以及从一个版本升级到下一个主要版本所需的所有变化。

    做到这一点的一个好方法是在你的项目中包括一个UPGRADE文件。你可以看看这个例子

版本管理库与应用程序

语义版本管理(Semantic Versioning)是一个很好的软件版本管理标准,但是它对于使用某种软件包管理器进行安装的库和框架的作用要比对于不直接依赖的应用和服务的作用好得多。

例如,你如何识别网络用户界面上的向后兼容问题?

对于这类软件,有更多的灰色地带,你最终会使用你的直觉。

例如,不久前我为我维护的一个网络应用程序发布了一个新的主要版本,它与以前的版本完全兼容。然而,它引入了比平时更多的功能,以及大的UI变化,所以我决定值得一撞。

正因为如此,有些项目采用了不同的方法来对应用程序进行版本管理。比如说。

  • 火狐和Chrome有6周的周期,在每一个周期之后,无论如何都会发布一个新的主要版本。
  • Jetbrains每年都会发布一些他们的IDE的版本(我想是3个),这些版本总是以他们发布的年份开始,比如2020.3.0 ,而且他们会增加修复错误的补丁数量。
  • Ubuntu每年发布2个版本,一个在4月,一个在10月,它们总是以发布的年份和月份来标识,比如19.0420.10

特殊版本

还有一组特殊版本,可以用来发布所谓的预发布版本。这些都是由语义版本学(Semantic Versioning)所涵盖的,但是有时候它们并不那么容易理解。

而且,你很可能永远都不需要使用这些版本,因为只有相对较大的项目才会需要这种级别的粒度,但是,知道它们的目的是什么以及它们意味着什么,还是很有好处的。

0.x.y

你有可能发布一个版本的软件,其主要数字是0 。当这种情况发生时,这意味着你的软件仍然处于早期阶段。

这并不意味着它一定是不稳定的,但它意味着你仍在频繁地对它进行修改,因此,它可能比数字大于0 的版本更脆弱一些。

阿尔法

阿尔法版本的目的是让一部分人测试一些新的功能,但你并不希望人们在生产中使用它。

阿尔法版本处于非常早期的阶段。它们的公共API很可能会发生变化,而且它们很可能会包含一些错误。

语义版本学(Semantic Versioning)指出,阿尔法版本是由这种模式来识别的。MAJOR.MINOR.PATCH-alpha.NUMBER,例如2.0.0-alpha.1

测试版

与alpha版本类似,beta版本也容易包含错误,但是它们的API在理论上不会改变。这意味着,你有可能调整你的软件,以便开始使用一个测试版,而当相应的稳定版发布之后,你应该不需要做那么多的改动。

语义版本管理(Semantic Versioning)定义了一种类似于alpha版本的模式。MAJOR.MINOR.PATCH-beta.NUMBER,比如说2.0.0-beta.1

候选版本

候选版本(Release candidate,简称RC)是预发布版本,您希望将其发布给普通用户群,以测试即将发布的版本。你想发布一个RC,这样它就会被尽可能多的人测试,以发现可能的bug和边缘情况。

它们不应该包含很多bug,但也可以发现一些。公共API不应该再发生变化。

根据语义版本学(Semantic Versioning),识别RC的模式是MAJOR.MINOR.PATCH-rc.NUMBER ,比如说2.0.0-rc.1

总结

我们已经看到了正确地对软件进行版本控制的一些方法和注意事项。

当你没有很多经验的时候,版本控制并不那么简单,但是正如你所看到的,你只需要知道一小套规则,并使用一点你的直觉。

有了这些工具,你就能正确地对你的软件进行版本管理。