开发者

How many levels of abstraction do I need in the data persistence layer?

开发者 https://www.devze.com 2022-12-09 23:01 出处:网络
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

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 o开发者_C百科n 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.


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).


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.


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


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消