Monthly Archives: November 2009

Persistence Ignorance and ActiveRecord

Jimmy Bogard recently tweeted that Persistence Ignorance does not apply to the ActiveRecord pattern.  I couldn’t agree more because ActiveRecord is about creating a strong coupling to the database schema.

Persistence Ignorance is about keeping your business objects ignorant of the underlying mechanism used to persist them and the schema in which they are persisted.  In the case of ActiveRecord, it doesn’t apply because these objects are intimately coupled to the schema itself.  ActiveRecord objects may implement a special base class, have lots of decorator attributes and other such things.  But ActiveRecord objects should also be simple DTOs–ones that can be easily serialized across the wire if necessary.

Just because we are tightly coupled to a database schema does not mean we have to be coupled to any particular database product or vendor.  In other words, we should still be able to swap out a relational database using another one from another vendor without having to modify our application code.

Using CQRS this becomes less than trivial because the only place where we use a relational database is for reporting.  Incidentally, this happens to be the ideal location for a relational database because they’re really, really good at querying data.

By using the proper abstraction to isolate your ActiveRecord-based technology, you should be able to swap out not only your database product, but also your data access technology and your application shouldn’t even notice.

The Software Simplist

Udi Dahan is known as the “Software Simplist”.  What does he mean by simple?  Is he saying that software cannot be used to tackle complex problems?  Or does he mean that we work at a problem until a simple, clean, and concise solution presents itself?  And what about “the simplest thing that could possibly work”?

Here are a few of my favorite quotes regarding simplicity:

"I wouldn’t give a fig for the simplicity on this side of complexity; I would give my right arm for the simplicity on the far side of complexity" ~ Attributed to Oliver Wendell Holmes Jr.

“Simplicity does not precede complexity, but follows it.” Alan Perlis

"Complexity means distracted effort. Simplicity means focused effort." ~ Edward de Bono

From these statements we learn that true elegance and simplicity only come after diving head first into a problem and then seeing all the various nuances and angles of the problem.

That’s why I tend to gravitate towards Udi’s down-to-earth approach to tackling software.  It’s when you’ve been through the fire that you gain the perspective and understanding to solve a problem in a simple way.

The next time you’re convinced you’ve found a simple solution, take a step back and consider if you’re on the near or far side of complexity.

CQRS: Reporting Database Access Strategies

One of the things that I love about CQRS is that it completely eliminates the impedance mismatch that you normally experience with traditional ORMs. It is incredibly compelling to be able query and retrieve all values necessary for a particular report or screen in a single database call because of a denormalized database schema.

Over the past year there has been significant debate regarding Microsoft’s LINQ to SQL, Entity Framework, and ADO.NET Data Services data access strategies. Further, NHibernate with the 2.0+ release has become the de-facto standard in many ALT.NET shops. Other solutions such as LLBLGen and Subsonic are also gaining more and more acceptance and traction.

With all of these options, the question becomes: which one should we use? The answer from a CQRS perspective is…it doesn’t matter. That’s right. It doesn’t matter. One of the primary reasons this works is because the only place you need a relational database is in your reporting context and it follows the ActiveRecord pattern where the class structure mimics the table schema. Most data access mechanisms handle this scenario very, very well. But you’ve got to expose your data access through the correct abstraction.

In a project I am working on, we simply created an abstraction of our data access mechanism through an IAccessStorage interface which had a single property with the following signature:

IQueryable Items { get; }

It could be queried using either a “SQL-like” LINQ expression or like this:

storage.Items.Where(user => user.Id == 12345)

As a proof of concept, I created a class to abstract each persistence mechanism, e.g. NHibernateStorage, LinqToSqlStorage, EntityFrameworkStorage, and SubsonicStorage. Using dependency injection, I was easily able to swap out which storage mechanism I used and my application code was none the wiser.

The caveat in all of this is that each one must have a LINQ provider. While I’ve run into some quirks in NHibernate’s LINQ provider related to “joins”, this isn’t really an issue for the reporting database because you don’t really want to be doing joins anyway.

An additional issue that you may notice concerns the DTO/class files generated by the above technologies. This may be a small issue because the “User” object generated by Subsonic is not the same one generated LINQ to SQL or the Entity Framework. In the end, it isn’t that big of a deal because these objects are simple DTOs with zero behavior. As long as they don’t have behavior, you’re okay, so you may end up with a dependency on the DTOs. If you really wanted to maintain purity, you could potentially use a solution like AutoMapper to map the generated objects to your own POCOs. [Update: The “dynamic” keyword in C# is another possible resolution to this.]

Conclusion

With all of the arguing that is happening regarding the various persistence mechanisms and their relative strengths and weaknesses, using CQRS allows us to completely avoid dependencies on any of the aforementioned projects thus allowing us to freely choose whichever one we see fit at that time. And if we make a mistake or discover additional capabilities in another ORM, we can swap implementations with virtually no effort. Thus, we are now doubly insulated from the database and we can swap both database and data access technologies at will.