Skip to main content

We should learn from Active Record

Posted by batate on January 19, 2006 at 9:42 AM PST

There are at least two major styles of object-relational persistence frameworks. Mapping frameworks take an object-centered view of the world, and wrapping frameworks take a database-centered view of the world. Since Hibernate, Java developers have taken the mapping world view, pretty much across the board.True, the mapping view has its advantages. The biggest one is the ability to map to those crusty legacy schemas, typically designed by that fresh gradute who did his dissertation on fourteenth-normal form. You can handle database-centric ideas like composite keys, and user defined types.

But there's a subtle undertone in the Java community that's going back to the basics. You can see indications of this movement in Spring's JDBC framework, and Clinton Begin's iBATIS framework. I often teach about persistence frameworks, and the most rapidly growing group of developers is those that want to explore JDBC extensions, like iBATIS and Spring JDBC. You just don't always need full ORM. And full ORM can get you in trouble when you don't have the skills to pull it off, as Ted Neward so pungently described in his Vietnam blog (I'd link to it, but the site has been down for a while.)

I'm not saying that ORM is the EJB of the 2000s. I just want to propose the idea that one size doesn't fit all, and sometimes, it's a good idea to admit the database. Which brings me to Active Record.

Java really needs something like Active Record. For the expected case, you can just create your schema, and let Active Record discover your relationships. So a person object winds up looking like this:

class Person < ActiveRecord::Base
  has_one :address
end

Ruby finds keys, foreign keys and table names through naming conventions (though you can override them if you want.) And you get all of the attributes created from scratch. Add a database column, and you don't have to change your code. Note that Ruby does something a little special here...it introduces attributes. With Java the experience would be different, but not impossible.

But the idea that my wrapping framework also eliminates repitition and extends through to relationships is very appealing to me. I can get down and dirty with SQL, or I can let the framework hide it from me. Admitting SQL is also one of the capabilities that's so attractive to iBATIS, and to a much lesser extent, Hibernate.

I also like the idea of reflecting through the model. I can ask any model class about an association on it. In this example, Person automatically gets an association called address. What table does it map to? I can say

Person.reflect_on_association(:address).active_record.table_name

I've built the basics for a simple report writer this way and it's nice. I can easily relate the table structure to the relationships of my object model. So to me, the lines between OR mapping and wrapping are blurring substancially.

Now throw in migrations. With a migration, you define a table in Ruby. Then, you have an .up method and a .down method. And you number the migrations so you can migrate schema and data in a single script. So here's a possible migration called 002_add_person.rb:

class AddPerson < ActiveRecord::Migration
  def self.up
    create_table "people" do |table|
      table.column "first_name", :string, :limit => 50
      table.column "last_name", :string, :limit => 50
      table.column "email", :string, :limit => 100
      table.column "company_id", :integer
      table.column "address_id", :integer
    end
  end

  def self.down
    drop_table "people"
  end
end

I can also add and drop columns and indexes. Active Record can take those migrations and translate them to SQL. So now, I'm pretty much independent of the underlying database version, if I want to be. And I can move up or down to any migration version:

rake migrate version=4

If I'm at 6, Rake will call 006*.down, and 005*.down. If I'm at 3, Rake will apply 004*.up. Migrations feel like Rails. I didn't expect to like them, but the idea just flows naturally.

Now, I'm not going to lie and say I'd be willing to jump through all kinds of hoops to try to map a legacy schema to a Rails project. I'd probably try to use Rails on Og, or Rails web services to a Java-backed project. But I do think that Active Record and Migrations solves it's target problem better than anything I've seen in the Java space.

So here's my point. Sometimes, it takes competition to force some interesting innovation. By using this stuff for a couple of weeks, my world view has changed. For a new project where I could define my own schema, or if I had an existing schema with object ids, I'd have a hard time moving back to the existing Java frameworks.

I'd love to see a strong Java implementation of Active Record. And I'd love to see a great generalized solution for migrations, wired into Ant. Sure, you can drive a screw in with a hammer. And sure, you can build a new schema with a mapping framework. But if you don't need to map, why bother? So the Java persistence community could learn a whole lot from Active Record. I'm a mapping bigot no more. Give me the best tool for the job.

Related Topics >>

Comments

ActiveRecord in Java

Bruce, these are all valid points, I felt the same about ActiveRecord, and waited...and waited until Java implementation shows up, but for some reason, nobody would implemented it so that it would have the same ease of use as AR. Finally, I thew in the towel and implemented i myself: http://code.google.com/p/activejdbc/ I hope this proves useful for some people. thanks Igor