First-Class Relationships, or, It's All Just CRUD
Posted by Jeremy Voorhis Mon, 26 Jun 2006 23:16:00 GMT
One classic yet braindead way of creating an application’s domain model has been to read your requirements document and underline the nouns. Sadly, some domain modelers never reach any further than this. Other savvy developers, however, may begin a project this way in order to drive a stake in the ground so work may progress and a feedback loop may be established between customer and developer. The important distinction here is that for the savvy developer, the domain is incomplete. Creating a rich domain model is, in fact, an emergent process.
One barrier for many inexperienced domain modelers is that they think each model must be a tangible thing. When describing a graph of domain object, however, we often have as much to say about the edges of that graph as we do about the nodes. It is at these times that we should think about promoting those edges to being their own full-fledged nodes.
For example, let’s start with a simple Rails app – a news site where readers may subscribe or unsubscribe to news categories and receive news stories from those categories in their personalized Atom feed. A naive domain model may allow a direct association between a User and a NewsCategory.
class User < ActiveRecord::Base
has_and_belongs_to_many :news_categories
end
class NewsCategory < ActiveRecord::Base
has_and_belongs_to_many :users
end
That could work, but what if we want to record additional metadata about when that User subscribed or unsubscribed? The direct association provides no place for us to store that. By promoting that association to a full-fledged model named NewsSubscription, we may store that metadata as attributes of the new model. Furthermore, we don’t necessarily introduce any new impedence by directing the relationship through this new model – ActiveRecord’s has_many :through association allows us to skip over a user’s subscriptions directly into the targeted news categories.
class User < ActiveRecord::Base
has_many :subscriptions
has_many :news_categories, :through => :subscriptions
end
class NewsCategory < ActiveRecord::Base
has_many :subscriptions
has_many :users, :through => :subscriptions
end
class Subscription < ActiveRecord::Base
belongs_to :user
belongs_to :news_category
end
DHH’s talk at Railsconf and Jim Greer’s blog post reminded me of this principle and suggested a new heuristic for a missing relationship model: entangled call sites in the form of controller actions. When we have a rich domain model which treats vital relationships as first-class citizens, complex operations within our domain can be mapped to simple CRUD operations on those relationship models. I look forward to exploring this in the following months, as well as diving back into Eric Evans’ remarkable Domain-Driven Design.

Interesting to hear more rumblings of Evans’ book (it’s apparently a massive one with other TWers – in fact the senior dev. I interview with also recommended it to me).
I posted a [brief follow-up](http://www.oobaloo.co.uk/articles/2006/06/27/domain-driven-design) along with some pointers from work we’ve been doing on the TW project I’m currently on.
Have to keep us posted with some tidbits from the projects you guys taken on at Planet Argon!
Great followup, Paul!