0

I have a question about a trend I see many developers and companies are following, especially the young developers or companies that started to depend on DI in their designs.(I admit I do that too sometimes)

That is to create an interface for each class and put the interface and the class both in the same file or the same project in best cases. In this solution, they never intend or think of any other implementation rather than a single one, and also you will see many marker interfaces.

  1. I am against the usage of marker interfaces.
  2. I see limited benefit for interfaces that have one single implementation.
  3. I do not think there is any advantage of depending on interfaces rather than the rigid implementation if every time you change the implementation you are going to recompile the interface and increase the version.

The only reason why they are doing that is to benefit from the DI framework in injecting instances in constructors and maybe parameters/properties. but I think that can and should be replaced by registering the class itself rather than the interface. Do you agree ? disagree? Thoughts? Corrections?

Assil
  • 572
  • 6
  • 21

2 Answers2

1

To achieve SOLID principles you need to build your solution over abstraction "Interface" when you register an Interface in Ioc container you keep you solution clean and related only with abstractions not their implementations which may differ in the future or need changes.

mshouman
  • 374
  • 2
  • 12
  • I totally, fully and extremely understand that. But in order to achieve that, interfaces need to be totally separated from the implementation in a separate project. Do you agree? Because in the future when things differ you will have to recompile and change the interface assembly if not breaking the interface itself, but when you separate interfaces from the implementation in separate projects, you don't need to change the abstractions or even touch then unless you have a major breaking changes. – Assil Jun 11 '18 at 12:50
  • understanding that make you able to reject your suggestion and I don't know what is the benefit of registering class rather than interface!! – mshouman Jun 11 '18 at 12:54
  • What I am trying to say is that registering the class rather than the interface (Which is bad) gives you the same benefits you seek (depending on DI to inject instances) if that was the ONLY benefit you are getting from DI framework. I mean when your interface and class are both in the same file, you break the meaning of abstraction. It does not matter anymore if you change the class and not the interface as long as you are deploying them together everywhere. – Assil Jun 11 '18 at 12:58
  • 1
    Sure using the same file for both calss and interface is a bad habit in general and anyone does that doesn't care about any principals – mshouman Jun 11 '18 at 13:15
  • According to the Dependency Inversion Principle: high level modules should *own* the abstractions they depend on. This typically means abstractions should be *separated* from their implementations (in different assemblies). An example where this could be useful is with a SQL data access layer (DAL) that must be swapped out for an Azure DAL, but without the need to recompile the Domain layer. In other cases, where is requirement does not exist, abstractions and implementations can be placed together. In that case, loose coupling can bring a lot to the table, as I mentioned in my answer. – Steven Jun 11 '18 at 15:06
1

Letting classes depend on abstractions instead of implementations makes a system loosely-coupled. Loose coupling has a few very clear advantages. Dependency Injection Principles, Practices, and Patterns defines the following advantages (chapter 1.2.2, table 1.1):

  • Late binding: Services can be swapped with other services without recompiling code.
  • Extensibility: Code can be extended and reused in ways not explicitly planned for.
  • Parallel development: Code can be developed in parallel.
  • Maintainability: Classes with clearly defined responsibilities are easier to maintain.
  • Testability: Classes can be unit tested.

This doesn't mean however that abstractions are always useful. For instance, in case:

  • The dependency is living in the same module as the consumer.
  • The consumer and dependency don't need to be tested independently.
  • The dependency is a Stable Dependency rather than a Volatile Dependency (see chapter 1.3.1).
  • The dependency will never have to be Intercepted. A common reason for interception is to be able to able cross-cutting concerns.

I see limited benefit for interfaces that have one single implementation.

When you have one implementation, this typically means that:

  • You don't fake the dependency for testing
  • You don't intercept its behavior to apply cross-cutting concerns

But you need to be sure you don't need testability, extensibility and late binding for that particular dependency.

Another way to look at this is from the Reused Abstraction Principle. Having a system with many one-to-one mappings between abstractions and implementations is a code smell. In the systems I write, I typically have a handful of abstractions that are implemented by 90% of the classes in my system (this model is explained in detail in chapter 10 of DI in .NET).

I am against the usage of marker interfaces.

Marked interfaces can be useful, but not from the perspective of Dependency Injection, since a marked interface does not have any members, and it is therefore useless to inject a marked interface into a consumer.

The only reason why they are doing that is to benefit from the DI framework in injecting instances in constructors and maybe parameters/properties.

I would say this statement is incorrect. DI libraries typically don't care about whether the dependency is a concrete type or an abstraction. They happily inject it for you anyway. You start injecting abstractions because of the benefits of loose coupling.

Steven
  • 166,672
  • 24
  • 332
  • 435