Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 695
Kenneth Cochran Avatar asked Jan 23 '23 01:01

Kenneth Cochran


2 Answers

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

like image 169
Jeff Sternal Avatar answered Feb 14 '23 12:02

Jeff Sternal


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.

like image 43
Daniel Robinson Avatar answered Feb 14 '23 10:02

Daniel Robinson