BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Preserving flexibility while using Active Record pattern

Preserving flexibility while using Active Record pattern

This item in japanese

Bookmarks

Active Record pattern used in Rails, Hibernate, and many other ORM tools is a data persistence pattern that allows mapping database rows to objects. This useful tool, however, is a source of confusion according to Bob Martin. “A 1:1 correspondence between tables and classes, columns and fields” is based on the presumption that tables and objects are similar, whereas, in fact, programming style oriented around data and OOP have virtually opposite characteristics.  

Objects hide data and expose behavior because public interface is built around methods. Data structures expose data and have no behavior because they typically don’t contain business rules. Hence, objects and Data structures don’t have same immunities and vulnerabilities.  Objects are immune to the addition of new types - because in OOP, algorithms don’t have any information about the kind of object they are dealing with” – but they are not immune to the addition of new functions: 

The old example: shape.draw(); makes the point. The caller has no idea what kind of shape is being drawn. Indeed, if I add new types of shapes, the algorithms that call draw() are not aware of the change, and do not need to be rebuilt, retested, or redeployed.  

[…] 

By the same token, if I add new methods to the shape class, then all derivatives of shape must be modified. 

Algorithms that use data structures are, on the contrary, immune to the addition of new functions but vulnerable to the addition of new types:  

Now consider an algorithm that uses a data structure.  

