Persistence in Ruby on Rails is done by most people through the ActiveRecord ORM, which follows and is named after the Active Record pattern. There are other Ruby ORMs (like DataMapper) that don’t follow the Active Record pattern, but they aren’t used nearly as much.
Some .NET people seem to sneer at Ruby’s use of Active Record. There is a .NET implementation of the Active Record pattern (Castle ActiveRecord, which is a layer on top of NHibernate). In .NET and Java, the Active Record pattern is somewhat frowned upon and is usually considered not as good as a more robust, flexible ORM like NHibernate or the Entity Framework where your database tables don’t have to look just like your objects.
Some people would say that the Active Record pattern violates separation of concerns because the entity objects know how to load and save themselves. One big problem in the .NET world is that since an entity object can load itself, it has to do so with static methods (e.g. User.Load(3)), which means that now you can’t stub that out in a test (if you’re in a static-typed language). In a dynamic language like Ruby you don’t have the testability problem because you can stub out class methods (analogous to static methods in .NET).
There are still more concerns posed about the Active Record pattern. Is it maintainable in the long term? What if you don’t want your database tables to look like your objects? What if I would rather have separate domain service classes to do the persistence? What about the repository pattern?
If you’re a .NET person, you have to think about life in a truly dynamic world, where you don’t have the testability issues. Are any of those other things really a concern? If you’re starting a new app, what are the chances that your database tables won’t look like your objects? In most cases, I would say slim to none! If you have an application where you have some data concerns that would require to make your data model have a different shape than your objects, then you can’t use ActiveRecord. If you want to use an object database like MongoDB, then you use an ORM that works with MongoDB (like Mongoid). If you’re building a new app on top of an existing database, you may need something that will allow you to do different kinds of custom mappings (although you might be able to shoehorn it somewhat). But for the large majority of everyone else, what is the real concern?
The added flexibility that something like NHibernate or DataMapper gives you comes with a price — added complexity. Fluent NHibernate and some of the new Entity Framework stuff allow you to do convention based mapping so that it takes away a lot of this pain. If your domain model objects have a different shape than your database tables, you could have performance concerns (although not always).
What you get from ActiveRecord is simplicity, and simplicity is worth something. When you use ActiveRecord, you are essentially saying that your database and codebase are under your control, so you can have your database tables match the domain model objects using certain conventions. Your database becomes a very thin layer that does nothing more than store and retrieve data, and all of the business logic is in the business layer (where it should be in my opinion, regardless of your ORM). If you have to change your domain model objects for some reason, you change the database too. So I’m not constrained by my database because all of my logic is in the business layer, which allows me to easily change either layer whenever I need to. The benefit to this is that you don’t need to write any code to map your objects to your database and you don’t need as much hand-rolled SQL (you’re always going to have hand-written SQL for some queries no matter what).
The Rails project that I’m currently on is four years old. We use ActiveRecord as our ORM. I don’t see any situations where it really constrains us at all or makes our code less maintainable. I think it makes things simpler because it is assumed that the database tables and domain model objects look the same (you can override some of that if you need to). I feel like there is a lot of fear and uncertainty in the .NET world over ActiveRecord because the pattern isn’t really accepted in the .NET world (for good reasons). But that doesn’t mean that it doesn’t fit well in a dynamic language like Ruby, where I think it works quite well.
So if you’re a .NET person who is skeptical about ActiveRecord in Ruby, I would encourage you to have an open mind. There are other alternatives if it doesn’t fit your application, but in most cases I think it gets the job done quite well.
SubSonic will give you ActiveRecord in .Net, too.
Gotta admit, when I first started looking at Rails, the ActiveRecord pattern felt kind of dirty. The more I used it and understood what was going on with how Rails approaches the domain, it made more sense. (Though I still wondered what a Rails dev would do with a nice, old, brownfield database. You know…something from The Enterprise.)
That said, I’ve actually started doing more and more MongoDB in my Ruby work (more Sinatra than Rails, too) and using Mongoid has kind of taken me away from the Active Record pattern, but I still kind of loop it in and it seems right. I’m sure I’m bastardizing something, but I’m happy at the end of the day and everything still feels like it’s in the right place.
First, I’d say not just the .Net world frowns upon the ActiveRecord pattern. I know what you mean, though.
The problem is a basic one. I think we all need to reach back to the fundamentals of OOD every once in a while and ask if our designs violate the fundamental principles of objects. In this case, mixing data access in with an entity reduces cohesion. That may not be a problem, but as your system gets more complex, it inevitably will.
As I have said before, if your data entities don’t double as business entities, this may be fine, but when you start put too much unrelated behavior in your objects, you begin to have cohesion problems.
Take for example, the method save. Save may mean something different depending on context. In the context of ActiveRecord, it may mean “persist this object.” In the context of the business, it may mean “keep this for later.”
Also, many times, more complex systems involve distributed transactions, and service tie-ins. If you write your code without a layer of indirection between your (raw) data and your entities, then these things become problematic. You will have to end up using two approaches for persistence, which then forces knowledge of the adjacent layers’ inner workings to leak into your entity layer.
ActiveRecord is good when you know your app is and will remain simple, and the data is and always will be under your direct control. This is one of the reasons rails is derided is as “not enterprise ready.”
I’m not attacking ActiveRecord or Rails, but it should be understood what exactly the consequences of adopting this [IMO] anti-pattern are.
Since you can replace the static method for testing with Pex’s Moles, I’m not sure that testability should be such a big concern anymore. A bigger concern, in C# today is the relative lack of abstraction of static methods (there are no static interfaces). There is a type-safe solution to this problem, such as Haskell’s type classes. Duck typing also solves this problem, although it creates others, and is less of a natural fit for this issue than for other use cases.
I suspect that you have not had maintainability concerns with ActiveRecord in your Rails app because you are happy with the ActiveRecord interface, which is, after all, a fairly safe route to take in the Rails world. I further suspect that you might have maintainability problems in a big way if you ever wanted to change to a data service with a very different interface, like Hibernate (not that you would necessarily choose that one!). But I will freely admit that I have less experience with Ruby/Rails than C#.
My more significant architectural concern with ActiveRecord is actually the same concern I have with making a data entity and the business entity the same, single type. I don’t think it is an accurate representation of a database (or data service) record, which, after all, has no methods. Fowler’s argument against the so-called “anemic domain” is surprisingly, for him, weak. He essentially says that maintaining two types is difficult. But you are already defining database metadata, either directly in the database, or in your object model. It is only difficult to maintain these types if you actually have to do any maintenance. If you define your schema in one place, and then generate code (which you can do with static code generation or with dynamic typing, at runtime) then there is really no additional maintenance.
Craig,
Fowler’s argument for the anemic domain applies to using entities that are “acted on” by transaction scripts (services in the modern lexicon).
To use his terms, the data entity is a DTO, and the business entity is a POJO (more appropriately, a POCO). In this case, it’s not anemic, since the DTO’s only purpose is to transfer state from one tier (your database) to another (your application).
Michael,
I see where you’re coming from with the data objects vs business objects, but in most apps I’ve worked on, I think that would be overkill. There are definitely cases where that makes sense (brownfield database, crazy persistence problems) but ActiveRecord wasn’t designed for those situations (as you pointed out). But I think it can work for most situations that aren’t as complex.
Jon,
I think that you have been lucky for the most part. The majority of development out there is slogging through a legacy of bad decisions, and imperfect integration scenarios. From the perspective of an architect, I’d have to say that assuming that your system won’t regress in to one of these is idealistic at best. Adopting a pattern like ActiveRecord, which forces coupling, shouldn’t be avoided, but it should be approached with the knowledge that it is an anti-pattern that could potentially create technical debt.
YAGNI doesn’t always apply. In the case of architectural or framework decisions, refactoring tends to be expensive and tends to affect large amounts of code. Imagine the impact on your unit tests if you decide that your system has grown sufficiently complex that you now need to move to a repository pattern from active record!
Michael, even if you take DTOs out of the picture, I don’t think Fowler’s approach lends itself to a functional style, where data and behavior are (for good reason) separated. It seems to me to be pretty closely tied to his own, more OO style of work, which he pretty much acknowledges. But OO is a methodology — a good one, often — not a goal, and calling anything not OO an “anti-pattern” and a “horror” (his words, not mine; he also calls himself an “object bigot,” which I won’t contest) is self-limiting.
In general, Fowler does much better describing the things he does do than the things he doesn’t, I think.
Good point on idealists in young projects. :)
Craig,
You’re right that the anemic domain is a criticism that only holds water in an OO world. I believe that that was the context of the criticism.
The problem with the anemic domain model is that it’s not responsible for its own state. I don’t think anyone would have ground to argue that this is a problem in functional languages, since state mutation is not a concept the paradigm supports.
Michael, exactly right. It’s solving a problem which barely exists in some not-purely-OO environments — a problem which even “good” OO arguably encourages.* Which makes the criticism that using an “anemic” domain means you’re not sufficiently OO-pure kind of superficial to me. It’s like saying “don’t write bad code.”
* Despite this, I will continue to write OO code. I just don’t think it’s the be-all and end-all of good design.
Jon,
Just wondering whether rails can handle these nontrivial (meaning not 1:1) mappings easily:
– inheritance
– many-to-many
– IDictionary (is it “map” in ruby?)
Other than that, I’d say yes, my db looks pretty much the same as my entities.
Ulu,
Inheritance – yes
Many to many – yes (either through another object that you specify or just a simple two-column table that doesn’t have a Ruby class)
Dictionary – not sure on that one, but I haven’t done that in .NET either. It would be really easy to create an object that wrapped a dictionary (Ruby calls them Hashes, but the concept is the same)