I got a message this morning from Gregg at Ruby5 asking why I wrote the master_slave_adapter plugin instead of using Technoweenie’s Masochism and I think the answer to this question deserves a little blog post (and the blog really needs some new content :P).
When building the Talkies project we had to setup a master-slave environment using MySQL at the production servers. To get these things up and running I configured the replication on MySQL and set out to find a solution on Rails/ActiveRecord to handle this special need, all SELECT* statements should be sent to the slave db while all other commands should be sent to the master. The only solution available at the time was Masochism (at least it was the only one I could find).
With Rails 2.1, everything looked like we would live happily ever after, but Rails 2.2 brought a lot of changes and many of them on ActiveRecord, the main one being connection pooling and we upgraded. The production server, that wasn’t really live yet, broke badly, the new connection pooling code made the application crazy and the slave was receiving UPDATE* and INSERT* calls ( this was the code at the moment ).
With this new issue showing up I set out to find a solution, the first thing was to hack the plugin itself (as github had no “issues” thing at the moment). Trying it out I couldn’t really find a simple fix and wasn’t really happy with the way the plugin worked, looked a lot like a hack when a hack wasn’t really needed, so I started to write my own solution.
The first requirement was that it should perform no black magic at all, we were burned more than once during the project by plugins that were too clever and relied heavily on monkey-patching, so my solution had to be really straightforward and do as little clever things as possible.
But hey, active_record needs a database adapter, so why not just build a fake database adapter that forwarded the work to a master or slave connection depending on the method called? This way I would never need to hack ActiveRecord, as the thing would just be a common database adapter, like all the others and the plugin would survive to Rails upgrades with little or no changes. And that’s exactly what I did, an ActiveRecord database adapter who’s job is to route method calls to a real master or slave connection.
Why was it an improvement?
By relying on the ActiveRecord database adapter contract I had no need to monkey-patch Rails itself, it would just work, even if Rails or ActiveRecord got upgraded, the only thing that would make me change the plugin was if the database adapter contract got changed and this isn’t really something that changes a lot.
And if there’s one thing that’s burning a lot of people using plugins and Rails itself is clever code and too much monkey-patching. When you’re building a solution that’s going to be “inserted” inside someone else’s codebase that you don’t even know how it’s going to look like, you better try to avoid changing too many things or breaking well known contracts, you might end up with bugs that are hard to discover and kill. And they’ll surely make you waste a lot of your time.
Monkey-patching and class-redefinition are some of the coolest features of Ruby as a language, but they should be used with care and are better avoided if possible.
August 24, 2009 at 6:21 pm
Sounds good – enjoyed the post. Nicely argued aswell. When the need arises I will look here for a solution. :)
August 31, 2009 at 9:44 am
Is there any legacy plugin from technoweenie which as not being replaced by a far better one ? :P
August 31, 2009 at 12:51 pm
I still find attachment_fu the best solution for attachments :)
September 2, 2009 at 2:21 pm
Really! Why don’t you like about Paperclip?
September 2, 2009 at 2:23 pm
S3 and Cloudfront support :)
September 3, 2009 at 12:23 pm
Of if I’m not mistaken, you added cloudfront support, right? Your name sounds very familiar :) I replaced my own legacy plugin actually… the rewrite branch of attachment_fu kicks much more ass. I’ve literally been using it for about a year and a half, but it’s been hiding in a non-master branch because I haven’t had time to write decent docs for it.
September 3, 2009 at 12:22 pm
Why didn’t you just submit the code to masochism? I’d take a full rewrite (it’s a tiny plugin anyway), and then everyone can benefit. Plus, you get more users using your code that can point out problems.
The masochism plugin is kind of funny. I wrote it as a joke in response to some other weird master/slave plugin. I’ve never really used it though, but all these other people say it rocks and sent me lots of fixes. *shrug*
September 3, 2009 at 3:06 pm
Hey Rick,
Well, I didn’t submit ‘cos it was “another” plugin. I never thought that you’d accept it as a “replacement” ;D
September 4, 2009 at 2:38 am
Ah I realize it can be a tough call to make. You’d have to either support the masochism’s API pretty closely or provide a good migration path. Not trying to start some shit or anything :)
September 8, 2009 at 8:34 pm
Heh… I guess independent reinvention of the wheel is the best confirmation that your thoughts were on the right track.
http://github.com/sd/master_slave_adapter/tree/master
I should have promoted it better.
October 12, 2009 at 11:14 pm
[...] The author himself has admitted (in comments) that the project has fallen into a bit of a state of disrepair, and apparently it [...]
September 3, 2009 at 3:07 pm
Now I don’t remember it either. I did integrate Cloudfront to attachment_fu but right now I’m not really sure if I handled it back to the project, it’s been a long time since I did it.
But anyway, I’m still using attachment_fu a lot and will definitely look into your new branch, maybe I can contribute with the docs that are not there yet, the plugin helped me a lot, maybe it’s time to give something back.
September 4, 2009 at 2:39 am
That’s cool.. I also have some s3/image handling features to push up too. My github message queue is insane. I’ve kind of been taking a break from the OSS scene this year if you can tell…