Monkeypatching is Destroying Ruby

Hi folks,

I wrote a blog post with the intentionally provocative title above,
which can be found here:

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.

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

···

On Sun, Feb 24, 2008 at 06:07:36AM +0900, Avdi Grimm wrote:

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

···

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

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."

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.

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

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.

I really think that your BLOG entry is a bad way to say something
intelligent, AMOF you say many intelligent things.

It would make so much more sense to explain aspects of the technique
you do not like, I see the following issues:

Lots of people seem to confuse Runtime class modification
(metaprogramming) with MP.
There are very important issues to be discussed about if MP is on core
classes or commonly used packages
and most importantly if you MP in a package or in an application.

I have the feeling that you were making *very valid* points but they
do not concern MP in at least 50% of their use cases.
(or maybe those I use).

As others have said it somehow boils down to bad code vs. good code
and thats why I would have appreciated some examples of everyday code.
It is obvious that doing things like
class Array
   def size; 0 end
end
in a library or an application is nonsense.
OTOH
class Array
   def to_hash
        Hash[*self.flatten]
   end
end
might just make an application much more readable, but I still would
think twice of putting it into a library.
If I do so (putting it into a library ) another point you have been
talking about becomes important, convention, documentation.
Your Blog post could be a series of very interesting posts but you are
throwing years of experience and reflexion at us in one single post.
Have mercy with us !

But do not fear I am working on a programming language that will not
allow for bad code anymore, first release is scheduled for stardate
4242.42 :wink:

Cheers
Robert

···

On Sat, Feb 23, 2008 at 10: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

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.

--
http://ruby-smalltalk.blogspot.com/

---
Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein

I can't agree with this, there's too much going on to really make such a widely aimed statement. Monkey patching may be destroying a lot of developers, but how can most of 'the community' who, (myself included), have not been involved with ruby for sufficient years to be entirely confident on which patterns will be bad and which will be good, for a given situation. With the amount I have learned about ruby over the past couple of years, and the drastic swings in code quality, I can see how these things happen too. I went through stages of enjoying meta based solutions, right back to OO again, learning the simultaneous destruction and power of various techniques. I've been through stages of writing code that very few people can read, and those that can don't want to, right back to making code that non-programmers can read clearly. Ruby makes all sides easy, what you choose is a combination of culture, purpose, desire and habit. Many young ruby developers have a desire to be 'clever', and this often starts to disappear after some experience (in my experience). Hail simplicity, it will be good for all of us, but as for monkey patching destroying ruby, I'm not so sure.

Trying to stay a little away from the pattern discussion (as I hate the term, I think it leads to mis(/over)use). I would make the observation that some pieces of software in use in some really successful ruby projects (one that really screams out in my head, as rails was mentioned, is evented_mongrel, by Kirk Haines), is supplied entirely as a monkey patch along with the swiftiply package.

The important thing is for developers to realize the impact of the code they write, and as most experienced developers can tell you, this takes wisdom that is gained largely through experience, and one can never expect to catch everything in every scenario. The 'pattern' (if you like) of monkey patching is not one which is easy to maintain, by it's nature it can be very coupled with any underlying implementation, and often requires shortcuts to be taken (some (maybe most) would say it is a shortcut by it's very nature).

It is however, a fantastic prototyping tool. It is incredible when used at the final application development stage when you really just need a behavior to change on an underlying framework or api. Clearly there are better and worse ways to go about these things, and as always tests and documentation really help (as by these procedures, if there is a better way, you will often find it producing those). I think for frameworks under ruby, there are possibly some 'patterns' which are good to adhere to, and they are being discussed continually all over the place. Mostly they boil down to good (clean, maybe so far as to say 'pure') OO patterns, for which ruby provides some real convenience.

$0.02

···

On 23 Feb 2008, at 21:07, 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.

--
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.

Phlip wrote:

http://avdi.org/devblog/?p=18

I don't know what "Aspect Oriented Programming"....

I want this:

(clip)

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?

It can't be done in Ruby. I spent quite a lot of time analysing how to
construct such a language, as I've used this kind of design principle
for more than a decade to design aspect-oriented object models.

The problem is that for every call, you need to pass in a hidden parameter
which contains a descriptor for every namespace visible from the caller's
perspective, and you need to use that list of namespaces to disambiguate
the method call itself. Access to other parameters of the method from
inside the callee is also a problem, as they may be of classes that "don't
exist" from the POV of the callee.

Basically, such a language is possible, but I don't believe the implementation
can be made efficient.

A more restricted version of this behaviour can be done by treating every
aspect-limited extension (which I call a facet) of an object, as a special
kind of subclass. Such a subclass must not be allowed private access; it
can only use the public interface of its superclass. The superclass instance
is initially instantiated as just the superclass, but the facet methods are
"realized" as they're used, revealing the aspect behaviour of the object.
Again, this can't be faked very well in Ruby, and the various Traits modules
are a better solution.

However, I do believe that from a modeling POV, the approach is very valuable.
My ActiveFacts project explores the only real way to do this effectively,
which is in terms of elementary fact types. That means that all roles of
each object type are specified in one or more vocabularies (aspects), and
since the fact types are *elementary*, they're totally composable.

The same approach isn't easy to extend to modeling behaviour, for the
reasons I mentioned. You say tomato, I say tomatoe, but in Ruby, the
composition of the two things can only have one name, or you get collisions.
Unless you want to modify a Ruby interpreter to allow you to monkey-patch
Method#call, but then you're implementing your own VM :-).

Clifford Heath.

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.

···

On Sat, Feb 23, 2008 at 4:38 PM, Gregory Seidman <gsslist+ruby@anthropohedron.net> wrote:

--
Avdi

I don't agree with the title

Like I said at the beginning of the article, neither do I :wink:

* 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!

···

On Sat, Feb 23, 2008 at 5:23 PM, Eric Mahurin <eric.mahurin@gmail.com> wrote:

--
Avdi

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.

···

* Eric Mahurin (eric.mahurin@gmail.com) wrote:

I believe that "monkey patching" in packages can easily kill
interoperability with other packages.

--
Thomas 'Freaky' Hurst
    http://hur.st/

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/.

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

···

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."

In other words, it's the hairless monkeys (I'm one of them :).

Todd

···

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.

My point exactly :slight_smile:

···

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

--
Avdi

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/vframe.rb/ruby/ruby-talk/20717?20588-22393

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

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 helps, 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

···

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.

In the para phrased great words of Mel Blanc:

"Duck season!"
"Monkey season!"
"Duck season!"
"Monkey season!"
"Monkey season!"
"Duck season! FIRE!!!"

<BLAM>

Regards,

Mikel

···

On Sun, Feb 24, 2008 at 1: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.