Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why all the Active Record hate? [closed]

As I learn more and more about OOP, and start to implement various design patterns, I keep coming back to cases where people are hating on Active Record.

Often, people say that it doesn't scale well (citing Twitter as their prime example) -- but nobody actually explains why it doesn't scale well; and / or how to achieve the pros of AR without the cons (via a similar but different pattern?)

Hopefully this won't turn into a holy war about design patterns -- all I want to know is ****specifically**** what's wrong with Active Record.

If it doesn't scale well, why not?

What other problems does it have?

like image 468
Adam Tuttle Avatar asked Aug 11 '08 15:08

Adam Tuttle


People also ask

Why Active Record is anti pattern?

Active Record gone crazy As mentioned above in most cases your application is not that simple so this pattern quickly becomes an anti-pattern: You start with a big application, you have limited time, and there it is the framework in the shelf that could help you deliver “value” very quickly.

What is meant by active record?

1 What is Active Record? Active Record is the M in MVC - the model - which is the layer of the system responsible for representing business data and logic. Active Record facilitates the creation and use of business objects whose data requires persistent storage to a database.

How do I delete a row in active record?

If you want to delete many rows quickly, without concern for their associations or callbacks, use delete_all instead.


2 Answers

There's ActiveRecord the Design Pattern and ActiveRecord the Rails ORM Library, and there's also a ton of knock-offs for .NET, and other languages.

These are all different things. They mostly follow that design pattern, but extend and modify it in many different ways, so before anyone says "ActiveRecord Sucks" it needs to be qualified by saying "which ActiveRecord, there's heaps?"

I'm only familiar with Rails' ActiveRecord, I'll try address all the complaints which have been raised in context of using it.

@BlaM

The problem that I see with Active Records is, that it's always just about one table

Code:

class Person     belongs_to :company end people = Person.find(:all, :include => :company ) 

This generates SQL with LEFT JOIN companies on companies.id = person.company_id, and automatically generates associated Company objects so you can do people.first.company and it doesn't need to hit the database because the data is already present.

@pix0r

The inherent problem with Active Record is that database queries are automatically generated and executed to populate objects and modify database records

Code:

person = Person.find_by_sql("giant complicated sql query") 

This is discouraged as it's ugly, but for the cases where you just plain and simply need to write raw SQL, it's easily done.

@Tim Sullivan

...and you select several instances of the model, you're basically doing a "select * from ..."

Code:

people = Person.find(:all, :select=>'name, id') 

This will only select the name and ID columns from the database, all the other 'attributes' in the mapped objects will just be nil, unless you manually reload that object, and so on.

like image 102
Orion Edwards Avatar answered Oct 22 '22 08:10

Orion Edwards


I have always found that ActiveRecord is good for quick CRUD-based applications where the Model is relatively flat (as in, not a lot of class hierarchies). However, for applications with complex OO hierarchies, a DataMapper is probably a better solution. While ActiveRecord assumes a 1:1 ratio between your tables and your data objects, that kind of relationship gets unwieldy with more complex domains. In his book on patterns, Martin Fowler points out that ActiveRecord tends to break down under conditions where your Model is fairly complex, and suggests a DataMapper as the alternative.

I have found this to be true in practice. In cases, where you have a lot inheritance in your domain, it is harder to map inheritance to your RDBMS than it is to map associations or composition.

The way I do it is to have "domain" objects that are accessed by your controllers via these DataMapper (or "service layer") classes. These do not directly mirror the database, but act as your OO representation for some real-world object. Say you have a User class in your domain, and need to have references to, or collections of other objects, already loaded when you retrieve that User object. The data may be coming from many different tables, and an ActiveRecord pattern can make it really hard.

Instead of loading the User object directly and accessing data using an ActiveRecord style API, your controller code retrieves a User object by calling the API of the UserMapper.getUser() method, for instance. It is that mapper that is responsible for loading any associated objects from their respective tables and returning the completed User "domain" object to the caller.

Essentially, you are just adding another layer of abstraction to make the code more managable. Whether your DataMapper classes contain raw custom SQL, or calls to a data abstraction layer API, or even access an ActiveRecord pattern themselves, doesn't really matter to the controller code that is receiving a nice, populated User object.

Anyway, that's how I do it.

like image 26
Sam McAfee Avatar answered Oct 22 '22 06:10

Sam McAfee