Monkey-patching Vs. S.O.L.I.D. principles?

不打扰是莪最后的温柔 提交于 2019-12-18 10:34:36

问题


I'm slowly moving from PHP5 to Python on some personal projects, and I'm currently loving the experience. Before choosing to go down the Python route I looked at Ruby. What I did notice from the ruby community was that monkey-patching was both common and highly-regarded. I also came across a lot of horror stories regarding the trials of debugging ruby s/w because someone included a relatively harmless library to do a little job but which patched some heavily used core object without telling anyone.

I chose Python for (among other reasons) its cleaner syntax and the fact that it could do everything Ruby can. Python is making OO click much better than PHP ever has, and I'm reading more and more on OO principles to enhance this better understanding.

This evening I've been reading about Robert Martin's SOLID principles:

  • Single responsibility principle,
  • Open/closed principle,
  • Liskov substitution principle,
  • Interface segregation principle, and
  • Dependency inversion principle

I'm currently up to O: SOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.) SHOULD BE OPEN FOR EXTENSION, BUT CLOSED FOR MODIFICATION.

My head's in a spin over the conflict between ensuring consistency in OO design and the whole monkey-patching thing. I understand that its possible to do monkey-patching in Python. I also understand that being "pythonic" is to follow common, well-tested, oop best-practices & principles.

What I'd like to know is the community's opinion on the two opposing subjects; how they interoperate, when its best to use one over the other, whether the monkey-patching should be done at all... hopefully you can provide a resolution to the matter for me.


回答1:


There's a difference between monkey-patching (overwriting or modifying pre-existing methods) and simple addition of new methods. I think the latter is perfectly fine, and the former should be looked at suspiciously, but I'm still in favour of keeping it.

I've encountered quite a few those problems where a third party extension monkeypatches the core libraries and breaks things, and they really do suck. Unfortunately, they all invariably seem stem from the the third party extension developers taking the path of least resistance, rather than thinking about how to actually build their solutions properly.
This sucks, but it's no more the fault of monkey patching than it's the fault of knife makers that people sometimes cut themselves.

The only times I've ever seen legitimate need for monkey patching is to work around bugs in third party or core libraries. For this alone, it's priceless, and I really would be disappointed if they removed the ability to do it.

Timeline of a bug in a C# program we had:

  1. Read strange bug reports and trace problem to a minor bug in a CLR library.
  2. Invest days coming up with a workaround involving catching exceptions in strange places and lots of hacks which compromises the code a lot
  3. Spend days extricating hacky workaround when Microsoft release a service pack

Timeline of a bug in a rails program we had:

  1. Read strange bug reports and trace problem to a minor bug in a ruby standard library
  2. Spend 15 minutes performing minor monkey-patch to remove bug from ruby library, and place guards around it to trip if it's run on the wrong version of ruby.
  3. Carry on with normal coding.
  4. Simply delete monkeypatch later when next version of ruby is released.

The bugfixing process looks similar, except with monkeypatching, it's a 15 minute solution, and a 5-second 'extraction' whereas without it, pain and suffering ensues.

PS: The following example is "technically" monkeypatching, but is it "morally" monkeypatching? I'm not changing any behaviour - this is more or less just doing AOP in ruby...

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



回答2:


In my view, monkeypatching is useful to have but something that can be abused. People tend to discover it and feel like it should be used in every situation, where perhaps a mixin or other construct may be more appropriate.

I don't think it's something that you should outlaw, it's just something that the Ruby guys like to use. You can do similar things with Python but the community has taken the stance that things should be simpler and more obvious.




回答3:


Monkey patching is not ruby-explicit, its done all over javascript too, with negative (IMO) effects.

My personal opinion is monkey patching should only be done to

a) Add functionality to an old version of a language which is available in the new version of the language which you need.

b) When there is no other "logical" place for it.

There are many many easy ways to make monkey patching really awful, such as the ability to change how basic functions such as ADDITION work.

My stance is, if you can avoid it, do so.

If you can avoid it in a nice way, kudos to you.

If you can't avoid it, get the opinion of 200 people because you probably just have not thought about it hard enough.

My pet hate is mootools extending the function object. Yes, you can do this. Instead of people just learning how javascript works:

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

There was added a new method to every function object, ( yes, im not joking ) so that functions now have their own functions.

foo.delay( 5000 , args );

Which had the additional effect of this sort of crap being valid:

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

And on like that ad infinitum.

The result? You no longer have a library, and a language, your langauge bows to the library and if the library happens to be in scope, you no longer have a language, and you cant just do things the way that they were done when you learn the language, and instead have to learn a new subset of commands just to not have it fall flat on its face ( at the cost of excessive slowdowns! )

may i note that foo.delay also returned an object, with its own methods, so you could do

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

and even

 x.clear.delay(10); 

which may sound overly useful, ... but you have to take into consideration the massive overhead used to make this viable.

 clearTimeout(x); 

SO HARD!

(Disclaimer: its been a while since I used moo, and have tried to forget it, and function names/structure may be incorrect. This is not an API reference. Please check their site for details ( sorry, their API reference sucks! ))




回答4:


Mokeypatching is generally wrong. Create a proper subclass and add the methods.

I've used monkeypatching once in production code.

The issue is that REST uses GET, POST, PUT and DELETE. But the Django test client only offers GET and POST. I've monkeypatched methods for PUT (like POST) and DELETE (like GET).

Because of the tight binding between Django client and the Django test driver, it seemed easiest to monkeypatch it to support full REST testing.




回答5:


You may find enlightening this discussion about Ruby's open classes and the Open-Closed Principle.

Even though I like Ruby, I feel monkey-patching is a tool of last resort to get things done. All things being equal, I prefer using traditional OO techniques with a sprinkle of functional programming goodness.




回答6:


In my eyes, monkey-patching is one form of AOP. The article Aspect-Oriented Design Principles: Lessons from Object-Oriented Design (PDF) gives some ideas of how SOLID and other OOP principles can be applied to AOP.




回答7:


My first thought is that monkey-patching violates OCP, since clients of a class should be able to expect that class to work consistently.




回答8:


Monkey-patching is just plain wrong, IMHO. I've not come across the open/closed principle you mention before, but it's a principle I've long held myself, I agree with it 100%. I think of monkey-patching as a code-smell on a larger scale, a coding-philosophy-smell, as it were.



来源:https://stackoverflow.com/questions/293236/monkey-patching-vs-s-o-l-i-d-principles

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!