|
|
|
|
||||||
![]() |
|
|
LinkBack | Outils de la discussion |
|
|
#1 |
|
Messages: n/a
Hébergeur: |
Hi folks,
I wrote a blog post with the intentionally provocative title above, which can be found here: http://avdi.org/devblog/?p=18 While the title is a bit of deliberate hyperbole, I am genuinely troubled about the popularization of monkey patching in the Ruby community. I explain my reasons more thoroughly in the post, but here's a synopsis: Monkeypatching has become the hip thing to do in the Ruby and (especially?) Rails communities, and it has reached the point where experienced programmers are turning to it as the tool of first resort *even* when there is a simpler, more traditional solution available. I suggest that it's time for Ruby hackers to start setting a better example. My hope with this post is to start a conversation about fostering robust software extension mechanisms in the Ruby ecosystem. I welcome any comments, both here and on the blog. -- Avdi P.S. Before anyone accuses me of it, yes, this is a kind of self-promotion. But I really do want to start a conversation about this, and no one reads my blog. |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
On Sun, Feb 24, 2008 at 06:07:36AM +0900, Avdi Grimm wrote:
> Hi folks, > > I wrote a blog post with the intentionally provocative title above, > which can be found here: > > http://avdi.org/devblog/?p=18 [...] > My hope with this post is to start a conversation about fostering > robust software extension mechanisms in the Ruby ecosystem. I welcome > any comments, both here and on the blog. I read the post. I think it is both futile and wrongheaded. Futile, because I don't think it will change anyone's opinion. Wrongheaded, because I think it's a filtering problem rather than an approach problem. For any community of open source software, there will be lots of code released. A lot of it will be crap. Consider CPAN; it's full of implementations and reimplementations of the same APIs, functionality, and bindings to C libraries. Some of the packages are good, but a lot of them are crap. How do you tell the crap from the good? That's a filtering problem. Trying to get people to only release good code is utterly futile. So you had a problem with UnitRecord. Its code smelled bad to you. You reimplemented the functionality in NullDB in a way that doesn't smell as bad. Assuming it works equally well (I haven't had occasion to use either), there are now two implementations of the same functionality, one of which is, for some metric, better than the other. Should the worse one never have been written/released? What a silly thought. Even if it shouldn't have been, there's no means to control it (nor should there be, in my opinion). Furthermore, would you have thought to write your "better" implementation if the "worse" implementation hadn't been there as an example? Maybe, maybe not. There's an argument, usually in the context of test-driven development, for doing the simplest thing that works. Well, you say, it doesn't work. No, it *no longer* works for your purposes. That's when you need to revisit it. If a piece of code implementing functionality you need is causing problems, you need to either fix it or find/build a new implementation of that functionality. Monkey patching can cause problems, but it makes it easy to get things working quickly. There's a lot of value in that. Until it breaks, it's a win. When and if it breaks, it's time to fix or replace it. This is true of any number of other techniques (e.g. relying on Rails-generated SQL until there are performance problems). So don't lament that people are using this tool to increase their productivity, and that it sometimes gets in the way of your productivity when you reuse their code. Rejoice that someone thought of useful functionality and implemented it for you, and fix/replace it if it doesn't suit your needs. If you are dedicated to never releasing code that includes monkey patches, more power to you. Don't expect anyone else to follow that lead. As a side note, I had a knee-jerk reaction to ignore the entire post when you brought up dependency injection and robustness. It shows a very enterprisey (in the worse possible way) perspective. You and your team were capable of figuring out and fixing your problems. Your reaction to a hard problem should not be to promote "practices" to make it easier for less capable programmers; it should be (as it was with NullDB) to solve the problem and release your solution for everyone's benefit. > Avdi --Greg |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
On Sat, Feb 23, 2008 at 4:38 PM, Gregory Seidman
<gsslist+ruby@anthropohedron.net> wrote: > I read the post. I think it is both futile and wrongheaded. Futile, because > I don't think it will change anyone's opinion. Wrongheaded, because I think > it's a filtering problem rather than an approach problem. Thanks for reading it! I appreciate your feedback. > are crap. How do you tell the crap from the good? That's a filtering > problem. Trying to get people to only release good code is utterly futile. I want to make it clear that I never called for only releasing good code, or for some kind of control over what kind of code is released. 80% of everything will always be crap; but there's still value in setting a good example. > There's an argument, usually in the context of test-driven development, for > doing the simplest thing that works. Well, you say, it doesn't work. No, it > *no longer* works for your purposes. That's when you need to revisit it. If > a piece of code implementing functionality you need is causing problems, > you need to either fix it or find/build a new implementation of that > functionality. I think there's a misunderstanding here - I used the example I did because it was a case where the initial solution was *not* the simplest thing that could possibly work. I obviously cannot speak for Dan's thought process, but to me it appeared an example of having gotten into the habit of always reaching for the monkey wrench (if you'll excuse the pun) first, even when it's not the most pragmatic tool. Whether or not this was the case with UnitRecord, it is definitely an attitude I've seen more and more lately. It's this habit that I'm trying to combat, because I think a lot of times monkey patching not only hurts productivity in the long term, it hurts it in the short term too. Monkey patching is *not* always the shortest distance between two points. It's tricky and prone to subtle bugs. I do not agree that monkey patching is usually the quick & dirty solution - often it's the slow & dirty solution. Unfortunately, along with the assumption that monkey patching is the easiest way to get things done comes the assumption that if anyone wants to extend your code they can always monkey patch, so there's no point providing extension points. Again, thanks for the alternate point of view. -- Avdi |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
[Note: parts of this message were removed to make it a legal post.]
On Sat, Feb 23, 2008 at 3:07 PM, Avdi Grimm <avdi@avdi.org> wrote: > Hi folks, > > I wrote a blog post with the intentionally provocative title above, > which can be found here: > > http://avdi.org/devblog/?p=18 > I don't agree with the title, but I agree almost everything you said. When I first starting using ruby a few years ago, I thought the idea "monkey patching" was a very powerful and useful technique. Later, I came to the same conclusions as you. I know we are in the minority. I believe that "monkey patching" in packages can easily kill interoperability with other packages. I think this comment of yours hits the nail on the head: "And this is really the point. Monkey patching is the new black. it's what all the hip kids are doing. To the point that smart, experienced hackers reach for a monkey patch as their tool of first resort, *even when a simpler, more traditional solution is possible*." So true. Here are a couple cases I can think of people doing "monkey patching" and the alternative traditional solution: * adding new (or perceived missing) functionality (methods) to a class. The traditional solution would be to just inherit from the class and use the derived class instead where you want this new functionality. Since you can't inherit from some classes (i.e. immediates, a problem with the language IMHO), you can instead use something like Forwardable instead. * adding #to_* methods to String. A single letter is quite common for the * which can make a collision all the more likely. The more encapsulated solution would be to class method for creating one of these objects from a String (i.e. klass#from_s(s)). Every case I thought that I needed "monkey patching", I've found a relatively simple solution. I usually only do monkey patching in the following cases which have no reuse: top-level script, testing, and quick hacking. Eric |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
On Sat, Feb 23, 2008 at 5:23 PM, Eric Mahurin <eric.mahurin@gmail.com> wrote:
> I don't agree with the title Like I said at the beginning of the article, neither do I ;-) > * adding new (or perceived missing) functionality (methods) to a class. The > traditional solution would be to just inherit from the class and use the > derived class instead where you want this new functionality. Since you > can't inherit from some classes (i.e. immediates, a problem with the > language IMHO), you can instead use something like Forwardable instead. Indeed. The irony here is that Ruby is perhaps the easiest language in the world to implement delegation in. I'm planning on writing a series of posts on alternatives to monkey patching, and delegation is going to be one of the first techniques I talk about. > Every case I thought that I needed "monkey patching", I've found a > relatively simple solution. I usually only do monkey patching in the > following cases which have no reuse: top-level script, testing, and quick > hacking. Quite. I have no objection to monkey patching in those contexts, assuming that it really IS the easiest solution. Thanks for the reply! -- Avdi |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
[Note: parts of this message were removed to make it a legal post.]
On Sat, Feb 23, 2008 at 4:36 PM, Avdi Grimm <avdi@avdi.org> wrote: > On Sat, Feb 23, 2008 at 5:23 PM, Eric Mahurin <eric.mahurin@gmail.com> > wrote: > > * adding new (or perceived missing) functionality (methods) to a class. > The > > traditional solution would be to just inherit from the class and use > the > > derived class instead where you want this new functionality. Since you > > can't inherit from some classes (i.e. immediates, a problem with the > > language IMHO), you can instead use something like Forwardable instead. > > Indeed. The irony here is that Ruby is perhaps the easiest language > in the world to implement delegation in. I'm planning on writing a > series of posts on alternatives to monkey patching, and delegation is > going to be one of the first techniques I talk about. > Here are the main alternatives I use (in order): * put the functionality elsewhere. The simplest example is instead of monkey-patching String#to_xyz, make XYZ::from_s. When your new class wants some interaction with a built-in class, put the functionality in the new class instead of monkey-patching it into built-in class. The monkey patching approach usually just saves you a few characters when using the new functionality. I do this 95% of the time where others might monkey-patch. * inherit the class where you want additional functionality and use the derived class instead. * use delegation if inheritance doesn't work (immediates). Delegation is basically just a "has-a" implementation of "is-a" (inheritance), but it gives a little more flexibility. I've never really had to use this when I was tempted to monkey-patch. It would be an interesting exercise to go through some of the ruby stdlib and show alternatives to monkey-patching. Eric |
|
|
|
#7 |
|
Messages: n/a
Hébergeur: |
* Eric Mahurin (eric.mahurin@gmail.com) wrote:
> I believe that "monkey patching" in packages can easily kill > interoperability with other packages. Anyone remember the Chainsaw Infanticide Logger Manuever? ActiveSupport hacked into logger.rb to remove formatting, which was really nice when you wanted to use ActiveRecord in something outside Rails. And let's not mention the scary hacking of require. Let's just say.. I don't use Active* in any of my !Rails projects any more. -- Thomas 'Freaky' Hurst http://hur.st/ |
|
|
|
#8 |
|
Messages: n/a
Hébergeur: |
Avdi Grimm wrote:
> Hi folks, > > I wrote a blog post with the intentionally provocative title above, > which can be found here: > > http://avdi.org/devblog/?p=18 > > While the title is a bit of deliberate hyperbole, I am genuinely > troubled about the popularization of monkey patching in the Ruby > community. I explain my reasons more thoroughly in the post, but > here's a synopsis: > > Monkeypatching has become the hip thing to do in the > Ruby and (especially?) Rails communities, and it has > reached the point where experienced programmers are > turning to it as the tool of first resort *even* when there > is a simpler, more traditional solution available. I > suggest that it's time for Ruby hackers to start setting a > better example. > > My hope with this post is to start a conversation about fostering > robust software extension mechanisms in the Ruby ecosystem. I welcome > any comments, both here and on the blog. > One of my friends once passed this little quotation on to me: "Always code as if the person who will maintain your code is a violent psychopath who knows where you live." |
|
|
|
#9 |
|
Messages: n/a
Hébergeur: |
Rails != Ruby
The same is valid for the communities. The communities only partially overlap. I know many that do not use rails. I know many that do use rails. It is frustrating to try to read a blog that claims monkey patching is destroying ruby when in actuality the author meant Rails. And I do not care about rails either way (positive or negative) so it hardly interests me ... -- Posted via http://www.ruby-forum.com/. |
|
|
|
#10 |
|
Messages: n/a
Hébergeur: |
On Sat, Feb 23, 2008 at 7:13 PM, Marc Heiler <shevegen@linuxmail.org> wrote:
> It is frustrating to try to read a blog that claims monkey patching is > destroying ruby when in actuality the author meant Rails. No, I meant ruby. I have been coding in Ruby for ~7 years, since long before Rails appeared. At work I'm the first to correct people when they make a comment about "Ruby" when they really are talking about a Rails-specific feature. Yes, I used a Rails example. And I suspect that it's true that the phenomenon is more prevalent in in the Rails community than in the wider Ruby community. But for better or worse the majority of Ruby code being written today is being written for Rails, and the Ruby coders of tomorrow are cutting their teeth in the Rails community. Rails cultural problems will, increasingly, be Ruby cultural problems. -- Avdi |
|
|
|
#11 |
|
Messages: n/a
Hébergeur: |
SSBjYW4gc2F5IHRoYXQgSSBhZ3JlZSB3aXRoIGFsbCBwaWVjZX Mgb2YgeW91ciBhcnRpY2xlLiBU
aGlzIGlzc3VlIGlzCm5vdCByZWxhdGVkIHRvIHJhaWxzIGNvbW 11bml0eSwgaXQncyBydWJ5IHBy b2dyYW1tZXJzIGlzc3VlIChidXQgb2YKY291cnNlIHRoZXJlIG FyZSBwcm9ncmFtbWVycyB0aGF0 IG5vdCBtYWtlIHN1Y2ggYSBtaXN0YWtlcykuIFRoZSBzYW1lCm dvZXMgd2l0aCB1c2luZyBtb2R1 bGVzIGFzIG1peGlucyB3aGVuIHRoZXJlIHNob3VsZCBiZSB1c2 VkIGRlbGVnYXRpb24Kb3IgaW5o ZXJpdGFuY2UgYW5kIG1hbnkgb3RoZXIgdGhpbmdzLiBJIHNheS B0aGF0IFJ1YnkgaXMgdmVyeSBz aGFycAprbmlmZS4gSXQncyB2ZXJ5IHBvd2VyZnVsIGJ1dCB5b3 UgbXVzdCBrbm93IGhvdyB0byBv cGVyYXRlIHdpdGggaXQgdG8Kbm90IGh1cnQgeW91cnNlbGYuCg oKLS0gClJhZG9zs2F3IEJ1s2F0 CgpodHRwOi8vcmFkYXJlay5qb2dnZXIucGwgLSBt82ogYmxvZw o= |
|
|
|
#12 |
|
Messages: n/a
Hébergeur: |
On Feb 23, 2008, at 6:56 PM, M. Edward (Ed) Borasky wrote:
> One of my friends once passed this little quotation on to me: > > "Always code as if the person who will maintain your code is a > violent psychopath who knows where you live." Truly wonderful. If there were a poster of that available, I'd buy it and hang it where I could see it when I look up from my screen. You didn't make an attribution, so I presume you don't know who originated it. Too bad. Regards, Morton |
|
|
|
#13 |
|
Messages: n/a
Hébergeur: |
Oh bother. If it ain't the Duck, it's the Monkey.
No. It's not the Monkey, or the Duck that's killing Ruby... It's the Peoples. T. |
|
|
|
#14 |
|
Messages: n/a
Hébergeur: |
On Sat, Feb 23, 2008 at 8:08 PM, Trans <transfire@gmail.com> wrote:
> Oh bother. If it ain't the Duck, it's the Monkey. > > No. It's not the Monkey, or the Duck that's killing Ruby... It's the > Peoples. In other words, it's the hairless monkeys (I'm one of them .Todd |
|
|
|
#15 |
|
Messages: n/a
Hébergeur: |
> http://avdi.org/devblog/?p=18
> Monkeypatching has become the hip thing to do in the > Ruby and (especially?) Rails communities, and it has > reached the point where experienced programmers are > turning to it as the tool of first resort *even* when there > is a simpler, more traditional solution available. I > suggest that it's time for Ruby hackers to start setting a > better example. I don't know what "Aspect Oriented Programming" (and please don't try the standard explanations - they don't work on me, any more than "OO is about modeling the Real World in objects..."). I want this: module MyModule class ::String def inspect return 'shock the monkey' end end end I want .inspect, or whatever, outside my module, to behave normally. But if you inspect a string while my module is above you on the call stack, I get my hotwired version of .inspect. Does anyone have a Ruby Hack which does that yet? How hard would it be? -- Phlip http://assert2.rubyforge.org/ |
|
|
|
#16 |
|
Messages: n/a
Hébergeur: |
On Sat, Feb 23, 2008 at 9:08 PM, Trans <transfire@gmail.com> wrote:
> No. It's not the Monkey, or the Duck that's killing Ruby... It's the My point exactly :-) -- Avdi |
|
|
|
#17 |
|
Messages: n/a
Hébergeur: |
Trans wrote:
> Oh bother. If it ain't the Duck, it's the Monkey. > > No. It's not the Monkey, or the Duck that's killing Ruby... It's the > Peoples. We've survived worse. Remember the Snail? http://blade.nagaokaut.ac.jp/cgi-bin...17?20588-22393 -- vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407 |
|
|
|
#18 |
|
Messages: n/a
Hébergeur: |
On Feb 23, 2008, at 9:21 PM, Todd Benson wrote:
> On Sat, Feb 23, 2008 at 8:08 PM, Trans <transfire@gmail.com> wrote: >> Oh bother. If it ain't the Duck, it's the Monkey. >> >> No. It's not the Monkey, or the Duck that's killing Ruby... It's the >> Peoples. > > In other words, it's the hairless monkeys (I'm one of them .No, no, it's the apes. Monkeys have tails. The tailless primates are called apes. Regards, Morton |
|
|
|
#19 |
|
Messages: n/a
Hébergeur: |
Morton Goldberg wrote:
> On Feb 23, 2008, at 6:56 PM, M. Edward (Ed) Borasky wrote: > >> One of my friends once passed this little quotation on to me: >> >> "Always code as if the person who will maintain your code is a violent >> psychopath who knows where you live." > > > Truly wonderful. If there were a poster of that available, I'd buy it > and hang it where I could see it when I look up from my screen. > > You didn't make an attribution, so I presume you don't know who > originated it. Too bad. > > Regards, Morton > > Right -- I don't know who originated it, but I'm guessing you could find some guesses on Wikipedia. ![]() I do know that Gerry Weinberg is the originator of "If we built our buildings the same way we build software, the first woodpecker that came along would destroy civilization." |
|
|
|
#20 |
|
Messages: n/a
Hébergeur: |
Morton Goldberg wrote:
> No, no, it's the apes. Monkeys have tails. The tailless primates are > called apes. Didn't someone once identify the Common Patcher Monkey species as /Monachus recarcio/? (The one that feeds on bugs, marketects, and Starbucks pastries?) -- Phlip |
|
|
|
#21 |
|
Messages: n/a
Hébergeur: |
Avdi Grimm wrote:
> Hi folks, > > I wrote a blog post with the intentionally provocative title above, > which can be found here: > > http://avdi.org/devblog/?p=18 > > While the title is a bit of deliberate hyperbole, I am genuinely > troubled about the popularization of monkey patching in the Ruby > community. That so many people use the phrase "monkey patching" suggests many people don't actually understand how to use it. It's no more "patching" than reassigning to a variable is patching. "ZOMG! You're changing something at runtime!" Yeah, happens all the time. Use with caution; get on with life. Maybe if people weren't so spooked by metaprogramming they'd see it as yet one more feature of the language and use it appropriately, rather than treating it like high-priest voodoo that seemingly works by magic. -- James Britt "Serious engineering is only a few thousand years old. Our attempts at deliberately producing very complex robust systems are immature at best." - Gerald Jay Sussman |
|
|
|
#22 |
|
Messages: n/a
Hébergeur: |
James Britt wrote:
> It's no more "patching" than reassigning to a variable is patching. > > "ZOMG! You're changing something at runtime!" That's not MP. MP is changing a published class by re-writing one of its existing methods. Your whole program and all its modules get the new version, at design time. Otherwise, you have to... - inherit that class - override the method - upgrade all the class objects' .new sites The last one is the reason - without pristine Construction Encapsulation - MP is the shortest path between two points. So when we "use with caution", where highly popular libraries - obvious example Rails - get to patch whatever they feel like, and modules below them in the pecking order must refrain from patching so freely. That's why I suggested encapsulating the patch effects to the patching module. That's either a new feature in Ruby, or a very clever metaprogramming hack. Problem solved. -- Phlip |
|
|
|
#23 |
|
Messages: n/a
Hébergeur: |
[Note: parts of this message were removed to make it a legal post.]
On Sun, Feb 24, 2008 at 12:06 AM, James Britt <james.britt@gmail.com> wrote: > Avdi Grimm wrote: > > Hi folks, > > > > I wrote a blog post with the intentionally provocative title above, > > which can be found here: > > > > http://avdi.org/devblog/?p=18 > > > > While the title is a bit of deliberate hyperbole, I am genuinely > > troubled about the popularization of monkey patching in the Ruby > > community. > > That so many people use the phrase "monkey patching" suggests many > people don't actually understand how to use it. > > It's no more "patching" than reassigning to a variable is patching. When you are talking about global (and to a certain extent class) variables, there is an analogy. Most languages do have global variables, but they are also usually discouraged (especially changing them) because of the side-effects (state changes). Monkey patching is in this same vein, except worse IMHO (the state changes can be more intrusive). Like global variables, I don't think monkey patching is a good practice for reusable, inter-operable, and maintainable code. On the other hand, one nice time to use it is for creating a ruby-based DSL. But, when making a DSL where monkey-patching s, I think the monkey patching should be done as a thin layer. The base functionality should use no monkey-patching so that it can be used cleanly with other packages. You'd likely have problems combining multiple monkey-patched DSLs together if you couldn't disable at least some of the monkey-patching. You might also say the same of global variables. If you use them, use them only at the highest user/DSL/script/test level. The baseline reusable functionality should just be passed that global variables and not use them directly. Eric |
|
|
|
#24 |
|
Messages: n/a
Hébergeur: |
> I want this:
> > module MyModule > class ::String > def inspect > return 'shock the monkey' > end > end > end > > I want .inspect, or whatever, outside my module, to behave normally. If ruby had a package/module system with import/export where constants could be renamed and assigned for a specific set of code ... well. Such a system would be tricky to manage though due to all classes being open. Nothing stops you from adding a new method later on and it could sometimes be difficult (or rather non-intuitive) to determine whether the class X in that method should be the real class X or class Y that was assigned to X in the import statement of such a module. Anyway, you could also rewrite (live/hot/monkey patch, whoahoo!) String#inspect to check if the caller belongs to your module. If I'm not mistaken, ruby19 provides means to detect who/what is calling a method. I'd rather subclass String though, since this special use should be restricted to a well-defined module. But what should happen in your proposal if a method returns such a special string and something outside the module calls inspect? BTW I don't think the python community originally frowned upon MP. I can remember a self-proclaimed python expert who once explained with sparkling eyes the merits of MP to a young newcomer. I cannot remember the slightest trace of doubt and this already happened a few years ago. Regards, Thomas. |
|
|
|
#25 |
|
Messages: n/a
Hébergeur: |
On 23.02.2008 23:36, Avdi Grimm wrote:
> On Sat, Feb 23, 2008 at 5:23 PM, Eric Mahurin <eric.mahurin@gmail.com> wrote: >> I don't agree with the title > > Like I said at the beginning of the article, neither do I ;-) > >> * adding new (or perceived missing) functionality (methods) to a class. The >> traditional solution would be to just inherit from the class and use the >> derived class instead where you want this new functionality. Since you >> can't inherit from some classes (i.e. immediates, a problem with the >> language IMHO), you can instead use something like Forwardable instead. > > Indeed. The irony here is that Ruby is perhaps the easiest language > in the world to implement delegation in. I'm planning on writing a > series of posts on alternatives to monkey patching, and delegation is > going to be one of the first techniques I talk about. But keep in mind that since it's so easy you can shoot yourself in the foot equally well as I have tried to point out in a recent post: http://groups.google.com/group/comp....f76656fd2c0f68 On a broader scale: I agree with your assessment that MP can cause bugs that are hard to find and that there are usually other ways to achieve the same effect in cleaner ways. I for my part try to steer people away from using those "dirty" techniques (MP, inheriting core classes etc.) whenever I think there is a easier and clearer solution available. Do we need a discussion about this? Is MP really destroying Ruby and / or Rails? I don't know. Maybe MP is just the current buzz word that everybody uses and will go away like any other fashion. But I do think that it's ful to once in a while step out of daily business and think about things on a broader scale. It s keep our minds flexible and not run into a completely wrong direction for too long a time. Kind regards robert |
|
![]() |
| Outils de la discussion | |
|