41

I have come across the term "programming to an interface instead of an implementation" a lot, and I think I kind of understand what it means. But I want to make sure I understand it's benefits and it's possible implementations.

"Programming to an interface" means, that when possible, one should refer to a more abstract level of a class (an interface, abstract class, or sometimes a superclass of some sort), instead of refering to a concrete implementation.

A common example in Java, is to use:

List myList = new ArrayList(); instead of ArrayList myList = new ArrayList(); .

I have two questions regarding this:

  1. I want to make sure I understand the main benefits of this approach. I think the benefits are mostly flexibility. Declaring an object as a more high-level reference, rather than a concrete implementation, allows for more flexibility and maintainablity throughout the development cycle and throughout the code. Is this correct? Is flexibility the main benefit?

  2. Are there more ways of 'programming to an interface'? Or is "declaring a variable as an interface rather than a concrete implementation" the the only implementation of this concept?

I'm not talking about the Java construct Interface. I'm talking about the OO principle "programming to an interface, not an implementation". In this principle, the world "interface" refers to any "supertype" of a class - an interface, an abstract class, or a simple superclass which is more abstract and less concrete than it's more concrete subclasses.

3

6 Answers 6

65

"Programming to an interface" means, that when possible, one should refer to a more abstract level of a class (an interface, abstract class, or sometimes a superclass of some sort), instead of refering to a concrete implementation.

This is not correct. Or at least, it is not entirely correct.

The more important point comes from a program design perspective. Here, "programming to an interface" means focusing your design on what the code is doing, not how it does it. This is a vital distinction that pushes your design towards correctness and flexibility.

The main idea is that domains change far slower than software does. Say you have software to keep track of your grocery list. In the 80's, this software would work against a command line and some flat files on floppy disk. Then you got a UI. Then you maybe put the list in the database. Later on it maybe moved to the cloud or mobile phones or facebook integration.

If you designed your code specifically around the implementation (floppy disks and command lines) you would be ill-prepared for changes. If you designed your code around the interface (manipulating a grocery list) then the implementation is free to change.

16
  • 7
    NO. List/ArrayList is not what I am talking about at all. It's more like providing an Employee object rather than the set of linked tables you use to store an Employee record. Or providing an interface to iterate through songs, and not caring if those songs are shuffled, or on a CD, or streaming from the internet. They're just a sequence of songs.
    – Telastyn
    Mar 14, 2014 at 21:20
  • 1
    @AvivCohn: "programming to an interface instead of a specific implementation" is a basic part of sound programming. And whether you are on the OO bandwagon or not, you should adhere to it. Dec 12, 2015 at 17:39
  • 3
    The existence of the 'turbo button': en.wikipedia.org/wiki/Turbo_button is an actual real world example of your floppy disk analogy.
    – JimmyJames
    May 4, 2016 at 19:01
  • 1
    @AvivCohn I would suggest SpringFramework as a good example. Everything in Spring can be enhanced or customized by making your own impementation of their interfaces and Springs's main behaivor an features will keep working as expected... Or in case of customizations, as you expected. Programming to an interface is also the best strategy to design integration frameworks. Again Spring does with its spring-integration. At design time, programming to an interface is what we do with UML. Or it's what I would do. Abstract myself from the how it does and get focus on what to do.
    – Laiv
    May 5, 2016 at 7:51
  • 1
    @AvivCohn Also JEE specification is a good example. Every provider implements JEE specifications (interfaces or abstractions) its own way. Jboss for sure doesn't works exactly like Weblogic. Neither Weblogic does as Websphere does. However they all does what it's expected from a JEE platform
    – Laiv
    May 5, 2016 at 7:54
24

My understanding of "programming to an interface" is different than what the question or the other answers suggest. Which is not to say that my understanding is correct, or that the things in the other answers aren't good ideas, just that they're not what I think of when I hear that term.

Programming to an interface means that when you are presented with some programming interface (be it a class library, a set of functions, a network protocol or anything else) that you keep to using only things guaranteed by the interface. You may have knowledge about the underlying implementation (you may have written it), but you should not ever use that knowledge.

For example, say the API presents you with some opaque value which is a "handle" to something internal. Your knowledge might tell you that this handle is really a pointer, and you could dereference it and access some value, which might allow you to easily accomplish some task you want to do. But the interface doesn't provide you with that option; it's your knowledge of the particular implementation that does.

The problem with this is that it creates a strong coupling between your code and the implementation, exactly what the interface was supposed to prevent. Depending on the politics it might either mean that the implementation can no longer be changed, because that would break your code, or that your code is very fragile and keeps breaking on every upgrade or change of the underlying implementation.

A big example of this is programs written for Windows. The WinAPI is an interface, but many people used tricks that worked because of the particular implementation in, say Windows 95. These tricks maybe made their programs faster, or allowed them to do things in less code than would have otherwise been necessary. But these tricks also meant that the program would crash on Windows 2000, because the API was implemented differently there. If the program was important enough, Microsoft might actually go ahead and add some hack to their implementation so the the program would continue to work, but the cost of that is increased complexity (with all the ensuing problems) of the Windows code. It also makes life extra-hard for the Wine people, because they try to implement the WinAPI as well, but they can only refer to the documentation for how to do this, which leads to many programs not working as they should because they (accidentally or intentionally) rely on some implementation detail.