switch(s.type) { 

  case SQUARE: Shape.drawSquare((Square)s); break; 

  case CIRCLE: Shape.drawCircle((Circle)s); break; 

[…] 

Consider what happens if we add a new set of functions, such as Shape.eraseXXX(). None of the existing code is affected. Indeed, it does not need to be recompiled, retested, or redeployed. 

[…] 

By the same token if I add a new type of shape, I must find every algorithm and add the new shape to the corresponding switch statement. 

According to Bob Martin, using Active Record pattern results in a confusion typical for this “impedance mismatch between relational databases and object oriented languages.” He argues that even though “Active Record appears to be an object”, it “is meant to be used like a data structure.” It is true that it exposes behaviour since Active Record classes often contain business rule methods. However, Active Record doesn't really allow hiding data since “almost all ActiveRecord derivatives export the database columns through accessors and mutators”:

“The problem is that Active Records are data structures. Putting business rule methods in them doesn’t turn them into true objects. In the end, the algorithms that employ Active Records are vulnerable to changes in schema, and changes in type. 

[…] 

So applications built around ActiveRecord are applications built around data structures. And applications that are built around data structures are procedural—they are not object oriented. The opportunity we miss when we structure our applications around Active Record is the opportunity to use object oriented design.” 

This does not mean that Active Records should not be used. Bob Martin believes indeed that “ much of good design is about how to mix and match the different vulnerabilities and immunities of the different styles.” He advocates, however, for not using it as "the organizing principle of the application". In his opinion, it should rather belong “in the layer that separates the database from the application” and play the role of “a fine transport mechanism” between the hard data structures of database tables and the application's objects. This way, the application - "oriented around objects that expose behaviour and hide data" - is designed according to the Open Closed Principle and remains flexible for the addition of new features by adding new types.

Rate this Article

Adoption
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Community comments

  • Which came first, the object model or the database model?

    by Angus McDonald,

  • Crazy

    by Gavin King,

    • Which came first, the object model or the database model?

      by Angus McDonald,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      I think Bob's over-emphasising the problem based on implementations of Active Record where the database model (for whatever reason) is significantly different form the object model. One valid example of this is where the database is spread out amongst many servers, or across many tables for performance reasons.

      However in most cases OO developers build new applications so that the database model is decided by the persistence needs of the object model - in which case the Active Record pattern makes perfect sense.

      Bob is right that you might want to add to the basic set of data columns, and perhaps even hide some of the data persisted and only reveal it as necessary, but you can do that - at least with Rails' Active Record implementation you can. One of the beauties of Rails' approach to Active Record is that you only code the parts of your objects that are different - the basics of getting data to and from the database columns are all built-in for you. If you want to you can add new read-only properties, modify how any particular property is set or read, and generally mess about to your OO heart's content.

      Other ORM tools that are based on static/compiled languages have a harder time of this than Rails does because they lack the dynamic properties of Ruby - however that doesn't mean the pattern itself is bad ...

    • Crazy

      by Gavin King,

      Your message is awaiting moderation. Thank you for participating in the discussion.

    • Re: Crazy

      by Amr Elssamadisy,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Sadek has had the (bad) luck of always getting someone to attack his posts.... You are a patient man Sadek :)

      With that said, an ActiveRecord (as used by Rails) does strongly couple the data model and the object model. Period.

      If this is a problem, then use the data mapper pattern - which is implemented by Hibernate.


      I don't exactly know why this post requires a flame, but as Gavin said in his reply:


      It's not really worth the effort of fisking this post, but I'm bored so I'll go ahead and do it anyway.


      Now, to my humble opinion: I don't particularly like ActiveRecord because of just this point - either the database model looks like the object model or vice versa. That is probably because the majority of applications I've worked on rely on both models to be optimized.

      The data model is important for queries, reporting, etc via external tools, and the object model is important for organizing business logic.

    • Re: Crazy

      by Sadek Drobi,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Gavin,
      As you are a fan of the sun, this is from their difinition of an object from java.sun.com/docs/books/tutorial/java/concepts/...

      Hiding internal state and requiring all interaction to be performed through an object's methods is known as data encapsulation — a fundamental principle of object-oriented programming.

      I am not an OOP purist. I am rather a multi paradigm design guy, where you choose what paradigm fits the problem better. So I am not by any means defending OOP.
      Having said that, confusing domain objects with data structures is an important cause of design problems.
      Even if you are defending hibernate being flexible to decoupling both, when you start your solution, as most people do, by defining the OR mapping files, all your domain solution will be affected by the data model in the database. This bad practice is what Bob referred to as missing an opportunity to do OOP. All what he suggests is to abstract this O/R layer so that your domain model reflects better you domain problem. See Domain Driven Design by Eric Evans.

    • Re: Crazy

      by Sadek Drobi,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Sadek has had the (bad) luck of always getting someone to attack his posts.... You are a patient man Sadek :)
      :) Maybe because some of my posts oppose to the mainstream thinking. However all what I do is to reflect different points of view, and i tend to like these discussions when they are not religious ;).

      With that said, an ActiveRecord (as used by Rails) does strongly couple the data model and the object model. Period.

      I would even say in its difinition!

      If this is a problem, then use the data mapper pattern - which is implemented by Hibernate.

      Data mapper doesn's help with the problem if you are not concious about the difference between a Data Structure and an Object in your solution domain.


      I don't exactly know why this post requires a flame, but as Gavin said in his reply:


      It's not really worth the effort of fisking this post, but I'm bored so I'll go ahead and do it anyway.


      I still think that this post higlights a very important anti-pattern, where people confuse two different kind of constructs.

      Now, to my humble opinion: I don't particularly like ActiveRecord because of just this point - either the database model looks like the object model or vice versa. That is probably because the majority of applications I've worked on rely on both models to be optimized.

      The data model is important for queries, reporting, etc via external tools, and the object model is important for organizing business logic.

      I fully agree!

    • Re: Crazy

      by Gavin King,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Sadek, "state"!="internal state".

      Encapsulation means hiding the internal representation of the state. It certainly does not imply hiding state entirely. An object abstracts its internal representation of its state, exposing it via a well-defined interface.

      Trying to completely hide the state of all objects from all clients would be totally counterproductive, impractical, and absurd.

      Persistent entities are certainly able to perform this abstraction, contrary to the absurd assertions of the original poster.

    • Re: Crazy

      by Sadek Drobi,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Sadek, "state"!="internal state".

      "internal state"!="internal representation of the state"
      :)

    • I don't disagree... entirely.

      by Porter Woodward,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      There is definitely an "impedance mismatch" between object orientation and data models. A class diagram is not the same thing as an entity relationship (E-R) diagram. A very simple class diagram might be expressed as an E-R diagram - but it'd likely be a pretty weak object design.

      One of the things I find frequently in applications where data is "king" is a reliance on relatively primitive types. That's probably more of a discipline thing than any real flaw with the framework or pattern. Although I guess you might be able to say some frameworks or patterns do make it easier to slip in to certain types of anti-patterns?

      One of the things I find difficult in Active-Record style approaches (Rails, Grails, et al) is they make it difficult to "be abstract all the way". People immediately focus on the primitives - ints, strings, etc. Some of this probably stems from the typical database design process of defining fields.

      The other thing I find inhibited (maybe due to my own stupidity) is the usage of Interfaces. While the old adage about the "shape" is trotted out - the example of a class diagram using "shape" as an Interface which is implemented by rectangle and triangle is perhaps more useful when talking about applying the Active Record pattern. Because "shape" is just an interface defining behavior - likely without fields (it's not an abstract class) - but it does imply a relationship between all classes which implement it. They are all "shapes". For some reason this sort of design seems overly hard to model and capture in the Active Record pattern.

      Maybe I'm just missing something.

    • Re: Which came first, the object model or the database model?

      by Paul Beckford,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Hi Gavin,

      I agree that there are errors in the original post, but Bob is not "Crazy" or "Silly". There is an issue here that applies to both the "active record" and the "data mapper" patterns. Relational database tables represent relational data (state) not objects (state and behavior). That is why people invented OODMS to persist objects. The best representation I've seen for a relational database record is an hashmap. This is where frameworks like LINQ provide and interesting insite I believe.

      There is a mismatch between objects and relational database records and it is an issue that ORM (in all the forms I've seen) doesn't fully resolve. In fact I believe that Active Record does a better job at addressing this mismatch since it does provide some behavior to each hashmap (data record) by adding generic persistence methods like save, thus making each hashmap more of an object. An object should be able to persist itself don't you agree?

      Encapsulating each hashmap within a real domain object is overkill in most cases I agree, but it is an interesting idea. Generally ORM sorts of works most of the time, but there are edge cases where it does feel decidedly not OO. Perhaps taking the functional approach and forgetting encapsulation is the better paradigm here. Accepting that relational data is just data, and not objects may be more fruitful. After all the majority of objects in an ORM domain model tend to be anemic (just mutators). So would it not be better to admit that these domain entities are just data and represent them as hashmaps instead of pretending that we've got a bunch of domain objects?

      Just thinking out aloud...

      Paul.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

BT