views:

192

answers:

5

I'm writing an application using DDD techniques. This is my first attempt at a DDD project. It is also my first greenfield project and I am the sole developer. I've fleshed out the domain model and User interface. Now I'm starting on the persistence layer. I start with a unit test, as usual.

[Test]
public void ShouldAddEmployerToCollection()
{
    var employerRepository = new EmployerRepository();
    var employer = _mockery.NewMock<Employer>();

    employerRepository.Add(employer);
    _mockery.VerifyAllExpectationsHaveBeenMet();
}

As you can see I haven't written any expectations for the Add() function. I got this far and realized I haven't settled on a particular database vendor yet. In fact I'm not even sure it calls for a db engine at all. Flat files or xml may be just as reasonable. So I'm left wondering what my next step should be.

Should I add another layer of abstraction... say a DataStore interface or look for an existing library that's already done the work for me? I'd like to avoid tying the program to a particular database technology if I can.

+5  A: 

With your requirements, the only abstraction you really need is a repository interface that has basic CRUD semantics so that your client code and collaborating objects only deal with IEmployerRepository objects rather than concrete repositories. You have a few options for going about that:

1) No more abstractions. Just construct the concrete repository in your top-level application where you need it:

IEmployeeRepository repository = new StubEmployeeRepository();
IEmployee           employee   = repository.GetEmployee(id);

Changing that in a million places will get old, so this technique is only really viable for very small projects.

2) Create repository factories to use in your application:

IEmployeeRepository repository = repositoryFactory<IEmployee>.CreateRepository();
IEmployee           employee   = repository.GetEmployee(id);

You might pass the repository factory into the classes that will use it, or you might create an application-level static variable to hold it (it's a singleton, which is unfortunate, but fairly well-bounded).

3) Use a dependency injection container (essentially a general-purpose factory and configuration mechanism):

// A lot of DI containers use this 'Resolve' format.
IEmployeeRepository repository = container.Resolve<IEmployee>();
IEmployee           employee   = repository.GetEmployee(id);

If you haven't used DI containers before, there are lots of good questions and answers about them here on SO (such as Which C#/.NET Dependency Injection frameworks are worth looking into? and Data access, unit testing, dependency injection), and you would definitely want to read Martin Fowler's Inversion of Control Containers and the Dependency Injection pattern).

Jeff Sternal
+1 for repository interface
Chris Marisic
EmployerRepository does in fact implement an IEmployerRepository interface, which exposes CRUD operations. Are you suggesting that I should implement database aware concrete classes such as SQLServerEmployerRepository, OracleEmployerRepository, FlatFileEmployerRepository, etc until I decide on a database technology?
codeelegance
In this case I was trying to TDD my way to an implementation of IEmployerRepository but I guess I can't do that unless I either add another level of abstraction below the repository(which doesn't seem to add anything useful), write and test several database-dependent implementations or pick a database and stick with it.
codeelegance
Ah I understand your question a bit better now (I think!), and I've updated the answer accordingly. (And I think you should continue using a stub repository until you know which persistence technology you want.)
Jeff Sternal
It's true, if your requirements won't involve supporting multiple persistence technologies, adding the additional abstraction layer won't be useful - *except to enable TDD* (or really even just unit testing), which I think is worth the small investment in decoupling!
Jeff Sternal
+1  A: 

At some point you will have to make a call as to what your repository will do with the data. When you're starting your project it's probably best to keep it as simple as possible, and only add abstraction layers when necessary. Simply defining what your repositories / DAOs are is probably enough at this stage.

Usually, the repository / repositories / DAOs should know about the implementation details of which database or ORM you have decided to use. I expect this is why you are using repositories in DDD. This way your tests can mock the repositories and be agnostic of the implementation.

Daniel Robinson
A: 

I wrote a blog post on implementing the Repository pattern on top of NHibernate, I think it will benefit you regardless of whether you use NHibernate or not.

Creating a common generic and extensible NHiberate Repository

Chris Marisic
A: 

One thing I've found with persistence layers is to make sure that there is a spot where you can start doing abstraction. If you're database grows, you might need to start implementing sharding and unless there's already an abstraction layer already available, it can be difficult to add one later.

James Bailey
A: 

I believe you shouldn't add yet another layer below the repository classes just for the purpose of unit testing, specially if you haven't chosen your persistence technology. I don't think you can create an interface more granular than "repository.GetEmployee(id)" without exposing details about the persistence method.

If you're really considering using flat text or XML files, I believe the best option is to stick with the repository interface abstraction. But if you have decided to use databases, and you're just not sure about the vendor, an ORM tool might be the way to go.

Tiago Brandes