What’s An Interface?

I mentioned in the first post of this series that I’ll likely be referring to C# in most of these posts. I think the concept of an interface in C# extends to other languages–sometimes by a different name–so the discussion here may still be applicable. Some examples in C++, Java, and Python to get you going for comparisons.

An interface contains definitions for a group of related functionalities that a class or a struct can implement.
By using interfaces, you can, for example, include behavior from multiple sources in a class. That capability is important in C# because the language doesn’t support multiple inheritance of classes. In addition, you must use an interface if you want to simulate inheritance for structs, because they can’t actually inherit from another struct or class.

It’s also important to note that an interface decouples the definition of something from its implementation. Decoupled code is, in general, something that programmers are always after. If we refer back to the points I defined for what makes good code (again, in my opinion), we can see how interfaces should help with that.

Extensibility: Referring to interfaces in code instead of concrete classes allows a developer to swap out the implementation easier (i.e. extend support for different data providers in your data layer). They provide a specification to be met should a developer want to extend the code base with new concrete implementations.

Maintainability: Interfaces make refactoring an easier job (when the interface signature doesn’t have to change). A developer can get the flexibility of modifying the implementation that already exists or creating a new one provided that it meets the interface.

Testability: Referring to interfaces in code instead of concrete classes allows mocking frameworks to leverage mocked objects so that true unit tests are easier to write.

Readability: I’m neutral on this. I don’t think interfaces are overly helpful for making code more readable, but I don’t think they inherently make code harder to read.

I’m only trying to focus on some of the pro’s here, and we’ll use this sub-series to explore if these hold true across the board. So… should every class have a backing interface?

An Example

Let’s walk through a little example. In this example, we’ll look at an object that “does stuff”, but it requires something that can do a string lookup to “do stuff” with. We’ll look at how using an interface can make this type of code extensible!

First, here is our interface that we’ll use for looking up strings:

public interface IStringLookup
{
string GetString(string name);
}

And here is our first implementation of something that can lookup strings for us. It’ll just lookup an XML node and pull a value from it. (How it actually does this stuff isn’t really important for the example, which is why I’m glossing over it):

In the code snippet above, you’ll see our Main() method creating an instance of “MyObject” which is the thing that’s going to “DoStuff” with our XML string lookup. The important thing to note is that the DoStuff method takes in the interface IStringLookup that our XML class implements.

Now, XML string lookups are great, but let’s show why interfaces make this code extensible. Let’s swap out an XML lookup for an overly simplified CSV string lookup! Here’s the implementation:

And voila! We’ve been able to extend our code to use a COMPLETELY different implementation of a string lookup with relatively no code change. You could make the argument that if you needed to modify the implementation for a buggy class that as long as you were adhering to the interface, you wouldn’t need to modify much surrounding code (just like this example). This would be a point towards improved maintainability in code.

“But wait!” you shout, “I could have done the EXACT same thing with an abstract class instead of the IStringLookup interface you big dummy! Interfaces are garbage!”

And you wouldn’t be wrong about the abstract class part! It’s totally true that IStringLookup could instead have been an abstract class like StringLookupBase (or something…) and the benefits would still apply! That’s a really interesting point, so let’s keep that in mind as we continue on through out this whole series. The little lesson here? It’s not the interface that gives us this bonus, it’s the API boundary and level of abstraction we introduced (something that does string lookups). Both an interface and abstract class happen to help us a lot here.

3 Comments for this entry

I have been thinking about how abstractions and unnecessary layering can impede readability.

To take on your title, I don’t think every class should have an interface. Often interfaces have a single implementation which will never be replaced. They can still be useful for reasons you have indicated (testing, decoupling, etc.), but I don’t think the default should be to include them everywhere.

In one codebase I work in they have went CRAZY with interfaces for everything. Following how the code fits together is much harder. Understanding what the behaviour is without debugging the code is a challenge. At this extreme reading the code is much harder. The extra interfaces get in the way.

While an interface is a convenient abstraction, it isn’t the only tool for the job and can be abused. Choosing when to use interfaces or another abstractions and when not to use them is part of the fun of being a developer. As with anything I think there is a better balance to be found.

Thanks for the comment, and I’m glad you enjoyed the post! I’m excited to write a bit more about these topics because they’re questions I’ve been asking myself *AND* they come up in the workplace too.

As with most things, I usually don’t believe the best answer is to any one extreme, but rather somewhere in the middle. With these posts, I’m hoping to try approaching them from an extreme perspective (i.e. all classes must have interfaces) to try and prove that putting strict rules in place that apply to all of your code can often make the code worse.

I’ve set out in one of my hobby projects to take a lot of the practices I’ll be talking about in this series to one extreme or another. In the beginning, the rules felt great to have in place… but after writing enough code in one codebase, some of the rules seem to be inhibiting adding more code. Kind of ironic 🙂

Great Los Techies post! It aligns with what you were saying about not “the only tool for the job”, and I certainly echo that!

I work as a team lead of software engineering at Magnet Forensics (http://www.magnetforensics.com). I'm into powerlifting, bodybuilding, and blogging about leadership/development topics over at http://www.devleader.ca.