/ INTERFACE, CLEAN CODE

Limits of programming by interface

One of the earliest and most fundamental principle one learns while coding is programming by interface.

Definition

Interface-based programming defines the application as a collection of components, in which Application Programming Interface (API) calls between components may only be made through abstract interfaces, not concrete classes. Instances of classes will generally be obtained through other interfaces using techniques such as the Factory pattern.

— Wikipedia
https://en.wikipedia.org/wiki/Interface-based_programming

For example, the following signature is not compliant as it uses a concrete class:

<T> ArrayList<T> foo();

The compliant signature should be:

<T> List<T> foo();

The rationale behind this design is that the caller shouldn’t be concerned about the concretion, but only about the contract. Hence, the provider implementation can change without impacting the caller code. Programming by interface helps avoid the ripple effect, where a codebase change in a specific place will require a change in a lot of other places.

The tip of the iceberg

I teach it in my courses, and I’m among the first to point it out in code reviews. Recently, however, I started to ponder if it should be as ubiquitous as it is.

Getting back to the previous example: if the signature references List, the implementing code may return ArrayList, LinkedList or any implementation that conforms to List for that matter. It for sure will compile in all those cases. However, switching the returned implementation might have other side-effects.

You might know that ArrayList is backed by an array, while LinkedList is backed by Node objects being referenced by one another. Both offer different performance results, depending on the operation being performed.

Data structure

Time complexity

Average

Worst

Access

Search

Insertion

Deletion

Access

Search

Insertion

Deletion

Array

θ(1)

θ(n)

θ(n)

θ(n)

O(1)

O(n)

O(n)

O(n)

Doubly-Linked List

θ(n)

θ(n)

θ(1)

θ(1)

O(n)

O(n)

O(1)

O(1)

From http://bigocheatsheet.com/#data-structures

Hence, the exact concretion returned might be an implementation detail - or not.

Not a mere paper cut

It’s easy to discard the previous issue: it’s pretty straightforward to look at the code and check the implementation.

And yet, this check doesn’t imply that the dependency won’t change. Worse, the above example only brushes at the top of the iceberg. Another case involves core principles of OOP:

Both guidelines naturally lead to the Decorator pattern:

decorator pattern

As an example, let’s use the Scalar hierarchy from the Cactoos library:

scalar

This design follows the above principles. It makes it very simple to compose different Scalar objects e.g.:

Scalar scalar = new StickyScalar<String>(
  new RetryScalar<String>(
    new Scalar<String>() {
      @Override
      public String getValue() {
        // Get the value from a network call
      }
    }
  , 3)
);

All those nested decorator layers make it quite difficult to understand properties about the value. For example, in the above snippet, the StickyScalar keeps the value once it’s read successfully once. Underneath, there are 3 attempts to read from the network.

Just knowing a variable contains a Scalar won’t probably be enough in most cases: some return the same value over time, while others do not, etc.

Conclusion

It’s considered a good practice to handle abstractions over concretions. In system-GUI, the most used example is to return a Window reference, knowing it will be a UnixWindow on Unix systems and a WindowsWindow on Windows ones. In that case - and some other, it’s the right thing to do.

In other cases, however, it’s not. The right type to manage is not the interface but a more concrete type.

Nicolas Fränkel

Nicolas Fränkel

Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Also double as a trainer and triples as a book author.

Read More
Limits of programming by interface
Share this