NWorkspace, why?

My current pet project is called NWorkspace and is (or, at least, might become) what I call adapters for different persistence solutions. Nope, it's *not* another OR Mapper for .NET, which might come as a shock!
:-)
Instead, what NWorkspace does is try to reuse the functionality of the current OR Mappers. Pretty wild, huh?

First of all, letís take a step back. As you might have noticed, if you are following my blog, I'm currently working on a couple of DDD projects. What I have noticed is that I find myself writing some silly code purely to be able to run automatic tests against a stub which simulates the database and against the real database (when it has been built).

Sure, I know, I can run the majority of tests against the Domain Model without dealing with persistence at all. I do that, and thatís not the problem here. The problem is when I take the next step, so to speak, and want to test the interaction where repositories are involved.

What also happens is that I want to let users try out the application before the database has even been created. What they get instead is just a stub, so that they can get a feel for the application and provide feedback early on. This allows me (and the team) to make pretty radical changes to the Domain Model and UI without having to make any changes to a database schema as well. It's also extremely easy when it comes to distribution and installation for early demos.

You may be wondering what this stupid code is. Well, assume I use a custom stub for tests without database, and NHibernate for example as the OR Mapper for tests with the database. Typically, what I do then is create a specific interface for each repository, such as ICustomerRepository, for example, which I implement by the classes CustomerRepositoryStub and CustomerRepository. The code in those classes is pretty similar but different, so I need two of them. They get information from the consumer as a constructor parameter, such as a stub instance, in the case of the stub implementation, and an ISession, in the case of NHibernate. The CustomerRepository can then use the ISession for stating database questions and for associating instances with the Unit of Work.

When it comes to the CustomerRepositoryStub, there is no database against which to ask questions, so the stub-repository will iterate lists for filtering out the requested instances instead. Pretty different, as I said.

What also happens is that this affects the test code. It's not just how the instantiation of the repositories is done that differs, but how the transaction is dealt with, etc.

So, what I usually get is three test classes (one is a base class) per repository, one repository interface and two repositories (in two separate assemblies). Not an extreme amount, perhaps, but it doesn't feel too good.

So, I started thinking about how hard it would be to create some abstraction for which I could create implementations for different persistence providers. This would mean that I could code against that abstraction in both the tests and the repositories, and in doing so reduce the amount of dumb code. I could probably see the NH-interface as that abstraction and let the stub implement it, or I could implement a stub dialect for NH... However, I thought this might be a generic problem for several OR Mappers that I would be working with, so I started another route. That's where NWorkspace comes in.

So, NWorkspace is mainly a couple of simple interfaces (and some helpers), which are implemented by adapters so that NHibernate can be used under the surface. Or my stub implementation, or probably many other OR Mappers as well, if adapters are written for them. However, please note that I don't think this will be used for switching between different OR Mappers in the same project. It might help a bit, but definitely not the whole way, even if you switch between similar OR Mappers that are both POCO-style, for example. There are a lot of semantic differences that NWorkspace won't be able to hide. The main goals of NWorkspace are instead something like:
  • Reducing the amount of dumb code when writing tests against both stubs and databases.

  • Simplifying the API for consumers of OR Mappers (when a simple API is all that is needed).

  • Providing a "standard" API (including querying) which will make it cheaper for developers moving between different OR Mappers in different projects.
When I write the tests against IWorkspace (which is the main interface of NWorkspace), I only need one test class per repository (or at least "all" the code could move to the base class). I also only need one repository per aggregate, and I can (if I want to) skip the repository interface. I can also move back the repository into the Domain Model assembly again.

My friend Mats Helander considered something similar to NWorkspace a couple of months ago, which he called NORM. Here, the idea was to define a couple of standard interfaces which .NET OR Mappers could implement to support that standard. NWorkspace takes a different approach and doesn't require OR Mapper vendors to implement anything. Instead, anyone who is interested could write an adapter for adapting any OR Mapper to NWorkspace. Sure, it will mean some performance overhead, but probably not too much for most cases.

If you're wondering about the name, it's inspired by Christoffer Skjoldborg's and my project called Valhalla. There, our class, which has the Unit of Work and the Identity Map, is called Workspace. NWorkspace (or its adapter implementations) won't typically *have* Unit of Work/Identity Map, but will use those in the mappers instead.

NWorkspace is little more than an idea right now, and is definitely not ready for real use. I have written a small proof of concept and I'm very eager to move on. If you are interested, watch this blog. I'll be talking about the basic API in a few days' time.

Comments?