I'm writing a game in Typescript, and decided going in that I was going to try to adhere to the idea of "interface based programming", where you write code based on an interface, instead of the implementation, of an object.

I wrote up a good number of interfaces, and classes that implement them, then took a step back and realized that the classes were simple enough that I'll likely never need to change the implementation, since there's really only one way to do what the class does (moving a Phaser.Sprite in a restricted way to act like a tank).

Then I remember reading a few years ago about the idea of YAGNI, which is basically that you shouldn't over-engineer your code to include things you may never use.

Following best practices, should every class implement an interface, or should you limit it to classes that you expect to be potentially swapped out in the future?

  • Remember, when you use an actual class as a parameter, you're also coding to an interface, to the interface of this class. Nobody forces you to use that specific class, you could just as well inherit it and provide completely new functionality, but that does not seem right. Interfaces exist to make people wrap their heads around the idea easier. With that being sad, no, you don't really need interfaces for everything. – Andy May 2 '16 at 18:17
  • 1
    Possible duplicate of The need for adding an interface to every class – gnat May 2 '16 at 19:14

The reason for having interfaces is because it simplifies polymorphism. Meaning you can send instances by contract rather than knowing their actual implementation. For instance, you may send a "Reader" to a method, so that such a called method can use it's "read()" method. By declaring an interface "Reader" you can make any object conform to this contract, by implementing the methods it specifies. This way, any caller may assume certain methods will exist, even if the objects underlying the contract may be completely different.

This decouples polymorphism from a base class, and makes it possible also between class chain borders, by implying a contract.

Now... This is only useful if you have the need for multiple inheritance chains to act in the same way, or if you will have many base classes with common behaviour that you will want to pass to other users.

If you only have ONE inheritance chain (baseclass->subclass) or just the base, or you have no need to actually PASS the related objects to someone else or use them generically, then you would not add interface implementations, as that notion is then useless.

|improve this answer|||||
  • I'd also add that interfaces should model abstractions, so don't create them by simply hoisting all the public members of a class. Think about what that class represents, and only put those things in the interface that any object of that type should have. You might also wind up creating multiple interfaces (e.g. Moves and Shoots for your tank example) for a single class. – TMN May 3 '16 at 12:50

If you are not sure if you actually need the interfaces, then you probably don't. This is the core of the YAGNI principle. When you need to be able to swap the implementation, then you introduce an interface.

|improve this answer|||||

Creating an interface for every class is a bit overkill. From a purely object-oriented perspective, every class already has an interface. An interface is nothing more than the public-facing methods and data members of a class.

We typically use "interface" to mean "a Java class defined using the interface keyword" or "a C++ class with only public, pure virtual functions." These are useful abstractions, because they decouple the interface of a class from its implementation.

With that in mind, use interfaces when appropriate.

  • Will there be multiple implementations for an interface? If so, this situation may be a candidate for extracting common, public-facing methods into an interface.

  • Will I hand off implementations of a potential interface to other modules that should not know the inner workings of my module? An interface can be useful here, because it reduces the size of the touch point between modules.

Notice the weasel words above: "may" be a candidate, "can be" useful. There is no hard and fast rule that says "yes" or "no" for a given situation.

That being said, having an interface for everything is most likely overkill. If you see this pattern, you are going to far:

interface I {
  int getA()
  int getB()
  int getY()
  int getZ()

class C : I {
  int getA() { ... }
  int getB() { ... }
  int getY() { ... }
  int getZ() { ... }
|improve this answer|||||
  • One more reason for interfaces is if your testing system makes it necessary, which may depend on your language and test-framework. Hopefully you don't need to do this, of course. – Darien May 3 '16 at 1:55
  • @Darien: The reason that a testing system may require interfaces is because the test are actually using a different (mocked) implementation, bringing you back to the first bullet of when an interface is appropriate. – Bart van Ingen Schenau May 3 '16 at 10:29
  • Some great stuff here. Just pondering this: An interface is nothing more than the public-facing methods and data members of a class. Whilst this is true for an interface implementation, it certainly does not hold true for an interface which is never implemented, although granted - this would be something of a code smell. – Robbie Dee May 3 '16 at 11:16
  • @RobbieDee it is true for e.g. a Java interface, it just so happens that everything in the Java interface is also its public-facing interface (OO concept). – user22815 May 3 '16 at 16:28
  • Everyone! Write down the answer's 2nd & 3rd sentences. Laminate it. Put it in your wallet. Reference often. – radarbob May 4 '16 at 21:30

It can be very tempting for newer developers to think of interfaces as an inconvenience that you simply add just because you're told it is "best practice". If you are blindly doing this, it smacks of cargo cult programming.

There are a number of very good reasons that you should consider interfaces for larger developments rather than throwing together a set of classes.

Mocking frameworks

If you want to test a multi-layer application without having to craft in objects for the various layers, you'll undoubtedly want to use mocking frameworks to mock out the layers. Interfaces are used extensively here.

Dependency injection

Whilst they have fallen out of favour somewhat due to the bloat they add, the idea is sound - the ability to simply swap in concretions based on an interface. The principle can also be found in many design patterns such as the factory pattern.

These approaches are summarised in the D from SOLID principles. The rub of this is - use abstractions, not concretions.

Like design patterns themselves, when to use them is a judgement call. The takeaway point is to understand how the interfaces are useful not just stick them on your classes because you feel you have to. There is a good discussion of the various merits of DIP and YAGNI here.

|improve this answer|||||
  • Note that dependency injection and IoC containers are two completely different things (one is a design principle and the other is one way of concretely putting that principle into practice by using various frameworks). You can use DI without using an IoC container. – sara May 3 '16 at 12:41
  • @kai "You can use DI without using an IoC container". I think more mature development shops can (and do). There is simply no need to pollute the code for what is ostensibly a simple concept. Joel is of a similar view. – Robbie Dee May 3 '16 at 13:17
  • YAGNI is very tricky. Whatever the philosophy is, in most cases, in reality, YAGNI is used as an excuse for cutting corners. Avoid coupling should be taken more seriously. It is frustrating to see in many scrum meetings, a developer calls himself blocked because someone else did not finish their job. How come blocking another developer is saving anybody time? My suggestion is to use an interface to avoid coupling. Of course, one doesn't have to use an interface for Model classes. – Ripal Barot Jun 1 '19 at 20:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.