My last article was intentionally provocative, and my expectations of response were exceeded. The “ruby-talk thread”:http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-talk/292269?292062-292516 was full of good comments. I’m appreciative of everyone who has taken the time to respond either there or here on the blog.
I thought I’d write a quick followup and just respond to a few of the points that came up repeatedly in the ensuing discussion.
h5. “This is a Rails problem, not a Ruby problem.”
I’ve been coding in Ruby for something like seven years now. When I started ruby-talk was the only game in town, and Rails was years away. Now I work at a Rails shop now, and I’m the self-appointed “Ruby geezer” – I’m the guy who corrects people when they complain about some “Ruby” feature which is really a Rails extension.
I know the difference between the Rails community and the Ruby community. And the fact of the matter is, these days most of the payed work being done in Ruby is Rails work. For better or for worse, the coders of tomorrow’s Ruby community are coming to it from Rails. Rails cultural problems will increasingly be Ruby cultural problems.
h5. “Monkey patching is a powerful and useful technique”
No argument there. What I am calling for is that it be used sparingly, judiciously, and only when there are no other practical options. In particular, I’m discouraging the use of monkey patching as a standard mechanism for extending core or third-party libraries – especially when those extensions will be packaged and distributed.
h5. “Bad code has always been with us. There’s nothing special about monkey patching”
What is special about monkey patching is that right now it is being used as a de-facto standard mechanism for class extension in gems and plugins, to the exclusion of less invasive techniques. Numerous gems add functionality to core classes like @Object@. In some cases it’s warranted, but in many it seems to be more because we can than because it’s called for. And in Rails, it is simply assumed that if you’re going to extend, say, ActiveRecord with a plugin, you’re going to do it by monkey patching @ActiveRecord::Base@ or some other core Rails class.
As an thoroughly modern OO language, Ruby offers almost an embarrassment of riches when it comes to methods for extending functionality while maintaining encapsulation. Inheritance, mixins, rediculously easy delegation. Using monkey patching to extend classes throws all of that away, and takes us back to the C days of working all in one big undifferentiated namespace. Except in C if you were lucky the compiler would complain when you redefined an existing symbol. Ruby will happily let you override methods and overwrite instance variables without a peep. This, of course, is part of the power of Ruby. Power that should be reserved for prototyping and for special cases, not for everyday plugins and libraries.
h5. “Where’s the code?”
This is a legitimate criticism. So far I’ve talked a lot about the evils of rampant monkey patching, and I haven’t shown any code, either to demonstrate what not to do, or to demonstrate alternatives. This is almost unforgivable on a programming blog. I’m planning on remedying that ASAP. I’m working on a series of posts covering alternatives to monkey patching. Stay tuned.