Like me, Leah Neukirchen has recently been making their first advances into Rails development. Also like me, they’re a Rubyist from way back, unlike a lot of people who have come to Ruby via Rails.
My practical experience of Rails began a few weeks ago, when I started my new job: before then, I had only glanced at the successive releases of Rails, but hadn’t had any reason to delve any deeper into actually using it.
My experience so far has actually borne out my initial impressions: Rails includes a lot of features to facilitate some of the more mundane aspects of web development, but it is not the universal panacea it’s sometimes painted as. That shouldn’t be taken as a negative comment, but just a reflection of the fact that writing a complex app is still complex no matter how you do it. What Rails provides is a good starting point, especially with respect to MVC separation, test-driven development, and automation of development tasks. It’s also probably useful in forcing some better practices on people who have used messier development techniques in the past.
The second biggest problem is fighting with ActiveRecord; in fact, I think all my problems so far can be reduced to wrong use of ActiveRecord. I just hope we will get along better together in the future. (Once you got it to work, it’s pretty nice, of course.) Maybe my database schema was a bit too difficult for a first use. (Featuring self-referential entries etc.)
I’d agree with this. In fact, I’ve found ActiveRecord to be the hardest thing to use. Part of that is, I think, due to the so-called ‘impedance mismatch’ that’s probably inevitable when mapping between objects and SQL. I find myself knowing exactly what I want to do, and how I’d do it in SQL, but working out the ActiveRecord way is a bit harder. SQL can be unnecessarily complex and seemingly inconsistent, but ActiveRecord has plenty of surprises of its own—and many undocumented capabilities. It’s a frustrating process to learn them, sometimes.
I also think that there’s one big danger in ActiveRecord, but it’s one that is not actually inherent to the library itself. Because of the object-oriented syntax, it becomes natural to perform actions by chaining methods. In one respect, that’s excellent: it’s readable, and the intent is clear. On the downside, however, the differences in efficiency can become profound when the number of objects is large: in other words, it’s not so scalable.
In fact, just such a problem cropped up at work yesterday. The latest revision died under production loads, and I had to dig through the intermediate changesets since the previous release to find what was causing the problem. I’m not sure yet, but I think that a similar piece of code to the first example above was the cause. (We haven’t had a chance to verify it yet.) An item-counting method had been changed from an SQL query to a more Rubyish manner. The tests didn’t catch it, because it still worked, and they weren’t checking for speed or memory usage.
There are a couple of lessons, really. First, even if you abstract database operations into objects, it doesn’t necessarily get easier: some understanding of the underlying technology’s strengths and weaknesses is invaluable. Second, tests will only test what you thought to test for!