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.

On Sun, Feb 24, 2008 at 06:07:36AM +0900, Avdi G. 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

On Sat, Feb 23, 2008 at 4:38 PM, Gregory S.
[email protected] 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.

On Sat, Feb 23, 2008 at 5:23 PM, Eric M. [email protected]
wrote:

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 4:36 PM, Avdi G. [email protected] wrote:

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

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.

Avdi G. wrote:

here’s a synopsis:
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.”

On Sat, Feb 23, 2008 at 3:07 PM, Avdi G. [email protected] 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

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 …

On Sat, Feb 23, 2008 at 7:13 PM, Marc H. [email protected]
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.

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

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.

I can say that I agree with all pieces of your article. This issue is
not related to rails community, it’s ruby programmers issue (but of
course there are programmers that not make such a mistakes). The same
goes with using modules as mixins when there should be used delegation
or inheritance and many other things. I say that Ruby is very sharp
knife. It’s very powerful but you must know how to operate with it to
not hurt yourself.


Rados³aw Bu³at

http://radarek.jogger.pl - mój blog

On Sat, Feb 23, 2008 at 9:08 PM, Trans [email protected] wrote:

No. It’s not the Monkey, or the Duck that’s killing Ruby… It’s the

My point exactly :slight_smile:

On Sat, Feb 23, 2008 at 8:08 PM, Trans [email protected] 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

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

Morton G. wrote:

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

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

Avdi G. 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 B.

“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

On Feb 23, 2008, at 9:21 PM, Todd B. wrote:

On Sat, Feb 23, 2008 at 8:08 PM, Trans [email protected] 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

On Sun, Feb 24, 2008 at 12:06 AM, James B. [email protected]
wrote:

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