修复重要错误时的语义版本控制


18

我目前管理的图书馆有很多公共用途,并且我对语义版本化有疑问。我想重构该库的一个相当重要的部分,该部分执行不正确-始终执行不正确。但是,这样做将意味着更改公共API,这是一个重大决定。

我要进行的更改围绕如何使用迭代器展开。当前,用户必须执行以下操作:

while ($element = $iterator->next()) {
   // ...
}

至少在PHP的本机Iterator接口中,这是不正确的。我要替换为:

while ($iterator->valid()) {
   $element = $iterator->current();
   // ...
   $iterator->next();
}

类似于:

foreach ($iterator as $element) {
    // ...
}

如果您查看Tom的语义版本控制指南,他清楚地指出,对公共API的任何更改(即那些向后兼容的更改)都应证明是主要版本的合理性。因此,该库将从1.7.3跳到2.0.0,对我来说,这是一个太远的步骤。我们只是在谈论一个已修复的功能。

我确实有计划最终发布2.0.0,但是我认为这是您完全重写该库并实现了许多公共API更改的时候。引入此重构是否需要发行主要版本?我真的不知道它是如何工作的-我更愿意将其发布为1.8.0或1.7.4。有人建议吗?


是什么阻止您保持向后兼容性?
mouviciel 2013年

目前,该next()方法用于检索当前元素并向前移动内部指针。哪有错 next()应该移动指针,并current()用于检索...
hohner

6
因此,在新版本中,人们不必在意next()仅是移动指针的返回值,这真的不会破坏兼容性
棘手的怪胎

Answers:


29

您犹豫是因为您不想进行语义版本控制,而是要进行“广告支持版本控制”。您期望版本号“ 2.0”告诉全世界您库中现在有很多新功能,而不是您更改了API。没关系(许多软件公司和/或开发人员都可以这样做)。恕我直言,您有以下选择:

  • 坚持语义版本控制,并坚持必须将版本号更改为2.0.0的事实
  • 将版本控制方案更改为4个数字。“ 1.1.7.3”现在是您的版本,“ 1.2.0.0”是更改API后的下一个版本,“ 2.0.0.0”是“全新2.x产品系列”的第一个版本
  • 使您的修订程序向后兼容(因此,请勿更改的功能next,只需添加validcurrent功能)。然后,您可以使用“ 1.8.0”作为下一个版本号。如果您认为更改的行为next确实很重要,请在2.0.0中进行。

最后一个选择将是一个完美的解决方案:您不能要求next()继续做它正在做的事情。为了正确实现功能,它必须做一些不同的事情。因此,如果我使它向后兼容-新功能/修复也将是错误的,并且会破坏整个更改的重点。
hohner 2013年

2
您在第三个项目符号中提出的更广泛的建议(使修复程序向后兼容)是一个不错的建议。在这种情况下可能无法使用,但是整体技术值得考虑。该功能最终变得更复杂,但这可能是可行的途径。

谢谢大家:如果我可以接受两个,我会的。我最终破解了新next()方法以实现所有新功能,以及使向后兼容所需的功能。不得不破坏这种新功能感觉很恐怖,但是,嘿。
hohner 2013年

10
@hohner:现在也该记录不推荐使用的旧行为了,因此您可以在2.0.0中将其删除。
2013年

7

坚持使用汤姆的语义版本控制指南。

对公共API的任何重大更改都必须在以下两个点之一进行:

  1. 决不
  2. 在主要版本更新中

顺便说一下,我的投票是第一位。但我承认这仅适用于琐碎的事情。

问题在于保持向后兼容性,并确保您不会破坏API以前的用户。

本质上,您正在为不知道更改的用户创建索引错误。强制进行这样的更改将强制所有用户执行以下操作:

  1. 编写修复程序以使用新方法
  2. 验证此修复程序,并确保它没有破坏任何东西
  3. 将产品的新版本发送给最终用户

这可能会花费很多精力,尤其是当您考虑为验证这样的更改而只需要几个项目的测试用例时。考虑到还需要更新其安装的用户中下游用户的数量时,工作量会增加。

对于这么小的东西,我会放任不管,不用理会。
如果它真的使您感到困扰(显然会,或者您不会问),那么我将执行以下操作。

  1. 在代码树中创建v2.0.0分支
  2. 向v2.0.0分支做出第一个贡献,即此更改
  3. Release Notes提前发送预览,广播即将发生更改

然后要耐心等待,因为需要花费一些时间来积累其他证明将版本号升级到新的主要版本的理由。高级通知(第3部分)使您有时间从最终用户那里接收反馈,以了解该更改将产生多大的影响。


另一种解决方案是添加一个新功能,该功能可以按照您想要的方式运行。

如果有的foo()话,您将创建fooCorrect()以提供修复程序,但也完全保留向后兼容性。在某些时候,您可以foo()拒绝让其他人知道不要使用它。

面临的挑战是,您将在其中找到需要对其进行更新的其他内容fooCorrect(),并且最终fooCorrectedCorrect()还是有些愚蠢的废话。

如果您现在真的想要修复此问题,那么这种替代方法可能是最好的方法。请注意并警惕以这种方式创建许多额外的功能,因为它会使API难以使用。这种意识可能足以防止此类问题中最严重的问题。

但这可能是考虑一些小问题的“最糟糕”的方法。


我同意你的看法。我面临的问题是我想完全重写v2.0.0的库(因为其中许多问题需要解决);所以我不希望像迭代器这样的小变化成为大变化的基础。因此,我的选择是:忽略此错误,或修复该错误并将其放入新的主要版本中?
hohner 2013年

@hohner-更新了答案,以提供创建新功能的替代方法。请注意,许多新的类似名称的函数几乎与更改API本身一样糟糕。

3
@hohner:始终错误>在这种情况下始终不一致。行为仍然起作用,这不是惯用行为。考虑到如果进行此更改,则会破坏客户端代码。在没有警告的情况下执行此操作将不胜感激。
Phoshi

@ GlenH7在这种情况下,将无法使用替代命名的方法。PHP的本机迭代器依赖于这些方法(即next()不是nextCorrect())。我将看看是否可以修改next(),以便它向后兼容并且在实现Iterator接口时可以正常工作。
hohner

1
@Phoshi你很高兴-我现在完全同意。现在是时候尝试编码不可能的了:D
hohner
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.