1

Please someone help me clarify an issue I'm having with dependency inversion principle. If I have a repository in my DAL that looks like this and an corresponding interface in the DAL. I'm essentially saying to someone that will use my DAL, "here is an interface to use called 'FindEvents', this is my contract via interface. SO the developer knows not to use the object directly but to use my interface. I could even make the object private and only expose the interface as public

DAL -

public class YogaSpaceEventRepository : IYogaSpaceEventRepository
{
    public IQueryable<YogaSpaceEvent> FindEvents(DateTime start, DateTime end)
    {
    // Retrieve Data from Database
    }
} 

public interface IYogaSpaceEventRepository : IDisposable
{
    // here my repo (data access layer) is referencing my business layer to return YogaSpaceEvent
    IQueryable<YogaSpaceEvent> FindEvents(DateTime start, DateTime end); 
}

But if I take out this interface and stick it in the BLL (DDD method), so that I can avoid circular references (DAL needs to reference BLL to understand the object 'YogaSpaceEvent' that it's returning and somewhere in my BLL I need to call FindEvents - now it's circular). This totally breaks the rule of interfaces!? Because now if the DAL developer hands over the DAL assembly, you as a developer using that DAL assembly won't know what can be changed or not (no contract - no interfaces in the DAL)!

By putting

public interface IYogaSpaceEventRepository : IDisposable
{
    // here my repo (data access layer) is referencing my business layer to return YogaSpaceEvent
    IQueryable<YogaSpaceEvent> FindEvents(DateTime start, DateTime end); 
}

aren't you breaking the one rule of an interface?? Which is a contract - the dev of the DAL can't say here is my library and I'm only guaranteeing what's in this interface. NOW there is no interface, hence no contract.

Please someone give me some feedback here!

Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
chuckd
  • 13,460
  • 29
  • 152
  • 331

4 Answers4

7

If you go to the source of the Dependency Inversion Principle, you'll see that:

"clients [...] own the abstract interfaces" (ch. 11)

Thus, the interface shouldn't go in the DAL, but in the library that uses the interface.

Once there, it's also important to adhere to the other SOLID principles, in this case particularly the Interface Segregation Principle, so don't put more members on the interface than are required by the clients.

When it comes to composition, you may find the following helpful:

Community
  • 1
  • 1
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • You don't have to go to the source, the [Dependency Inversion Principle wikipedia article](https://en.wikipedia.org/wiki/Dependency_inversion_principle) describes this to by saying "In a direct application of dependency inversion, the abstracts are owned by the upper/policy layers". – Steven Mar 23 '15 at 09:05
  • Looking at this `interface IYogaSpaceEventRepository : IDisposable`, I was expecting you would say that disposable abstraction is a leaky abstraction :) – Sriram Sakthivel Mar 23 '15 at 09:47
2

The simple answer is that you don't put it in either your BLL or DAL - you put it in a third assembly that only contains contractual items - i.e. interfaces and any basic entities it may use.

You obviously understand the reason for separating out the data access logic from the business layer. If you are then going to use an interface it is almost redundant to include it in the assembly that implements the DAL - this is because there will be little or no separation of concerns between the interface and the implementation - you'll change them both at will and in lock step.

The purpose of having the interface is to say this is what any DAL I implement will look like and any caller should be able to call any of those DAL implementations without being changed. Consider if you offered a choice between data repositories - one in SQL Server, one in MySQL, and one in the cloud - all three should implement the same interface.

If you can categorically say that you are only ever going to have one DAL, then consider dispensing with the interface unless you maintain that in a third assembly. In this situation the interface is not worthless, you're just not using it to its full effectiveness.

If I remove that out of the DAL and into some other assembly then any contract I try to make with someone using my DAL doesn't exist. So doesn't that defeat the purpose of the interface?

I'm not sure I understand where you're going with that statement....
If someone else calls your DAL they need to create a concrete instance (there are a variety of ways to do that), but they should cast it and use it as that IDalLayer interface. If your DAL returns repositories, then they too should be generic interfaced. This means your IRepository interface can be defined in the same separate assembly as the IDalLayer interface, or even in a different assembly again. There is no need to have this defined in the DAL implementation assembly.

slugster
  • 49,403
  • 14
  • 95
  • 145
  • Maybe you can further answer my question here - I'm only using one DAL and it's to Sql Server via Entity Framework. So I have different repos in this DAL and the repos have interfaces, by having the interfaces here in the DAL, aren't I saying the the user of the DAL, here are my interfaces to use? access to the DAL is through the interface, right? If I remove that out of the DAL and into some other assembly then any contract I try to make with someone using my DAL doesn't exist. So doesn't that defeat the purpose of the interface? – chuckd Mar 23 '15 at 07:15
  • @user1186050 I've updated my answer. I hope that answers your question, I've deliberately stayed away from dry technical descriptions (there's already hundreds of articles out there describing these patterns in that manner). – slugster Mar 23 '15 at 10:14
  • Sorry, but I mis-typed. I meant to say "if I remove out my interface". – chuckd Mar 23 '15 at 18:27
  • I agree with this. But to further clarify/confirm, in the SQL Server, MySQL and Cloud scenario, you would need to have a separate assembly that contains the interfaces, then say your SQL Server implementation references the contracts assembly and implements them, then your business layer references BOTH the contracts and the SQL Server assemblies right? and if we change to MySQL then we swap out the SQL one and use the MySQL assembly, is this accurate? – Alex Mar 27 '18 at 16:46
  • @Alex that is correct - you continue to reference the assembly that defines the interfaces and just swap out the assembly with the implementation. If you use a configuration approach to load the implementation assembly then in theory you don't need to change any references at all, just change the config. – slugster Mar 27 '18 at 18:19
1

Onion Architecture provides good guidance for this kind of problem. The idea is that there's a strict hierarchy between layers and dependencies only go one way, which makes things a lot simpler. Dependency Inversion is used for the (few) cases when a concrete implementation is located further to the edges of the onion than its abstraction.

The key takeaways are :

  • Domain is the innermost layer, so it doesn't reference anything other than itself. Also (DDD rule) it's none of the Domain's business to know when or how entities should be persisted.

  • As a consequence, in your example, YogaSpaceRepository.FindEvents() is not called by the domain but by an Application service.

  • Repository interfaces are declared in the Domain layer (or the layer just around it), but implemented in the Infrastructure layer.

guillaume31
  • 13,738
  • 1
  • 32
  • 51
0

There are many ways to skin a cat :)

I agree with @MarkSeemann, the interface should be declared wherever you need it, in this case in your BLL, but that doesn't mean that the implementation needs to be declared in the same layer you can implement it in your DAL and your DI container will make sure to inject the correct implementation at runtime

This makes more sense when you think for example sending an email in response of an action in the domain. I think you would like to abstract the code that actually sends the email from the domain but still your domain will command when to send the email, this is a perfect example, the interface could be declared in the domain layer but implemented somewhere else

But if I take out this interface and stick it in the BLL (DDD method)

However I don't think that a domain object should now anything about persistence, but if your design justify it go ahead

Jupaol
  • 21,107
  • 8
  • 68
  • 100