保持编程语言向后兼容与修复其缺陷


56

首先,是一些上下文(您大多数人仍然知道的东西):

每种流行的编程语言都有明显的演变,大多数时候都以其版本标记:您拥有Java 5、6、7等,PHP 5.1、5.2、5.3等。发布新版本可提供新的API,修复错误,添加新功能,新框架等。总而言之:很好。

但是该语言(或平台)的问题呢?如果某种语言存在问题,开发人员要么避免使用(如果可以的话),要么学习忍受它。

现在,这些语言的开发人员从使用它们的程序员那里得到了很多反馈。因此,随着时间(和版本号)的流逝,这些语言中的问题将慢慢但必定会消失,这是有道理的。好吧,不是真的。为什么?向后兼容,这就是原因。但是为什么会这样呢?请阅读以下内容,了解更具体的情况。


我可以解释我的问题的最好方法是使用PHP作为示例:

PHP被成千上万的人所喜爱和憎恨。所有语言都有缺陷,但是显然PHP是特殊的。查看此博客文章。它有很多所谓的PHP缺陷列表。现在,我不是PHP开发人员(尚未),但是我通读了所有内容,并且确定列表中的很大一部分确实是真正的问题。(并非全部,因为它可能是主观的)。

现在,如果我是积极开发PHP的人之一,那么我肯定会一一解决这些问题。但是,如果这样做,则依赖于该语言特定行为的代码将在新版本上运行时中断。用两个词概括一下:向后兼容。

我不明白的是:为什么要保持PHP向后兼容?如果我发布了修正了所有这些问题的PHP版本8,就不能在上面发出一个大警告:“不要在该版本上运行旧代码!”?

有一种叫做过时的东西。我们拥有它好多年了,而且行得通。在PHP的背景下:看看这些天来人们如何积极地劝阻这些mysql_*功能的使用(推荐使用mysqli_*PDO和PDO)。弃用工程。我们可以使用它。我们应该使用它。如果它适用于函数,为什么不适用于所有语言?

假设我(PHP开发人员)这样做:

  • 启动新版本的PHP(假设8),并修复所有这些缺陷
  • 新项目将开始使用该版本,因为它会更好,更清晰,更安全等。
  • 但是,为了不放弃旧版本的PHP,我会不断发布更新,修复安全问题,错误等。这出于我未在此处列出的原因是有道理的。这是常见的做法:例如,看看Oracle如何继续更新MySQL 5.1.x版,即使它主要关注5.5.x版。
  • 大约3或4年后,我停止更新PHP的旧版本并使其消失。很好,因为在这3或4年中,无论如何大多数项目都会改用PHP 8。

我的问题是:所有这些步骤是否合理?会很难吗?如果可以做到,那为什么不做呢?

是的,缺点是您破坏了向后兼容性。但这不是值得付出的代价吗?有好处的是,在3到4年内,您将拥有一种可解决90%问题的语言。它的名字将确保它的流行。

编辑:好的,所以当我说3或4年内人们将转向假设的PHP 8时,我没有正确表达自己的意思。我的意思是:3或4年内,如果人们开始使用PHP 8,他们将使用PHP 8。新项目。


31
对于这个特定的问题,PHP是一个糟糕的例子,因为您经常会选择使用的版本。大多数PHP站点都部署在共享服务器上,服务器的所有者在选择版本,而不是您。每个新版本都会修复很多东西(mysql_*例如,在5.5中已弃用),但是如果大多数托管服务提供商提供一个或什至两个版本(5.3是-不幸的是-仍然是大多数版本)就无关紧要了。供应商提供)。
yannis 2013年

5
...我也想你低估了,应移植的代码量,事情会打破量,第三方的依赖,以适应量等
dagnelies

12
对于每个低估向后兼容性的重要性的开发人员来说,Joel Spolsky的这篇很棒的博客帖子joelonsoftware.com/items/2008/03/17.html都是“火星人头戴式耳机”所必须的。
Doc Brown

3
而且,PHP在每个发行版中都在缓慢地弃用功能-结果很多东西中断了。不幸的是,PHP被困在一个困难的地方,在那里他们甚至很难发出弃用警告,以这种方式,开发人员将看到它们最终不会破坏站点。
蓬松的2013年

