Sunday, June 24, 2007

OR - ActiveRecord

Via Bill de hOra I saw this: this on ActiveRecord at Twitter.

Couple 2-3 quotes:

One major downside of having an object-relational mapper is that you don't always control what goes on behind the scenes.

This pretty quickly brought us to an obscure corner of the ActiveRecord source (three cheers for source code!), where it became apparent that Rails was doing these gigantic loads from the database every time we saved even a single field in a related object. There are a bunch of mitigating circumstances that mean that this bug doesn't get triggered all the time, but it's still really really bad.

You mean insane SQL isn't just a problem with Java based OR tools?

I think Ruby is great. I think that ActiveRecord is great and do think that it has it's place.

My problem is that every time I have been associated with an OR tool (Toplink, EJB CMP, Hibernate) the exact panic described above has ensued. In my experience OR tools have been like very bad debt. They are shiny objects that make initial development a bit simpler & then make you pay pay pay down the road.

Now I don't have much information on Twitter, but I'd think that it would be the type of system that you would want to write SQL by hand for. You can either get some syntactic simplicity from OR tools and defer how the SQL gets generated (and wait for panic to ensue) to an OR tool or you can write SQL (a really simple language) and be in control.

Control isn't always required - and I am a big fan of Ruby on Rails - just sayn' choose wisely - there is more to life than concise model to database interaction.

As for the Three cheers for source code line, +1MM. Never ever use an OR tool that is not OSS. That is just asking for it.

I am going to get a breakfast burrito now.


Sarge said...

Breakfast burritos rock.

We solve problems in software by adding abstraction. I have no problem with O-R tools as a solution of added abstraction. As my former coworkers liked to say, "You made your choices". Where I think a lot of trouble occurs is with the either-or, us-vs.-them mindset that is both designed into these tools and culturally reinforced by their communities.

I worked on a product once that applied dozens of data-driven rules on millions of events per day. We used CMP EJB because, well, that's just the way you did it. We encountered several problems where the container-generated SQL exposed some bug in SQL Server. (Insert rant about shoddy Micro$oft software here.) In those cases, it would have not only been more efficient, but it would have been more correct to rip our own SQL. But for the code that fetched the parameters of the rules, a simple "int getIntSetting(String name)" that performed the selected and returned the first column of the first row is a better solution.

The moral to our story: when it comes to interacting with daterbases, a complete covering layer is a complete mistake.

quark said...

What I think is so problematic with OR mapping frameworks like ActiveRecord is that you usually have to go "all in". It's at least very hard to subtract some of the abstraction if you want to, for instance, add a stored procedure to plug a CPU consuming hole in your data layer.

OR mapping is great because it lets you get on your feet and run very quickly, but if you would like to go back and do some baby steps and crawling in any part of your system, the OR framework should allow you to plug in your own data logic without having to completely remove the OR layer alltogether.

fuzzy said...

sarge & quark, well said.

quark, "the OR framework should allow you to plug in your own data logic without having to completely remove the OR layer all together."

Only one that is remotely like this that I am aware of in Java land is iBatis. But I only did a tutorial so I don't have first hand experience.

I am fine with OR tools, I just flip my bozo bit when the argument is simplicity - OR tools are simple when things are working. They can become thee single most complicated thing in your system once they stop working / scaling /etc.