This is one of those so-called “best practices” that crops up a lot in the .net world:
You need to keep the different layers of your application loosely coupled with a clean separation of concerns so that you can swap out your data access layer for a different technology if you need to.
It all sounds right, doesn’t it? Separation of concerns, loose coupling…very clean, SOLID, and Uncle Bob-compliant, right?
Wrong. Contrary to what you may have been told by .net traditionalists, this is not a best practice. Oren Eini, aka Ayende Rahien, debunked it thoroughly about four years ago.
What he said needed to be said. Trying to abstract out your data access layer so you can swap it out is an exercise in chasing rainbows: it just piles on friction and obstructs you from other, more important optimisations. Every project that I’ve ever seen that has attempted this kind of abstraction has been riddled with severe
SELECT n+1 problems that could not be resolved without breaking encapsulation.
Nobody is saying here that separation of concerns is bad per se. What is bad, however, is inappropriate separation of concerns — an attempt to decouple parts of your system that don’t lend themselves to being decoupled. Kent Beck has a pretty good guideline as to when separation of concerns is appropriate and when it isn’t: you should be dealing with two parts of your system which you can reason about independently.
You can not reason about your business layer, your presentation layer, and your data access layer independently. User stories that require related changes right across all your layers are very, very common.
(Nitpickers’ corner: I’m not talking about test mocks here. That’s different. It’s relatively easy to make your test mocks behave like Entity Framework. It’s orders of magnitude harder to make NHibernate or RavenDB behave like Entity Framework.)
Because of this, implementing the strict separation of concerns necessary to make your persistence mechanism pluggable means enforcing strict protocols which slow down day to day development, increase your estimates significantly, adversely affect performance, and make some user stories impossible — all for a requirement that 99% of projects never need, and even for those that do, you can’t guarantee that it will even work, that you won’t have overlooked a myriad of very subtle issues that trip you up all over the place.
You will be diverting significant amounts of developer time and resources — for which your client is paying — away from adding business value which they are asking for, onto a high-maintenance non-functional requirement which they are not.
In other words, if you are attempting to make your data access layer interchangeable, you are stealing from your client.
If you can present a valid business case for making your persistence mechanism interchangeable, then it’s a different matter, of course. But even then, you should still warn them of the extra costs involved as well as the risk that it may not even be possible in the end. Otherwise you won’t be delivering good value for money.