Let’s assume you’re starting a new project.

What would make you choose between these two popular Ruby ORMs?

DataMapper

ActiveRecord

DM leads to "Model-Driven" development while AR leads to "Database-Driven" development

AR leads to abstractions that are tightly bound to the relational model, in certain cases this can lead to a model that's too tainted by the underlying database, it's quirks and the skill-set of those who modeled it. For simple models/schemas that might not be an issue but for complex models the gap between the needs of the application and the needs of the database will rear their ugly head as added complexity (in the queries, the controllers and the views)

Argue against this point

DataMapper supports composite and natural keys

Any property can be a key. Any composition of properties can be a key. ActiveRecord supports only auto-incremental integers as keys. This is a huge limitation.

Story from real life: once I had to implement an application that has a model which primary key was a composition of a foreign-key (integer) and a UUID field (persisted as a 16-byte string). I was able to do that with DataMapper thanks to its support for composite keys and custom properties.

Argue against this point

DataMapper has Property API

Instead of inspecting db schema and reflecting it to model attributes, DataMapper allows you to explicitly declare your model properties.

This serves many purposes. First of all you see how a model looks like by just looking at the class. It's especially important when you come to an existing project and you know nothing about the codebase or when your project is so huge you just can't remember all the attributes. With ActiveRecord you need to use silly plugins like annotate-models or keep on looking at your db schema.

Another purpose is that you can encapsulate a specific behavior in a custom property class. It allows you to work with legacy schemas and it also allows you to create complex property types like Enum, Flag, JSON, YAML etc. It's something ActiveRecord can't do and never will because of the pattern it's based on.

Properties are also used to automatically generate validations, for instance you declare a property with :required => true option and validates_presence_of will be applied automatically.

Argue against this point

DataMapper works great for legacy / read-only Databases

Some projects require that you must access a read-only Database. This means that you do not need migrations, timestamps or validations; since all of the data is already present. The only thing you must do is map in the existing tables, columns and relationships between them. This is where the modularity of DataMapper pays off, as you only need to require dm-core, or possibly dm-types.

For new Rails/DataMapper projects, the dm-rails template adds most of the usual DataMapper plugins to your Gemfile.

Argue against this point

The same is possible using migrations

*You* might get to a point where your database is in a bad state, but you shouldn't blame the lack of migrations. Personally I think the advantage of having the properties declared directly in the model far outweigh any potential issues that might arise from not using migrations rigorously. Migrations are not a magic bullet that automatically makes one a good developer. Do you have specific examples of bad habits that arose from not using migrations?

Argue against this point

CompositePrimaryKey gem is (and always will be) a monkey-patch

ActiveRecord assumes a simple primary key (called 'id') in many places, and a plugin like the referenced Composite Primary Key gem works by monkey-patching ActiveRecord's internals to circumvent those assumptions (it modifies Arel internals, too).

Consider well whether you want to introduce monkey-patches to the primary key handling code of your ORM. DataMapper's native support for CPKs means they are supported at every level of the framework. Official support means they will remain forward-compatible, as well.

https://github.com/drnic/composite_pr...

Argue against this point

Custom attributes (attr_accessible style) != Property API

Both DataMapper and ActiveRecord support 'custom attributes' of the type described (custom getters and setters is more accurate) -- it's all Ruby, after all. But that misses the point: conceptual coherence, declarative coding, responsibility decomposition, and more.

The ActiveRecord team recognizes the value of the Property API: in ActiveRecord 3.1 the AR::Base.serialize method is enhanced to support custom serialization, one portion of the Property API: http://edgerails.info/articles/what-s-new-in-edge-rails/2011/03/09/custom-activerecord-attribute-serialization/index.html. However, the Property API provides far more than custom serialization.

To understand it (coming from an ActiveRecord background), try to imagine a unified API covering the functionality currently fragmented between ActiveRecord's inferred attributes (ie., every DB column is a converted into a primitively-typed attribute), AR::Base.composed_of and AR::Base.serialize, then add model annotations and conceptual coherence and you're getting close.

