Brief technical note: The syntax highlighting gem I'm using isn't 1.9 ready, so in the mean time I'm using Gist for the embedded code in this post. It will likely not work in your feed reader. If you can't see the code examples, please visit the article on the site.
As a primer, I should note that I was recently laid off. If you're looking for a competent and experienced web developer, look at my resume and give me a call. I'm open to contract work or full time work or anything, really.
So while using this infinite free time that I have recently acquired, I was looking into MongoDB as an alternative to CouchDB. A few things about Couch were bugging me, but that's another post I guess. Naturally I gravitated towards Mongoid as an "ODM" (Still habitually say ORM even though the term isn't correct. Oops). Most people don't know this, but for much of the past year I've been working on an ODM for CouchDB*, so I'm a bit biased towards the solutions I came up with. Even with that said, there were a few things about Mongoid that bugged me. And strangely enough, they all have the same root cause and the same solution.
*= I'm working on releasing a version of it as soon as possible. It has a very thin adapter layer so I see no reason why I can't adapt it to MongoDB as well, so my work is not yet wasted.First off, I want to say that I'm not trying to bash the Mongoid developers specifically- I really appreciate the work they've done, and I know first-hand how hard creating an ODM is. It speaks volumes that they've been able to ship while I haven't. This is more of a critique on the larger Ruby community's choice of style when it comes to these things.
I'll save the worst for last, but there are three things that really left me scratching my head. First was the use of database.yml- why on earth are we still doing config files in YAML? The only reason ActiveRecord used YAML is because DHH didn't want to use XML. If you stop for two seconds you can realize that you don't need the config files in another language at all. Ruby can do this stuff perfectly fine. Allow me to demonstrate.
This is called a DSL, guys. The entire reason we use Ruby is because it is freaking fantastic at making DSLs. So why not take advantage of that? Passing a block is amazingly powerful when the receiver creates a new object and then that new object uses instance_eval to execute said block. When you pass in a block like this, you also get a huge advantage- you can execute arbitrary code to modify the newly-created object. Like so:
The possibilities are quite literally endless. This approach also has many other benefits. This brings me to my second pet peeve, which is the way that ActiveRecord (and, by inheritance, Mongoid) handle validations. The way that AR handles validations makes a little bit of sense, because you're not explicitly defining the fiends of the objects. But with Mongoid validations are a two-step process: Define the field, then define the validations. Why not do it all in the same step?
Which brings me to the third (and last) pet peeve about APIs. Why on earth do people use options hashes? They completely wreck documentation, and are consistently one of the major sources of confusion for everyone. When an options hash is not documented, and the hash isn't used for 3 or 4 levels down in the call stack, it can quickly become impossible to figure out what options are possible and what the valid values are. The solution? You guessed it- a DSL. Let me demonstrate both of these last two points in one example:
Isn't that better? The only downside is that it uses more vertical space, but the code looks flat-out sexy now. Hashrockets, fun as the name is, are one of the ugliest things in the Ruby language. An API should (almost) never require that you use them.
Your turn- do you like this approach? Hate it? Have a better alternative? Let me know. I'm quite interested to find out.