2

Please see the code below:

public interface IUnitOfWorkWrite <TSession> : IDisposable
    {
        TSession Session { get; }
        void Commit();
        void Rollback();
        ITransaction BeginTransaction();
    }
}

This interface is contained in the domain layer. The service layer provides an implementation. Therefore the domain layer is not dependent upon anything except NHibernate i.e. NHibernate has to be installed for Session and ITransaction.

Should the domain layer be dependent on NHibernate in this scenario?

VoiceOfUnreason
  • 34,589
  • 2
  • 44
  • 83
w0051977
  • 7,139

3 Answers3

5

Should the domain layer be dependent on NHibernate in this scenario?

From a purist perspective: no it should not. The domain layer shouldn't be carrying around a bunch of dependencies on your persistence solution. "UnitOfWork" and "Transaction" are not part of the ubiquitous language of most business domains.

From the onion perspective: your dependency is pointing the wrong way. Instead of adding an NHibernate dependency, you can put an agnostic service provider interface into your module, and then pass an NHibernate implementation of the agnostic interface to the ports that need it.

In practice: I doubt that the DDD police are going to come after you.

Domain Services can access the database

Not quite right. Implementations of Domain Services can access the database. The interface, used by the domain model, just expresses the service in the domain language. The implementation is going to be relying on other application and infrastructure services - ie, other service providers of interfaces that it defines, and it's turtles all the way down.

The thing that actually talks to the NHibernate is probably going to be an infrastructure service.

In other words, your composition root is probably going to look something like

NHibernateThing nhibernate = ...
DomainServiceImpl.Adapter infrastructure = InfrastructureService.using(nhibernate)
DomainService service = DomainServiceImpl.using(infrastructure)

where you are wiring each adapter into the appropriate port in turn.

Reread Parnas; at a fundamental level, NHibernate is the result of a decision, and you want module boundaries in place that separate the pieces that depend on that decision from the pieces that do not. That makes it easier to change when the time comes.

But - you should be balancing this against the risk of change; if NHibernate is always going to be part of your solution, then you shouldn't be investing in decoupling it from your domain.

VoiceOfUnreason
  • 34,589
  • 2
  • 44
  • 83
4

Your domain layer is where you add value to the software you are building. NHibernate is a means to an end. Tying the value of your software to a solution that doesn't really matter is a strategic error. What I mean by that is whoever is paying for this or whoever is using this really doesn't (or shouldn't) care how you read and write data.

The problem comes when you suddenly need to get away from NHibernate. Let's say you find out right before you release that NHibernate has a fundamental security flaw and no fix is in sight? If you've coupled your value (the domain layer) to this package, you're screwed. Or, more likely, some other tool comes out that you'd much prefer to use but the switching cost is too high to justify.

As CatWhisperer mentions in the comments below, there are also other practical reasons not to do this. For one it can complicate mocking and other types of testing. It also means that you are roughly tying your domain model to a persistence model. This makes the software you are creating less reusable in that you are preventing using your domain model with other types of data sources. For example, let's say someone wants to run a Monte Carlo simulation using your domain model. I'm not saying it's necessarily impossible to do this with NHibernate but it's going to add a lot of complexity.

I work with software from a vendor who built a major piece of their implementation using a proprietary feature of an expensive platform. At the time they decided this, it was common to run software in this way so they thought it was fine. Now this platform is a significant portion of the cost of running their software: a huge strategic blunder. Whatever time they think they saved by using this feature is completely overwhelmed by the reality that none of their customers want to pay for this expensive platform. It makes their software more expensive and essentially cuts into their profits because they don't see a dime of that added cost. The cost of removing the dependency is also high. This completely avoidable mistake will cost them many millions of dollars in revenue.

JimmyJames supports Canada
  • 30,578
  • 3
  • 59
  • 108
-2

If your domain layer is where you are accessing your data via NHibernate then yes it should be dependent on it. If you are calling to another layer to manage the access, then your abstraction is leaky and you have details about data access in places where the shouldn't be.

Layers that aren't accessing data should only be dependent on objects that represent the data and not know anything about how they are accessed. If this is not the case you aren't following the open/closed principle as you have objects with multiple reasons to change.

Ryathal
  • 13,486
  • 1
  • 36
  • 48