Jeff Atwood recently posted some thoughts on monkeypatching. Strangely, he only writes about one aspect of monkeypatching—modifying the functionality of a core language feature—and makes no mention of the much less dangerous and far more common use case, which is to modify the functionality of a third-party library.
As Jeff points out, monkeypatching a core language feature is almost always a bad idea because the changes propagate to all running code rather than just your code. This is an excellent way to virtually guarantee strange, hard to debug problems, especially if you’re writing an application that uses one or more third-party libraries or frameworks. On the other hand, monkeypatching third-party code is usually less dangerous and the effects are easier to control, since your changes will only affect code that uses that particular library.
Before monkeypatching, you should always exhaust all other options in the following order:
- If the change can be implemented in a reasonably elegant way without monkeypatching, do it that way (especially if it’s a change to a core language feature).
- If the library or framework you want to change is open source and your change would benefit other users, make your change there and contribute it to the project as a normal patch.
- If neither option is possible, then you may monkeypatch, but do so in as limited and careful a fashion as you can. Make the patch obvious; don’t hide it in the midst of a bunch of other code.
In all the open source code I’ve written to date, I’ve only ever needed to use a monkeypatch once. The patch in question is in Thoth, and it makes a very small change to the way Ramaze looks for a requested static file.
I implemented this as a monkeypatch because the feature is of limited use to most other Ramaze users and would have required significant changes to Ramaze if implemented in a generic way rather than in a way specific to Thoth’s needs. The patch is very limited in its scope; it only affects the instance of Ramaze on which Thoth—and nothing else—is running.
Even so, I still revisit this code every so often to reevaluate whether it should remain a monkeypatch or be added to Ramaze.