When using a schema-less datastore (cassandra, riak, redis, mongo, couchdb, etc) application code defines the 'schema', rather than the other way around. As such, several of the non-relational projects/bindings/adapters use something like the DataMapper Property API to declare model attributes.

Examples:

* ToyStore: https://github.com/newtoy/toystore/blob/master/examples/models.rb
* SuperModel: https://github.com/maccman/supermodel/blob/master/README#L59
* Mongoid: http://mongoid.org/docs/documents/fields.html

In other words, the whole premise of reflecting upon a defined DB schema to infer attributes is meaningless in a schema-free world; something like the DM Property API is a *necessity*. But none of the referenced projects offer the full power of the DM Property API.

Argue against this point

There is great support in IRC

I believed this about ActiveRecord too, and it *was* hard for me to find support which was already written. However, the IRC channel #datamapper on irc.freenode.net is full of committed and intelligent people who are only too happy to help.

Try a google search including site:irclogger.com and check the results then. Chances are good your problem has been discussed.

Argue against this point

DataMapper behaves in unexpected ways

Often you expect DataMapper to behave a certain way, but it does the opposite.

For instance:

DataMapper.auto_migrate!

This will automatically migrate your database to the correct schema to match your models. Wonderful. Unfortunately you just typed that in and you now have no data. What you really meant was DataMapper.auto_upgrade!

Similarly, create! <- without consulting the manual what should this do? Attempt to create a record and raise an error if it fails? No. It forces the creation of the record, bypassing validations.

Argue against this point

Not exactly useful and just adds clutter

Annotating which attributes you have on your database is not exactly useful, as you have a "Rails Console" and "ModelName.column_names" (or just ModelName, which inspects your columns for you) which is MUCH more useful. Otherwise, this "reflection" just adds clutter, because you have the type of each column on your database AND your model, and changing one needs to change the other, and IMHO Entity-Relationship diagrams are better tools than Property APIs or Schema files.

As for your second point, you can create custom attributes on ActiveRecord too, and its as easy as creating two methods, without any plugins or such. And, to include these custom attributes on methods like to_xml is a piece of cake, something I programmed someday without even needing to use plugins.

Argue against this point

Not writing manual migrations will get you into trouble later

DataMapper.auto_upgrade! is extremely limited. It is only good for creating tables and adding new columns to existing tables. It does not work in any of the following circumstances:

* Deleting a column
* Changing the type of a column
* Changing the name of a column
* Dropping a table
* Moving data from one table to another
* Any interesting schema changes that you don't want to involve data loss

Further, in many of the cases where you would expect it to do one of the above it will instead simply silently fail to do so.

It's a cute hack that is completely unsuitable for anything except starting from an empty database. Further, there is no way to get it to sensibly interact with manual migrations, so as soon as you need to do any of the above you are suddenly forced to move everything over to doing it manually.

Argue against this point

Not works everytime

On projects with many "has many :throught", with lots of conditions, not everytime eager-loading works nicely... and it's more difficult to make it manually eager-load

Plus, Oracle adapter doesn't play nicely if you're trying to eager-load more than 1000 records... and there is no easy work-around

Argue against this point

AR is exactly ModelDriven development

ActiveModel and the Rails framework is exactly Model Driven development. You don't really care on how the data is stored, you just define the model: just define your model attributes and they are magically saved.

A this point, it's exactly the same goal with DataMapper, so both are model driven and not database driven.

Argue against this point

Is an argument missing?

Please contribute - sign in and add the argument yourself.

Is an argument inaccurate, incorrect or has it been debunked?

Please contribute a counter-argument that gives a reasonable response to the argument with a web address to a reference for further reading.

Does the text of an argument misrepresent it in a biased or inaccurate way?

Please tweet @stef on Twitter to start a conversation about how to fix it.

Embed this debate

Mash this debate

Get this debate as JSON(P)