There are a lot of guides on how to write good code. Many organizations implement static code analysis to verify and improve code quality. Developers become more and more conscious of what clean code is, SOLID, design patterns, GRASP… So many instructions how to code so we start to forget what this is all about.
Why We Need Interfaces?
The very first use case of an interface is to describe behavior of an object that implements it. If a class
Dog implements interface
IAnimal, we are assured it (not always) can
Eat. Of course, a
Dog can also
Sit, but this is specific implementation that differs from a
Bird that can
A more complex use case of an interface is a polymorphism (often combined with dependency injection). If our code depends on abstraction (interfaces in this case), it is more flexible. We can use any class we want, that implements the necessary interface.
Thanks to interfaces, we can reduce coupling between classes. If your implementation is based on abstraction (such as interfaces), you could change the output of your application without changing the source code, just by changing implementation of the interface.
So Why Shouldn’t We Use Them?
At the beginning of my development journey, I didn't ask many questions, I just did what other, more experienced colleagues did. But after some time, I started to see flaws in design and implementations.
How many times have you seen such an interface:
public interface IMathCalculator
int Sum(int a, int b);
int Subtract(int a, int b);
With implementation like this:
public class MathCalculator : IMathCalculator
public int Sum(int a, int b)
return a + b;
public int Subtract(int a, int b)
return a - b;
Or even something like this:
public class CalculatorConfigProvider : ICalculatorConfigProvider
public double GetPiValue()
public interface ICalculatorConfigProvider
Ok, so what is possibly wrong in this code?
In my opinion, this interface is completely not necessary. Interface suggests possible multiple implementations. In this case, we have only one implementation with the exact name of the interface. The interface and its implementation is in the same namespace so it is not a problem to make use of a concrete implementation instead of an abstraction.
What is more, if you use IoC container (e.g., Ninject), you need to register all classes with their interfaces. This is another thing to remember and it may look like this:
The bigger a project is, the more entries are added when registering IoC Container. Initialization classes become bigger and harder to maintain. If you need to register dependencies in two different scopes (e.g., request scope for WebApi and Named scope for some asynchronous endless loop), you need to register your dependencies twice and it is a disaster.
Real Problem - Business Logic
We were talking about good practices, coupling, maintainability and so on. But I think the real problem is when you deal with your domain and business logic. This is a crucial part of the application - sometimes, a key point and the purpose of the application or even the whole company. This part contains some serious calculations, algorithms or laws.
If you add an interface to such class and then inject this interface, you have absolutely no control of how it would be used. Especially when you are making an API or a library used by another application.
A simple example of an
OrderGenerator that is executing domain logic of generating an
Products shows an idea:
public class OrderGenerator
private readonly TaxCalculator calculator;
public OrderGenerator(TaxCalculator calculator)
this.calculator = calculator;
public Order Generate(IEnumerable<Product> products)
var order = new Order();
foreach (var product in products)
var price = calculator.CalculatePrice(product);
TaxCalculator is injected into
OrderGenerator and it is making some calculations based on product type, tax prices and country laws.
public class TaxCalculator
public Price CalculatePrice(Product product)
With this implementation, you are certain that
OrderGenerator will calculate the price correctly for a given product.
Now consider that on a Code Review, some Senior-Expert suggested adding an interface to a
TaxCalculator and injecting an
ITaxCalculator to the
OrderGenerator. Seems pretty easy and it sounds like a good idea. You think of Interface segregation from SOLID, you know that interfaces are good. The code looks good too. :)
public interface ITaxCalculator
public Price CalculatePrice(Product product);
OrderGenerator became open for modifications. What does it mean? It means that you can implement a new
NoTaxCalculator that implements
ITaxCalculator and returns
0 as a price.
The problem is that it is a crucial part of your application. Or your ecosystem. Or your Company.
And now, someone can break it. :)
But I Need Interfaces To…
Well… I have heard some justifications why it is necessary to add interfaces to classes. Here are some of them:
- Register classes in IoC Container to inject them into another classes
- Mock classes in Unit Tests
- Write clean code and reduce coupling between classes
But, is it true?
IoC Container should resolve a class when it contains a
public constructor with all parameters that can be resolved by IoC Container.
If you add an interface JUST for a test - don't. Your production code should not be written just to satisfy tests. You can do whatever you want in a test project, but leave the production code. :)
Using interfaces instead of concrete implementations reduce coupling and that's a fact. But registering interface in the IoC Container adds complexity and lowers maintainability so if you use it only once in the application, it equalizes pros and cons in my opinion.
So What Should I Do?
First of all, you should think about meeting all business requirements. :) If you write the cleanest code of all time, but don't satisfy your business, then the application is useless.
Interfaces have great value and they should be used in every application. Thanks to interfaces, you can use polymorphism, add many patterns such us Strategy, Factory, Command and so on. You can inverse dependencies (D in SOLID) so if your domain uses repositories or adapters, you can inject interfaces and the implementation should be in a separate layer.
But as everything, you should use them wisely. :) Not all classes should have their own interfaces. This is not the only solution.
- 7th August, 2019: Initial version