You (Probably) Don't Need An Interface For That

It's easy to do things in the name of best practices but, how often do we sit down and ask ourselves if that is the right thing to do in our current situation?

You (Probably) Don't Need An Interface For That

In software development we are told early on that you should "Program to the interface, not the implementation". While this is great advice when you are programming against remote systems, or services that you don't control. It seems like what most developers hear is "Every class should have a corresponding interface".

We end up creating interfaces like IPrettySweetClass, with the single corresponding implementation of PrettySweetClass. The problem is that the IPrettySweetClass interface was probably written in a way that only allows one implementation. It is either so specific that others can't fully implement it themselves or it wouldn't make sense to have two implementations in a code base at a single time. Codebases quickly become riddled with IThis & IThat interfaces which offer no real value to anyone other than allowing a developer to check the "I programmed to the interface, not the implementation" option of their best practices checklist.

The easy solution to this problem is to ask some pretty simple questions before deciding to create an interface. Let's go over them & try to define which use cases are best served by an interface.

To start, we need to be sure we understand exactly what we are trying to abstract with our interface.

Will this interface outline a single responsibility or concept?

Can a clear & descriptive name be identified by the behaviors this interface will outline?

These questions can really be boiled down to: "Do I understand how I want the interface to be used enough to properly define it?". The answer should always be "yes". If you don't know what you are trying to abstract your interface will abstract the wrong things.

Once we know we can define what we want to abstract, we have to take the time to step back and ask if what we want to abstract truly should be abstracted. Interfaces should always define what should be done, but not how it should be done.

If we would like to create an interface we need to understand that the presence of an interface is going to tell any other developers that there are multiple ways to implement the functionality. Answering this set of questions will let us know whether or not that is really the case:

Is there a current need for more than one different implementation of this functionality?

Do I have clearly defined criteria for using one implementation over another?

Answering these questions isn't optional. If you do not have clear criteria for using one implementation over another one, why accommodate that use case?

If you do know you need to have multiple implementations, the second question forces you to define a plan for when you would use one or the other. I will even go so far as to say that if your library offers more than one implementation, your library should also manage the logic to decide which implementation should be used.
Creating a small factory to return the expected implementation will ensure that the logic used to decide which implementation is documented and isolated for changing requirements in the future.

There is one valid reason for creating an interface without knowing what the multiple implementations will be; Creating an interface with zero implementations.

Is the primary implementation of this interface going to be managed outside of the codebase that defined it?

When creating libraries for other developers to use, there are situations where creating an interface for the other system is valid. The .NET Core framework has an excellent example of this with IConfigurationProvider. This interface expects other, external libraries, to create implementations that can be utilized by the ConfigurationBuilder. ConfigurationBuilder and the defining library don't need to know a single implementation of IConfigurationProvider in order to work.

Creating interfaces shouldn't be done just for the sake of having one. Thought and effort should go into the decision in order to prevent confusion & ensure that the codebase remains clean and maintainable.

The world will keep spinning without every class having a corresponding interface. Besides, the new keyword isn't that scary.