Monkeypatching是否被视为良好的编程习惯?


15

我一直在印象中,monkeypatching属于快速和肮脏的hack类别,而不是标准的良好编程习惯。虽然我不时使用修复第三方库的小问题,但我认为这是临时性的修复,因此我会向第三方项目提交适当的补丁程序。

但是,我已经将该技术用作主流项目中的“常规方法”,例如在Gevent的gevent.monkey模块中

Monkeypatching是否已成为主流,正常且可接受的编程实践?

另请参阅:杰夫·阿特伍德(Jeff Atwood)的“ Monkeypatching for Humans”


13
我要说的是所谓的猴子补丁,被认为是好的编程习惯。甚至不知道它是什么,仅凭其名称即可。
littleadv 2012年

如果第三方不想做您需要的修复该怎么办?

1
@Thorbjørn:好问题,一方面我不喜欢monkeypatching,另一方面我不喜欢克隆项目并保留本地补丁的想法,如果这只是一个小问题。
vartec

1
@littleadv:...然后将其称为“热修复” /“即时修复”或“运行时修复”,听起来不错吧?;) 这都一样。
dagnelies

3
javascript几乎是围绕这个概念构建的
ZJR

Answers:


19

不,但是有时候monkeypatch的危害较小(比破坏代码:))。我对红宝石中的猴子补丁的一般规则是:

  • 有一个非常好的猴子补丁原因(临时的关键修补程序是一个很好的原因。除非您使用ActiveSupport,否则to_s方法的格式不是很好)

  • 使它们尽可能透明:将它们放在代码库中的特定位置并分离文件,编写描述Monkeypatch原因的文档(这里是一个示例)。

  • 易于删除-文档应包含有关删除以及注意事项的信息。许多猴子补丁是临时的,因此应该易于删除。


11

是的,monkeypatching非常有用!

不知何故,名字似乎对人们的看法影响很大。称其为“ monkeypatch”,听起来很糟糕,称其为“热修复”或“即时修复”,听起来不错。

独立于此,我认为在运行时更改方法/属性/功能的功能是非常有用的。即使是javascript人,也可能整天都在不知不觉中使用它。

例如:

button.onclick = function(e) { ...}

这条简单的线说明了您更改按钮行为的事实。它是按这种方式设计的。同样,您可以更改所有其他功能,但是这样做很愚蠢。

现在,关于以这种方式交付补丁的问题……嗯……为什么不呢?您只需要下载一个小补丁而不是一个大版本。哎呀,您甚至可以在不停止服务器的情况下修补服务器,太好了!然后,有一天,您还可以获取最新版本以进行更大的更新。很公平。所以,是的,我投票赞成“运行时修补程序”是一件好事。

有趣的是,有些语言(例如Erlang)甚至是围绕这个概念而建立的。动态更新服务器的能力。

当然,最后,与其他所有内容一样,这取决于您如何使用它。您可以制作出色的OO东西和糟糕的东西,都是一样的。

编辑:

无论您是要修补自己的库还是第三方库,让我添加一些区分大小写的功能。

...基本上,您对此类补丁所做的工作是修复您自己第三方库的错误。无论哪种情况,它都很有用。就您自己而言,它使您能够即时提供修复程序。对于第三方,要么等待(几个月?),直到他们自己修复它,要么现在就自己完成。(您仍然可以向他们提交补丁,以便他们将其修复在自己的身边)。当他们发布修复了问题的下一个lib版本时,如果您要更新库并删除补丁,仍然可以。

当然,现在,如果您使用补丁程序来更改lib的行为并使其脱离工作目的/方式,那么显然这就是灾难的根源。我希望,即使是猴子也能看到。;)


1
没有人说这没有用。但是,通常这不是一个好习惯。而且“修复程序”和“即时修复”对我来说听起来并不好。
Lukas Stejskal

1
好吧,我发现即时更改应用程序行为的功能非常有用,即使是大型应用程序,其功能也更大。哎呀,您甚至可以使用将旧方法存储为备份的代码以及按需自动回滚的命令!可能性是巨大的!
dagnelies,2012年

我同意这是一个强大而有用的功能。但它也非常危险(尤其是在Ruby中),因此应格外谨慎(尤其是对标准库和第三方库的修改)。您是否曾经尝试过根据几个猴子修补的第三方库维护应用程序?每当您尝试更新某些库时,便会遇到灾难。
Lukas Stejskal 2012年

1
是的,我同意,如果您不小心使用这些补丁,以意想不到的方式使用或滥用它们,它很快就会变得混乱。就像您可以滥用任何概念或弄乱任何东西。但是,否则,如果它们井井有条且透明,并且它们都在下一个大版本中发布,那么对我来说,它看起来很干净。...但是,我没有大量修补的ruby库的经验。
dagnelies

...我对后一种情况添加了一些评论。
dagnelies

8

我相信,由于其运行时性质以及无法在设计时发现它们,因此所有补丁都具有固有的风险。

他们欢迎运行时异常,并且需要复杂的调试器和监视才能跟踪。

当人们使用SEAL类时使用它们,因此无法进行继承。但是,有更好的方法可以扩展对象而不损坏对象。

我的两分钱


4

一般而言,修补是最后的选择,猴子修补更是如此。问题主要是可维护性之一。

很久以前,我的linux内核已应用了3个单独的补丁,这对于我的视频卡驱动程序和我拥有的两个专有应用程序是必需的。他们中的两个有冲突的更改,这意味着我需要第4个补丁来解决它们之间的差异。现在,每当上游内核中解决安全问题时,我要么必须等待这3个补丁的供应商发布对新内核版本的更新,这需要一个到六个月的时间,要么我必须手动维护上游安全补丁,直到其他补丁厂商赶上来。

几年后,供应商设法将其包含在上游内核源代码中,我能够停止这种平衡,但是您可以看到它在此期间是一团糟。除非必须这样做,否则不要对您的程序员造成影响。


3

否。这不是软件开发的标准技术。它仍然是解决严重问题的解决方法,并且具有明显的缺点。我想到违反《里斯科夫换人原则》。猴子补丁使人们很难对程序进行推理。对于您自己的程序,应将代码放在其所属位置。对于第三方库,您将始终处于危险之中,即您的补丁程序无法与该库的下一版本一起使用。

当然,如果您知道自己在做什么并且没有时间实施SOLID解决方案,则猴子修补非常有用。但是你永远不要视为标准技术,并在猴子补丁上构建猴子补丁。

顺便说一句,您是否曾经为猴子补丁编写过单元测试?


我认为您不能在此处应用LSP。它具有有关子类型的非常具体的定义。
康拉德·鲁道夫2012年

@KonradRudolph猴子修补对象会更改其类型。在动态类型化语言中,与类型u具有相同接口的每个类型t都是u的子类型。如果它走路像鸭子一样……
Scarridge

“……改变其类型” –很公平。说得通。
Konrad Rudolph 2012年

RE“这不是软件开发的标准技术。”,它似乎一直都在Python中进行*一直在测试
Tommy
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.