猴子修补。固体。原则?

时间:2008-11-15 23:39:30

标签: ruby monkeypatching solid-principles

在一些个人项目中,我正在慢慢地从PHP5转向Python,我现在很喜欢这种体验。在选择沿着Python路线前,我看了Ruby。我从红宝石社区注意到的是,猴子修补既常见又备受推崇。我还遇到了一个关于调试ruby s / w的试验的很多的恐怖故事,因为有人包括一个相对无害的库来完成一些工作,但修补了一些使用频繁的核心对象而没有告诉任何人。

我选择Python(除其他原因外)其更清晰的语法以及它可以完成Ruby所能做到的事实。 Python正在使得OO点击比PHP有所改进,我正在越来越多地阅读OO原则以增强这种更好的理解。

今晚我一直在阅读Robert Martin's SOLID原则:

  • S 单一责任原则,
  • O 笔/封闭原则,
  • L iskov替代原则,
  • nterface隔离原则,
  • D 依赖性反转原则

我目前正在 O 软件实体(课程,模块,功能等)应该开放以进行扩展,但需要修改

我的头脑是在确保OO设计的一致性和整个猴子修补之间的冲突。我知道可以在Python中进行猴子修补。我也明白,“pythonic”是遵循常见的,经过良好测试的oop最佳实践&原理

我想知道的是社群对两个相反主题的看法; 他们如何互操作,当它最好使用一个时,是否应该在所有......希望你能为我解决这个问题。

8 个答案:

答案 0 :(得分:29)

猴子修补(覆盖或修改预先存在的方法)与简单添加新方法之间存在差异。我认为后者非常好,前者应该被怀疑地看待,但我仍然赞成保留它。

我遇到过很多问题,其中第三方扩展会对核心库进行monkeypatches并破坏内容,而且它们真的很糟糕。不幸的是,它们总是看起来源于第三方扩展开发人员采取阻力最小的路径,而不是考虑如何正确地构建他们的解决方案。
这很糟糕,但它不再是猴子修补的错,而不是刀具制造者的错误,人们有时会割伤自己。

我见过的唯一合法的猴子补丁需求是解决第三方或核心库中的错误。仅此一点,它是无价之宝,如果他们取消了这项工作的能力,我真的很失望。

我们的C#程序中的错误时间表:

  1. 阅读奇怪的错误报告并将问题跟踪到CLR库中的小错误。
  2. 投资日期提出了一个解决方法,涉及在陌生的地方捕获异常以及大量黑客攻击,这会严重影响代码
  3. 在Microsoft发布服务包时花费数天时间解决hacky变通办法
  4. 我们的rails程序中的错误时间表:

    1. 阅读奇怪的错误报告并将问题跟踪到ruby标准库中的小错误
    2. 花费15分钟执行小型猴子补丁以从ruby库中删除bug,如果它运行在错误版本的ruby上,则在它周围放置警卫。
    3. 继续正常编码。
    4. 稍后在下一版本的ruby发布时删除monkeypatch。
    5. 错误修正过程看起来很相似,除了monkeypatching,它是一个15分钟的解决方案,一个5秒的'提取',而没有它,疼痛和痛苦随之而来。

      PS:以下示例是“技术上”monkeypatching,但它是“道德”monkeypatching?我没有改变任何行为 - 这或多或少只是在红宝石中做AOP ......

      class SomeClass
        alias original_dostuff dostuff
        def dostuff
          # extra stuff, eg logging, opening a transaction, etc
          original_dostuff
        end
      end
      

答案 1 :(得分:5)

在我看来,monkeypatching对于拥有可以被滥用的东西很有用。人们倾向于发现它,并且觉得应该在每种情况下使用它,也许混合或其他结构可能更合适。

我不认为这是你应该禁止的事情,这只是Ruby家伙喜欢使用的东西。你可以用Python做类似的事情,但社区已采取的立场应该更简单,更明显。

答案 2 :(得分:4)

猴子补丁不是ruby-explicit,它也是通过javascript完成的,具有负(IMO)效果。

我的个人意见是猴子补丁应该只进行

a)为您需要的新版语言中提供的旧版语言添加功能。

b)当没有其他“合乎逻辑”的地方时。

有许多简单的方法可以使猴子修补非常糟糕,例如能够改变 ADDITION 等基本功能的工作方式。

我的立场是,如果可以避免,请这样做。

如果你能以一种不错的方式避免它,那就是你的荣耀。

如果你无法避免它,请得到200人的意见,因为你可能只是没有考虑到它。

我的宠物讨厌是扩展功能对象的mootools。是的,你可以这样做。而不只是人们只是学习javascript如何工作:

setTimeout(function(){ 
    foo(args); 
}, 5000 ); 

为每个函数对象添加了一个新方法(是的,我不是在开玩笑),所以函数现在有自己的函数。

foo.delay( 5000 , args );

这种废话的附加效果是有效的:

foo.delay.delay( 500,  [ 500, args ] ); 

就像无限的广告一样。

结果呢?你不再拥有一个图书馆和一种语言,你的语言鞠躬到图书馆,如果图书馆恰好在范围内,你就不再拥有一种语言了,你不能按照学习时的方式做事。语言,而不是必须学习一个新的命令子集,只是为了不让它掉在脸上(以过度减速为代价!)

我可以注意到foo.delay还返回了一个对象,它有自己的方法,所以你可以做

x = foo.delay( 500, args ); 
x.clear(); 

甚至

 x.clear.delay(10); 

这可能听起来过于有用,但是你必须考虑到使这个可行的大量开销。

 clearTimeout(x); 

太难了!

(免责声明:自从我使用moo以来已经有一段时间了,并试图忘记它,并且函数名称/结构可能不正确。这不是API参考。请查看他们的网站了解详细信息(对不起,他们的API参考很糟糕!))

答案 3 :(得分:4)

Mokeypatching通常是错误的。创建一个合适的子类并添加方法。

我在生产代码中使用了一次monkeypatching。

问题是REST使用GET,POST,PUT和DELETE。但是Django测试客户端只提供GET和POST。我已经为PUT(如POST)和DELETE(如GET)进行了monkeypatched方法。

由于Django客户端和Django测试驱动程序之间的紧密绑定,将monkeypatch支持完整的REST测试似乎是最简单的。

答案 4 :(得分:3)

你可能会发现关于Ruby的开放类和开放封闭原则的启发this discussion

即使我喜欢Ruby,我觉得猴子修补是最后的工具,可以完成任务。在所有条件相同的情况下,我更喜欢使用传统的面向对象技术,并具有多种功能编程优势。

答案 5 :(得分:2)

在我看来,猴子修补是AOP的一种形式。文章Aspect-Oriented Design Principles: Lessons from Object-Oriented Design(PDF)提供了一些关于如何将SOLID和其他OOP原则应用于AOP的想法。

答案 6 :(得分:1)

我的第一个想法是猴子修补违反了OCP,因为班级的客户应该能够期望该班级能够始终如一地工作。

答案 7 :(得分:0)

猴子修补只是简单错误,恕我直言。我没有遇到你之前提到过的开放/封闭原则,但这是我长期坚持的原则,我同意它100%。我认为猴子修补是一种更大规模的代码气味,一种编码哲学气味,就像它一样。