Sustainable Development in Ruby: Introduction
This is the beginning of a series of posts on sustainable development in Ruby. No, I’m not talking about writing code on wind-powered laptops while sipping fair-trade coffee. But the sustainable development movement has a fairly direct analog in software development. As programmers, we work within a code ecosystem. The ease with which we write new programs is impacted by the choices of other coders before us, and likewise the decisions we make while coding affect other programmers down the line.
As with industrial development, in the early years of a particular software ecosystem it’s not always obvious that the choices we are making might be detrimental to our successors.
bq. the first generation of programmers is usually enthusiastic; any failure is a personal failure, so you can gloss over those things. It’s the second generation that’s going to be less enthused, that’s going to stare in bafflement at these classes that mysteriously spawn methods, and trying to figure out what’s going when there’s an exception in dynamically generated code.
– “Ian Bicking”:bicking
When a programming language is relatively young, unsustainable practices often go unnoticed, or are dismissed as easily avoidable.
bq. A mere flesh wound, says our programming primate: I usually don’t get conflicts, so I’ll pretend they won’t happen. The thing is, as thing scale up, rare occurrences get more frequent, and the costs can be very high.
– “Gilad Bracha”:bracha
When a language is only a few years old, the amount of code written in it is necessarily small. Legacy code is measured in the thousands of lines, rather than hundreds of thousands. If a section of code, or a third-party library, is causing problems – well, you can always rewrite it. As codebases grow, however, the rewrite option becomes less and less viable. Coping with legacy code is an everyday fact of life for most professional programmers.
h3. Parameters
If we take it to mean any and all techniques for making software more robust and easy to maintain, sustainable software development is a very broad subject. Indeed, one could argue that most of the major advances in the software field in the last 30+ years have been made with sustainability in mind – OO, refactoring, TDD, to name a few.
In this and the following essays I’m only going to be addressing one specific aspect of sustainability in the Ruby language. I’m going to be talking about the practice of dynamic class modification, colloquially “monkeypatching”. I’m addressing this subject because I believe injudicious use of dynamic class modification to be one of the greatest threats to long-term sustainability _currently_ facing Ruby.
h3. Definitions
What are we talking about when we say monkeypatching? Some divide dynamic class modification into two categories:
* Runtime addition of methods
* Runtime redefinition (overwriting) of methods
Some maintain that only the latter definition is true monkeypatching. The line is blurrier than it might first appear, however. If two separate libraries both add a @#to_xml@ method to the @Object@ class, then individually they are only _adding_ a method, but when both libraries are required by the same program one will be _overwriting_ the other – whichever one is loaded last. For this reason I will use monkeypatching to mean both the dynamic addition _and_ redefinition of methods, albeit with an emphasis on redefinition.
Specifically, I will be referring to dynamic _non-local_ addition and redefinition of methods. By non-local, I mean that the dynamic modification occurs outside of the original class definition. The following is not a monkeypatch:
class Foo
attr_accessor :bar # defines bar, bar=
# redefines bar
def bar
# ...
end
end
Whereas this version demonstrates monkeypatch:
class Foo
attr_accessor :bar # defines bar, bar=
end
# re-open the class
class Foo
# redefines bar
def bar
# ...
end
end
h3. No easy answers
bq. this “monkey patching” thing is seriously powerful
– “Chad Fowler”:fowler
bq. languages—like Ruby—that include dangerous features give the fringe a broader latitude to invent new things. Of course, they also break things and they invent stupid things and they get excited and write entire applications by patching core classes instead of writing new classes and commit all sorts of sin.
– “Reginald Braithwaite”:braithwaite
bq. One of the things that’s really great about agile languages is they give you the power to do anything. One of the most horrible things about agile languages is they give every other idiot the same power to stab you in the back with a rusty pitchfork.
– “Zed Shaw”:shaw
This series will *not* tell you when to monkeypatch and when not to. It is not my intent to set myself up as the arbiter of when monkeypatching is justified. These posts make the assumption that you already understand that Ruby dynamism is both tremendously powerful and potentially dangerous. I want to present some alternatives to monkeypatching, so that you can make an informed decision when deciding whether to use monkeypatching to solve a particular problem.
h3. Conventions
In order to help you make that judgement, I’ll be characterizing the techniques presented by their applicability. Some of the aspects affecting applicability are introduced below. In this context, the term
* *Who controls creation of the target?* – does your code call the class constructor, or is the object given to you already created by vendor code?
* *Are you the only client?* – is the target used by third-party code, or is your code the only code that touches it after it is created?
* *Can you intercept the target?* – if the target is produced and consumed by vendor code, is there still a point at which your code has access to it? Or is it’s use completely internal to vendor code?
These factors and others will affect which techniques are right for any given case.
[bicking]http://blog.ianbicking.org/theres-so-much-more-than-rails.html
[bracha]http://gbracha.blogspot.com/2008/03/monkey-patching.html
[braithwaite]http://weblog.raganwald.com/2008/02/1100inject.html
[fowler]http://chadfowler.com/index.cgi/Computing/Programming/Ruby/TheVirtuesOfMonkeyPatching.rdoc,v
[shaw]http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/153380

This work, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.
Related posts:
