Why I Don't Like ActiveRecord for Domain Model Persistence
Join the DZone community and get the full member experience.
Join For FreeWhen it comes to a rich domain modeling, I am not a big fan of the ActiveRecord model. The biggest problem that it entails is invasiveness - the persistence model invades into my domain model. And this was also my first reaction to the Lift-CouchDB integration module which was released recently.
The moment I say .
class Person extends CouchRecord[Person] {
//..
}
my domain model becomes tied to the persistence concerns.
When I started scouchdb,
my very first thought was to make it non-invasive. The Scala objects
must be pure and must remain pure and completely oblivious of the
underlying persistence model. In the age of polyglot persistence there
is every possibility that you may need to persist a domain model across
multiple storage engines. I may be using a JPA backed relational store
as the enterprise online database, which gets synchronized with some
offline processing that comes from a CouchDB backend. I need the domain
model persistence in both my Oracle and my CouchDB engines. The
ActiveRecord pattern is difficult to scale to such requirements.
Here's what I implemented in scouchdb ..
// Scala abstraction : pure
case class ItemPrice(store: String, item: String, price: Number)
// specification of the db server running
val couch = Couch("127.0.0.1")
val item_db = Db("item_db")
// create the database
couch(item_db create)
// create the Scala object : a pure domain object
val s = ItemPrice("Best Buy", "mac book pro", 3000)
// create a document for the database with an id
val doc = Doc(item_db, "best_buy")
// add
couch(doc add s)
// query by id to get the id and revision of the document
val id_rev = couch(item_db by_id "best_buy")
// query by id to get back the object
// returns a tuple3 of (id, rev, object)
val sh = couch(item_db by_id("best_buy", classOf[ItemPrice]))
// got back the original object
sh._3.item should equal(s.item)
sh._3.price should equal(s.price)
It's
a full cycle session of interaction with the CouchDB persistence engine
without any intrusion into the domain abstraction. I am free to use
ItemPrice domain abstraction for a relational storage as well.
CouchDB
offers a model of persistence where the objects that we store should be
close to the granularity of domain abstractions. I should be able to
store the entire Aggregate Root of my model components directly as
JSON. ActiveRecord model offers a lower level of abstraction and makes
you think more in terms of persistence of the individual entities. The
thought process is so relational that you ultimately end up with a
relational model both in terms of persistence and domain. With CouchDB
you need to think in terms of documents and views and NOT in terms of
relations and tables. I blogged on this same subject some time back.
The
philosophy that I adopted in scouchdb was to decouple the domain
entities from the persistence layer. You hand over a pure Scala object
to the driver, it will extract a JSON model from it and write it to
CouchDB. I use sjson
for this serialization. sjson works totally based on reflection and can
transparently serialize and deserialize Scala objects that you hand
over to it. From this point of view, the three aspects of managing
domain abstractions, JSON serialization and persistence into CouchDB
are totally orthogonal. I think this is difficult to get with an
ActiveRecord based model.
Opinions expressed by DZone contributors are their own.
Comments