20
python 2.x => python 3.x是一种从设计精良的语言到另一种设计稍好的语言的重大突破,它具有第一方支持,可以自动更改许多不兼容的结构。在它们之间移植代码就像在两种语言之间进行更改一样容易。Py3k仍在慢慢发展。
Phoshi

Answers:


25

听起来不错,但在实践中很少见。人们非常不愿更改正在运行的代码,即使对于新的绿色项目,他们也非常不愿意从他们已经知道的语言/版本切换方式。

在任何项目的优先级列表上,更改现有的,运行良好的代码都无法“正常工作”。他们不会命令经理已经认为已经花钱的事情,而只是为了能够升级到语言或平台的较新版本,而是要命令开发人员“暂时”保留旧版本。您可以尝试通过仅在新发行版中可用的强大功能来吸引用户,但这是一场赌博,您冒着减少用户基础而没有明显的语言收获的风险。流行观点认为,很酷的现代功能很难与分散的安装基础的价格权衡,而且冒着被誉为“升级跑步机”的风险。

(显然,大多数情况不适用于业余爱好者编写的项目,只是为了自己的乐趣。但是,(这里是flamebait ...)PHP很少被黑客选择,因为首先编写它是一种乐趣。 )


65

您低估了向后兼容性的影响;您对所有活动项目将在3或4年内迁移的估计过于乐观。

假设我是一名PHP开发人员。PHP有缺陷,但是我知道如何解决这些缺陷-这就是我作为PHP开发人员获得报酬的部分原因。现在假设PHP 8出现并修复了这些缺陷,但是它不是向后兼容的。结果是:

  • 我必须花时间更新PHP 8的代码。这是我可以花时间响应客户请求,实现新功能,与竞争保持同步的时间。
  • 即使执行了此操作,也很有可能错过了一些极端情况或无法预料的兼容性问题,从而在代码中引入了错误。

鉴于此,强烈建议不要迁移到PHP 8,即使它“更好,更清晰,更安全等”。据估计,仍然有数十亿行的COBOL(!)-尽管显然有更好的技术可用,但是更新的成本以及错误的风险,根本就不值得。

其次,即使我决定迁移自己的代码,任何不平凡的应用程序都依赖于第三方库,并且不能保证第三方库会迁移。例如,Python 3于2008年12月发布,但是Django(可能是领先的Python Web框架)将近五年没有稳定的,可用于生产的Python 3支持(请参见此处此处)。


8
有大量令人惊讶的COBOL职位空缺,尤其是在较老的保险公司Oo
Chad Harrison

1
@Josh Kelley:我同意你的观点,但是我认为这些问题仅影响无法清晰地将旧代码与新代码分开的语言,例如Python,PHP,因为需要包括库和C ++(模板)。具有不同编译模型的语言(例如Java,Scala,Clojure)表明,即使两种语言在源代码级别不兼容,也可以向旧代码(例如Java)添加新代码(例如Clojure)。
Giorgio 2013年

2
我不知道该发布为单独的问题还是作为评论。但是为什么他们不能制作一种将代码迁移提升到一流概念的编程语言呢?在Java中,有一个@Deprecated批注仅会警告您。也许另一种语言实际上可以提供一个宏,用正确的新代码替换旧代码。如果您使用的是最新版本,则调用不推荐使用的代码是错误的,但是旧代码将转换为使用不推荐使用的新代码。只是吐口水”
Daniel Kaplan

