ActiveRecord, the ugly design pattern

I first encountered the Gang of Four Design Patterns book back in 2001 when a friend lent me a copy. I didn’t immediately get it, most likely because my object oriented experience up to that point consisted primarily of small Delphi applications.

In the last few years I’ve been working on much larger systems and have come to appreciate design patterns enough to get my own copy and also to invest in Martin Fowler’s excellent Patterns of Enterprise Architecture which provides higher-level patterns aimed at large data-driven applications.

One of the design patterns presented, and indeed a core component of the Ruby on Rails framework, is that of the ActiveRecord which attempts to provide object-relational mapping.

It achieves this by specifying a single class per database table where instances of that class represent a row in the table – exposing a property for each field the row has in the database. Each ActiveRecord instance is therefore effectively a domain/business object.

So far so good but then the ActiveRecord pattern ignores the single responsibility principle by specifying that the object should also include a bunch of static methods for managing the table’s contents and retrieving instances.

What you end up with is one object with two distinct responsibilities separated by nothing but the static keyword. Static methods and fields can serve a useful purpose but dividing up responsibilities isn’t one of them and neither is to provide global-like access across your application (Singleton abusers take note).

I can think of at least two reasons why gluing two candidate objects into one physical one using the ‘static’ split causes ActiveRecord to suffer with problems:

Multiple connections

Sometimes an application requires connections to more than one database (e.g. reporting, aggregation, upgrading tools, per-user switching of database in a web application).

Static methods often rely on static fields which means you’re going to have trouble making the

data you’re going to have trouble making them behave like objects.

Inheritance mapping

There are three types of inheritance mapping techniques available.

  1. Concrete Table Inheritance – one table per concrete class containing columns for all fields of the class regardless of where they are declared
  2. Class Table Inheritance – one table per class in the hierarchy containing columns for fields of the class they are declared in only
  3. Single Table Inheritance – a single table for all classes in the hierarchy containing all columns for all possible sub-classes many of which will be null

Concrete Table is most likely where the tables created by the parent classes would have little or no value and Class Table where they do.

Single Table is what ActiveRecord implementations such as Ruby on Rails tend to use although quite how it works I’ve yet to discover… Does the parent class magically know enough about it’s child classes that it’s static methods can handle the update/select/delete? Can I ask the parent class for all objects and get a mixed collection back?

Alternatives

Fowler presents a number patterns as alternatives and many object-relational mapping (ORM) solutions including LINQ for SQL utilize them.

[)amien

3 responses

  1. Avatar for dies-el

    Hey Damieng,

    I believe Rails achieves Single Table Inheritance by adding an extra column (named 'type') to the table that lets rails know what model to use for what data. The model classes you then make use that invisibly to make sure they access the correct data.

    On a side note, the Rails book (Agile Web Develoblah, pg 341) does carry lots of warnings as to whether you should actually use STI or whether you should go for another method of categorising (e.g. tagging).

    dies-el 8 May 2007
  2. Avatar for steve

    It's not ActiveRecord that's ugly, it's the implementation of it. Whether or not to make the 'finder' methods static or put them in another, single-instance class is stylistic more than anything else - in both cases the implementations should be using a more generic implementation to do things like cacheing - whether that's done through delegation or inheritence will influence where you put those methods. I've seen it done both ways and both are adequate. Static methods of any kind are inherently a separation of responsibility, since by nature they cannot be instance-sensitive. Not using them in this case because of that actually implies that they should never be used. In fact static methods are useful where the implementation is domain-specific but not state-specific. Finder methods can actually fit that description, depending on implementation, although arguably because they all do similar things they would be better placed in an external class with policy / attribute-oriented behaviour rather than a domain-specific location.

    ActiveRecord works well as a pattern for simple stuff, but even in larger systems you'll probably find that a reasonable proportion of your classes fit it ok. Therefore being able to mix it with more complex mappings is the most pragmatic approach - have an automatic mapping for those that can use it, and manual mapping otherwise.

    Also, since overly deep inheritence structures can be limiting in their own right (the age old example of Person and subclasses Employee and Customer, but what happens if your employee is also a customer sometimes .. doh), I actually find that data inheritence is less of a problem in practice than it is in theory. Where it is necessary to have data inheritence, a case-by-case approach tends to be best rather than blanket application of one pattern. After all, it depends on the data mix / distribution as to which will be most appropriate - STI will be fine if there's only one or two small attributes, one of the other two will be more useful when there are bigger differences. And if you mapper is smart enough, you can switch between them if the data mix changes as the application evolves.

    steve 14 May 2007
  3. Avatar for Jimmy Zimms

    Millions years too late but what the hell, why not post? ;)

    It behooves me to mention that most of the time I happen to see Active Record pattern actually in use by non trivial applications is actually as a bridge between domain layers and an ORM itself. While being able to reconstitute a domain entity from the ORM and gain all the tastey wonderfullness that comes with it (auto session management, entity maps, less code, and now query providers) so far all the major vendors still all leak nondomain requirements into the objects, namely the requirement for a parametereless constructor and virtual and/or writeable properties. For some people this is a make or break issue so they bridge them via AR. That of course opens another can of worms but I can totally see where some people are coming from.

    Jimmy Zimms 4 November 2009