4
  • That's a good point, and I hear this a lot in certain contexts.
    – Telastyn
    Mar 14, 2014 at 14:17
  • 1
    I see your point. So let me see if I can adapt what you're saying to general programming: Let's say I have a class (class A) that uses functionality of abstract class B. Classes C and D inherit class B - they provide concrete implementation for what that class is said to do. If class A uses directly class C or D, it's called 'programming to an implementation', which isn't a very flexible solution. But if class A uses a reference to class B, that can later be set to the C implementation or the D implementation, it makes things more flexible and maintainable. Is this correct?
    – Aviv Cohn
    Mar 14, 2014 at 20:02
  • If this is correct, than my question is - Are there more concrete examples to 'programming to an interface', other than the 'using an interface reference rather than a concrete-class reference' common example?
    – Aviv Cohn
    Mar 14, 2014 at 20:03
  • 3
    @AvivCohn A little late in this reply, but one concrete example is the world wide web. During the browser wars (IE 4 era) web sites were written not towards what any specification said, but to the quirks of some browser (Netscape or IE). This was basically programming to the implementation instead of the interface. Aug 23, 2016 at 8:35
12

I can only talk about my personal experience, as this has never been formally taught to me either.

Your first point is correct. The gained flexibility comes from not being able to accidentally invoke implementation details of the concrete class where they shouldn't be invoked.

For example, consider an ILogger interface which is currently implemented as a concrete LogToEmailLogger class. The LogToEmailLogger class exposes all the ILogger methods and properties, but also happens to have an implementation-specific property sysAdminEmail.

When your logger is used in your application, it shouldn't be the concern of the consuming code to set the sysAdminEmail. This property should be set during the logger setup and should the be concealed from the world.

If you were coding against the concrete implementation, then you might accidentally set the implementation property when using the logger. Now, your application code is tightly coupled to your logger, and switching to another logger will require first decoupling your code from the original one.

In this sense, coding to an interface loosens coupling.

Regarding your second point: Another reason I have seen for coding to an interface is to reduce the complexity of code.

For example, imagine I have a game with the following interfaces I2DRenderable, I3DRenderable, IUpdateable. It is not uncommon for a single game components to have both 2D and 3D renderable content. Other components may be only 2D and others only 3D.

If 2D rendering is done by one module, then it makes sense for it to maintain a collection of I2DRenderables. It doesn't matter if the objects in its collection are also I3DRenderable or IUpdateble as other modules will be responsible for treating those aspects of the objects.

Storing the renderable objects as a list of I2DRenderable keeps the complexity of the rendering class low. 3D Rendering and Update logic is none of its concern and so those aspects of its children objects can and should be ignored.

In this sense, coding to an interface keeps complexity low by isolating concerns.

6

A Real World analogy might help:

A Mains electricity plug in an Interface.
Yes; that three-pinned thing on the end of the power cord from your TV, radio, vacuum cleaner, washing machine, etc..

Any appliance that has a main plug (i.e. implements the "has a mains plug" interface) can be treated in exactly the same way; they can all be plugged into a wall socket and can draw power from that socket.

What each individual appliance does is entirely different. You're not going to get very far cleaning your carpets with the TV and most people don't watch their washing machine for entertainment. But all of these appliances share the common behaviour of being able to be plugged into a wall socket.

That's what Interfaces get you.
Unified behaviours that can be carried out by many different Classes of Object, without the need for the complications of Inheritance.

4

There are perhaps two usages of the word interface being used here. The interface you are mainly referring to in your question is a Java Interface. That is specifically a Java concept, more generally it's a programming language interface.

I would say that programming to an interface is a broader concept. The now popular REST APIs that are available for many websites are another example of the broader concept of programming to an interface at a higher level. By creating a layer in between your code's inner workings and the outside world (people on the internet, other programs, even other parts of the same program) you can change anything inside your code as long as you don't change what the outside world is expecting, where that is defined by an interface, or contract that you intend to honour.

That does then provide you the flexibility to refactor your internal code while not having to tell all the other things that depend on its interface.

It also means that your code should be more stable. By sticking to the interface then you shouldn't break other people's code. When you really have to change the interface then you can release a new major version (1.a.b.c to 2.x.y.z ) of the API which signals that there are breaking changes in the interface of the new version.

As @Doval points out in the comments on this answer there is also locality of errors. These I think all boil down to encapsulation. Just as you would use it for objects in an Object Oriented design, so this concept is also useful at a higher level.

1
  • 1
    A benefit that's usually overlooked is locality of errors. Say you need a Map, and you implement it using a binary tree. In order for this to work, the keys need to have some ordering, and you need to maintain the invariant that keys that are "less than" the current node's key are on the left subtree, while those that are "greater than" are on the right subtree. When you hide the implementation of the Map behind an interface, if a Map lookup goes wrong you know the bug must be in the Map module. If it's exposed, the bug could be anywhere in the program. To me, this is the main benefit.
    – Doval
    Mar 14, 2014 at 12:20
3

The term "programming to an interface" is open to much interpretation. Interface in software development is a very common word. Here is how I explain the concept to the junior developers I have trained over the years.

In software architecture there are a wide range of natural boundaries. Common examples include

  • The network boundary between the client and server processes
  • The API boundary between an application and a third party library
  • Internal code boundary between different business domains within the program

What matters, is that when these natural boundaries exist, they are identified and the contract of how that boundary behaves is specified. You test your software not by whether the "other side" behaves, but whether your interactions match the specification.

The consequences of this are:

  • External components can be exchanged as long as they implement the specification
  • Natural point for unit tests to validate correct behaviour
  • Integration tests become important - was the specification ambiguous?
  • As a developer you have a smaller world of concern when working on a particular task

Whilst much of this can relate to classes and interfaces, it is as important to realise that it also relates to data models, network protocols and in a more general way working with multiple developers

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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