7
@tieTYT-一些编程语言可以执行此操作-参见Python的2to3或Go的gofix(talks.golang.org/2012/splash.slide#68)。它当然可以帮助淘汰过时的功能,但是当语言语义发生变化时,软件可以很好地理解和更新其他软件存在一定的局限性。
乔什·凯利

3
@hydroparadise我的姨妈在银行和保险公司担任开发人员,在危机的这些日子里,她公司的一些客户决定返回 COBOL,因为软件更便宜!因此,即使是经济也会影响公司迁移到较新语言/版本的速度。
巴库里

17

您正在对人类行为做出很多假设。如果您对其进行过多更改,人们将评估您的竞争对手,因为无论如何他们都将不得不花费大量的精力进行转换。对于开源语言,人们只会使用旧版本。

以python为例。3.x已经发布了四年,但仍未被广泛采用。人们尝试将其用于全新的项目,但是我认为您低估了维护代码的工作量。

当然,大多数人并不认为python 2.x是“有缺陷的”。他们没有像php用户这样的抱怨。Php处于更加不稳定的状态,因为很多人只因为它现有的大量代码库才坚持使用它。如果您失去了向后兼容性,很多人会抓住他们一直在等待转向python的机会。


我认为您的观点很好(+1)。我认为向后兼容是一个错误的问题,尤其是对于可以使用单独的编译功能的编译语言(请参见如何将Scala和Clojure与Java或C#与C ++集成)。但是要避免新语言毕竟只是旧语言的更新版本,这对于避免分叉或人们只是迁移到另一种语言非常重要。我认为这些原因比处理遗留代码要强大得多。
Giorgio 2013年

1
@Giorgio错误的问题?告诉所有必须同时支持多种语言版本的图书馆作家。
2013年

@svick:使用单独的编译,您不需要支持不同版本的语言。请参阅例如Scala如何使用未为Scala编译的Java库。
Giorgio

9

对于PHP以外的任何语言,我都会说,是的,这绝对有道理!这正是Python切换到Python 3的过程。

但是,PHP的问题在于语言设计本身存在太多缺陷,因此您所说的“ PHP 8”将是一种完全不同的语言。并且,如果您不得不切换到其他语言,为什么还要坚持使用新的PHP,而不是使用任何现有的稳定版本?

同样,PHP社区适应新内容的速度非常慢。只要看看摆脱掉花了多长时间register_globals。自2000年以来,它一直被认为存在安全风险。直到12年后才被最终删除。另一个例子,当PHP5引入时,它是对PHP4的巨大改进,但社区并未对其进行调整。我花了4年时间,采取了大规模行动(例如GoPHP5)来开始采用。甚至没有大量向后不兼容的更改。


5

免责声明:我管理ColdFusion用户组。

ColdFusion遭受同样的问题:被很多人爱着,被很多人鄙视。此外,还有大量基于Java之前版本的FUD。ColdFusion 10于去年问世,它是一个巨大的销售商,上周我签署了测试版本11的预发布版本。此外,有两种主要的开源替代方案,一种是由JBoss支持的。

我想在CF10中实现许多新功能,但是从CF 7或8迁移可能会很困难,具体取决于代码库的大小,即将到来的项目数以及一旦执行后就必须进行回归测试的资源是最新版本。我在8和9之间遇到了一些小的语法差异,以及代码无法以相同方式编译的极端情况。一旦找到,我会将它们记录在我们的编码标准中,这样它们就不会在以后的项目中或新开发人员中使用。

就是说,如果ColdFusion 11(或任何编程语言)要完全弃用某些功能和语法,那么查找和替换功能的工作量可能是巨大的。测试工作可能非常庞大。公司是否会付钱给开发人员,质量检查人员和项目经理以查找,替换和测试所有已弃用的东西?疑。

如果该语言的最新版本向后兼容,但在不更改代码的情况下提高了性能(CF9比CF8快30%,CF10比CF9快得多),谁在乎是否仍可更改函数调用?

作为一家公司,我们必须担心要取悦我们的客户并满足他们的需求才能开单服务,发展业务并招募更多客户。

FWIW,我很想在某个时候将我们带到最新版本的jQuery,但是由于某些功能在使用后已经过时了,并且考虑到系统中已有的JavaScript数量,因此不推荐使用某些版本。我们将实现这一目标。


4

这里需要权衡;有些错误确实需要修复,但是某些事情如果不破坏某人的代码就无法更改。我似乎记得有人说过“规则”,即每个错误修正都会破坏某人的项目,无论该错误有多晦涩或破损,有人都会将其用于某事。这就是程序员的本性。

(在我看来)这是主要发行版,次要发行版和修订版之间的差异。作为一般原则:

  • 假定主要版本包含重大更改。
  • 次要释放可能会稍微改变行为。
  • 修订应该是几乎相互兼容的。

例如,如果我正在用v2.3语言编写某些内容,那么升级到v2.3.2不会有任何区别。如果我升级到v2.4,则可能会发生一些变化-小语法调整,某些功能的行为会有所不同,因此我必须调整逻辑,等等。如果升级到v3.0,如果它崩溃了,我不会感到惊讶完全是-不推荐使用或缺少的功能,不支持或更改的操作太多,以至于我不能仅仅将其调整回行,实际上我必须重写一些功能以应对新的更改。

编辑:

史蒂夫·万斯(Steve Vance)的论文《高级SCM分支策略》说:

通常,有两到三个释放级别,由与周期相关的数字命名(例如1.2.3)。[...]在此结构中,第一个数字与主要版本相关联,表示它具有相对于先前版本的显着功能和功能增强;还可能存在需要迁移的重大不兼容性。第二个数字代表次要版本,其中包含较少的功能和功能增强,大量的错误修复,并且没有不兼容性。第三个数字表示补丁程序级别,几乎仅表示错误修复的集合;补丁级别之间不允许任何功能增强,也不兼容。

我对此所做的唯一更改是上述原则,即程序员通常会找到“使用”错误的方法,因此带有“大量错误修复且没有不兼容性”的次要版本可能会很困难,因为这些错误会破坏使用它们的东西,或者将导致不必要的解决方法并开始引起问题。


我希望2.3-> 2.4可以添加功能,但不能删除它。
Donal Fellows 2013年

1
巧合的是,我最近遇到了一个相关的报价。评论时间有点长,所以我将编辑答案。
anaximander

2

它实际上取决于语言的目标-语言打算使用哪种类型的应用程序。

例如,忽略Android,Java主要用于大型企业系统和中间件。这些类型的应用程序在大小和时间上都会变得非常大。这有一些含义。设想一个具有500K + LoC的系统,在开发阶段,该系统上的50名工人是工程师。通常,这种类型的系统需要10个开发人员才能进入维护阶段;现在,如果语言更改且更改不向后兼容,则由于编写了某些部分的程序员已经消失了,没有人愿意触摸它,因此无法轻松地将项目迁移到新版本。这是一个较小的问题,较大的问题在于,要使500 LoC应用程序适应新的语言约束是种昂贵的事实。例如,如果泛型不是使用类型擦除和List list = new List(); 不会编译成百万行的代码就需要重写-这是很大的代价。

另一方面,PHP倾向于在网络上用于更简单的应用程序。通常它是由一个程序员或一个小团队开发的。这个想法是,开发人员非常了解整个项目,可以更轻松地集成语言更改。同样,它的目的是非常快速地构建站点,并且速度越快越好,因此,如果新的语言功能可以做得更好,那么即使以一些向后兼容的代价也可以实施它。


1

可以说微软通过ASP.NET(作为经典ASP的后继产品)或VB.NET(尽管后者做出了很多让步,以至于“重新启动”该语言的大部分好处都丧失了)而进行了类似的更改。

无论如何,如果有人记得即使借助迁移工具将VB6代码迁移到VB.NET的噩梦,他们也会立即同意,语言迁移工具对于主要的语言更新效果不佳。

可能有可能使平台向前发展,但是,您仍应至少通过一些修订为“不推荐使用的” API提供支持。


1

人们在流行的编程语言中尖叫的许多“缺点”并不是,它们是当今尖叫者最喜欢的玩具所缺少的语言,因此语言从根本上存在缺陷,因为它缺乏语言。
下一个炒作出现了,该语言突然出现缺陷,因为它不遵守那种炒作。

Java中缺少闭包就是一个典型的例子。这根本不是语言上的缺陷,更改语言(令人遗憾地在议程上)以包括这些语言将使IMO从根本上削弱它,或者至少使它变得难以阅读和理解。

太多的人看不见的是,每种语言都有其长处和短处,试图创造一种结合了所有优点的东西,同时又避免了每一个缺点,只会造就一个完全无法使用的怪物,该怪物无能为力,难以置信地挥舞着,不可能有效利用。

另外,正如其他人指出的那样,向后兼容性对于保留现有用户至关重要,其中许多人不会花费数千小时和数百万美元/欧元来将其数百万行代码库改造为您认为“更好”的东西。而不是他们多年来使用的语言版本,并且您有很多很好的论据可以让自己保持足够的独立性,如果您想使用一些新的夸张的想法,那可能是下一个“ java杀手”, d最好与该玩具一起玩,而不是尖叫“ Java iz ded”,除非它“固定”为该玩具的克隆。


1

我建议,该语言的新版本应努力确保在新旧版本的语言中编译的99.99999%的代码在这两种语言中均应相同工作,除非故意设计成不这样做,并且在大多数情况下当新版本拒绝在旧版本下编译的代码时,这是因为该代码(最好)是模糊的,并且应该以可以在新旧编译器下进行编译的不同方式编写。

例如,如果我正在设计一种类似于Java或C#的新语言,则在某些语言允许的情况下,我将禁止隐式类型转换。作为C#中的一个简单示例,给出了

int someInt;
double someDouble;

someInt.Equals(someDouble)无论变量的内容如何,表达式均保证返回false。它之所以double进行编译是因为可以将其转换为Object,并且对该类型int具有Equals重载,因此编译器会进行转换并进行调用。在设计C#和.NET Framework的新版本时,我希望它禁止装箱转换,因为它可能无法做任何有用的事情。可能有一些程序以无用但无害的方式进行了这样的比较,并且让编译器拒绝此类代码可能会破坏该程序,但是更正或删除此类无用的代码将是一个改进。

作为一个不太清楚的例子,假设

float f=16777216f;
int i=16777217;

并考虑一下表达式f==i。这可能是一些代码确实漂浮/整数比较和工作正常,但代码应重写为f==(float)i(double)f==i;(double)f==(double)i;[ intdouble推广是无损的,所以后两者将是等效的。其中比较直接一些代码floatinteger值可能总是与足够小,使得数字处理floatdouble比较会表现相同,但一个编译器一般不能知道; 代码应该明确需要进行哪种比较,而不是希望语言规则会符合程序员的意图。


1

最好不要破坏向后兼容性。

Microsoft用一种完全破坏了兼容性的新语言替换了VB6编程语言。因此,即使是今天,使用16年的VB6仍然比dotNet版本(2014年8月的Tiobe索引)更受欢迎。Gartner估计仍有140亿行VB6代码正在使用中。

在2014年,Microsoft再次不得不宣布,尽管Visual Basic编程社区提出了要求,他们将不会更新或开源VB6。但是他们已经将对VB6的支持扩展到“至少”到2024年,并且在Windows 7和Windows 8上都可以正常工作。对同一版本的VB6的支持将超过26年。

为什么即使Microsoft从不“更新” Office以使用dotNet,也必须重写现有的工作软件?


这似乎并没有提供超过先前14个答案的实质性内容
t

1

破坏向后兼容性存在一些不同的问题。一些问题源于大多数编程语言也是平台(解释器/运行时)的事实,其他问题源于对人性的假设。

答:用较旧版本编写的代码无法获得改进性能,安全性或功能的新版本的好处。您可以通过支持多个主要版本的编译器/解释器来缓解此问题,但这是一个巨大的资源消耗(即,它昂贵或花费很长时间,并且很麻烦)。

B.为较新版本编写的代码可能与较旧版本编写的代码不兼容。您可以通过拥有可以处理该语言的多个主要版本的解释器/编译器来解决此问题,但这比支持单独的解释器/编译器(A的变通方法)更麻烦。

C.重大更改(如果更改频繁/快速)也会使该语言更难使用,因为您有更多的知识要学习和学习。对语言的更改可能会迫使人们过度使用新语言,或者可能导致人们继续使用该语言的过时版本,而永远不会切换到新版本(就像python一样)。再者,这些变化也可能吸引新用户并激发旧用户。

D.需要保留和维护新的文档。在Google上查找内容并发现您正在阅读的文档版本与当前使用的版本不同总是一种令人困惑的体验。

总的来说,如果您创建了一种无需外部模块在乎您使用哪个版本的编程语言,那么出于正确的原因(修复该语言的主要缺陷)打破向后兼容性几乎绝对是正确的选择。 。不能做到这一点的主要原因可能是编程语言设计人员高估了与其他人的回答相抵触)破坏兼容性的成本,尤其是在早期。事实是,破坏兼容性的问题可以由该语言的用户解决或解决。这不仅适用于编程语言;这适用于API,用户界面-实际上是任何情况下的任何界面。

Facebook在更改其UI或开发人员API时会惹人讨厌。过去,它使平台难以使用。在某些情况下,API只是突然停止工作。但是人们一直在使用它,现在API和UI比5年前有了更大的飞跃。人们会抱怨变化对他们有利还是不利,但是(抱怨)不是放弃这种变化的好理由。不幸的是,编程语言开发人员将其用作保持其语言问题完整的原因。

因此,语言无法做出重大改变来提高自身的另外两个原因是:

E.语言开发人员认为他们的用户担心更改是停滞其语言的一个很好的理由

F.语言开发人员在制作语言时就喜欢他们的语言,他们可能认为它的缺陷还不错。

G.随着语言的发展,它们通常不再具有少数核心开发人员,而变成了更多由委员会建造的野兽。这意味着有关这些语言的决定很慢,而且常常是保守和不创意的。

H.最后一个原因是某些重大更改需要对解释器/运行时做出的设计决策进行大量重新评估。有时,对语言的改进只需要太多工作就不可行。我想这是比大多数问题更罕见的问题。

语言设计师通常不一定是工具设计师,因此他们没有想到解决此问题的好方法,或者执行得不好。这是我可以想到的一些解决突破性问题的解决方案:

  1. 在将它们删除之前,先不推荐使用它们。

  2. 提供良好的标准转换器工具。Python提供了2to3工具,但它的广告宣传不佳,正如我记得的那样,它不是python 3的标准,甚至还不能很好地工作(我记得必须手动检查2to3生成的程序才能解决问题)没有解决)。如果您的编译器/解释器检测到旧版本,则甚至可以自动运行此转换器工具。有什么会更容易?


Facebook类比的问题在于没有使用Facebook传统。别无选择。您要么使用当前版本的Facebook,要么根本不使用Facebook。同时,由于Python 2该版本Python 3仍然存在,因此仍有七成的人们在使用它,因为它仍然存在-如果不存在,他们会抱怨,但他们会移植到Python 3
凯文

我认为类推并不是问题,这实际上是我的意思。Facebook选择了“修复缺陷”路线,并且大多避开了“向后兼容”路线。这就是为什么他们没有旧版API的原因。这是一个极端的完美例子。
英国电信

打破编程语言的向后兼容性只会导致人们继续使用和/或分叉旧版本。Facebook的旧版本已不存在。我想您可以创建一个支持旧API的克隆,但没人会使用它,因为Facebook是一个拥有庞大用户群的品牌。
凯文

Facebook的优势在于,当更新时,以前的版本基本上不再存在。编程语言并非如此,这是一个相关的差异-您可以使用编程语言的过时版本,例如Python 2,因为它仍然存在。
凯文

我明白你的意思。我仍然认为这是两个极端的终结。如果某语言的不受支持版本中的主要缺陷变得明显,则可能是因为该版本不再存在,因为没有人愿意使用它。
英国电信

0

我不知道这对PHP代码来说不是问题,但是在许多古老的语言中,遗留代码永远不会在数年或数十年后进行更新,因为它可以正常工作,这对于运行它的企业至关重要,而且规模太大(例如数百万个SLOC),因此将其重写是没有意义的。这就是为什么尽管已知旧问题,尤其是在库中(即使它们更容易更新),Java却将向后兼容性变成几乎是宗教问题的原因。我猜想,尽管采用了C99和C11之类的标准,但是Linux内核中的许多代码也没有更新数十年。

即使在“企业”较少的语言中,打破古老的功能代码也可能是一个问题。这就是Python 2-> 3的情况。一大堆库和系统脚本是稳定的,不再维护了,不是因为它们被抛弃而是因为它们稳定并且正在工作。适应它们需要几年。因此,作为开发人员,如果您最喜欢的库尚未采取行动,则不一定要跳到python 3,因此您自己的代码也无法在python 3下工作,从而导致社区分散。


-1

问题出在向后兼容性问题之内。我执行的大多数PHP脚本都在较旧的RedHat服务器上运行。如果要在以后的脚本中使用该语言的较新版本,则必须在该服务器上更新PHP-并冒着使旧脚本损坏/不得不花费数小时来重写所有旧代码的风险。新标准。另外,我所有的开发人员都习惯于PHP以某种方式做出反应(无论这种方式是否“中断”)。如果它不再以这种方式做出反应,则可能会成为提高生产力的主要障碍,因为开发人员可能不得不从根本上重新学习PHP。

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.