# Stop Writing Interfaces With a Single Implementation

> Opening an interface for every class just in case isn't real flexibility; it's speculative abstraction that makes code harder to read.

- Type: Essays
- Published: 2026-10-31
- Tags: architecture, simplicity, opinion
- Reading time: 2 min read
- Source: https://muhammetsafak.com/engineering/essays/abstraction-inflation/
- Language: en-US
- Author: Muhammet Şafak

---
> **TL;DR:** A single-implementation interface is a mechanical misreading of "program to an interface": it makes navigation indirect, splits reading across two files and promises flexibility that never arrives. An interface earns its cost with several real implementations, an external boundary or a test seam that is actually used. When a second implementation arrives, extract interface is a few minutes of work.

On one project, every class had a twin: `UserService` and `UserServiceInterface`, `OrderRepository` and `OrderRepositoryInterface`. Each interface had exactly one implementation. The folder count had doubled; the flexibility gained was zero.

The single-implementation interface is the most common speculative abstraction — and it's usually the result of a misread principle.

## "Program to an interface" is being misread

The principle "program to an interface, not an implementation" has been repeated for years. But the word "interface" in the principle is not the `interface` keyword in PHP.

What the principle says is this: depend on a type's **contract**, not its **internal details**. A class's public methods are already its contract — which means a concrete class is, conceptually, already an "interface." Reading the principle as "open an `interface` file for every class" turns a design idea into a mechanical ritual.

## What a single-implementation interface costs

An empty abstraction isn't free:

- **Navigation gets indirect.** "Go to definition" takes you to the interface, not the code. To see the actual logic you take one more step — every time.
- **Reading gets harder.** To understand a behavior you open two files: what was promised and what was done. A single concrete class would have kept both together.
- **A false promise of flexibility.** The interface says "this can change." But it won't; the single implementation stays single for years.

This is one of the red flags I listed in [signals of an over-complex system](https://muhammetsafak.com/engineering/essays/signals-of-an-over-complex-system/).

## When abstraction is free

An interface earns its cost if it does real work. The places it's genuinely needed:

- **Multiple implementations actually exist.** Two payment providers, two storage backends — two concrete things that exist today.
- **There's a real external boundary.** The line between your application and a world it doesn't control — an external API, an SDK. Here the interface is a buffer.
- **There's a test seam you actually use.** To swap a costly, slow dependency you can't control — a payment gateway — for a fake in tests. But don't abstract everything on this pretext, like [mocking your own database](https://muhammetsafak.com/engineering/essays/integration-vs-unit-tests/).

The common thread: all three are needs that **exist today**. Not "just in case."

## Opening the seam later is cheap

The objection I hear most: "what if a second implementation shows up later?" If it does, pulling the interface out that day is an IDE refactor — "extract interface," a few minutes. The asymmetry from [the cost of just-in-case code](https://muhammetsafak.com/engineering/essays/the-cost-of-just-in-case-code/) holds here too: extracting an interface from a concrete class is easy; tearing out an unnecessary interface is hard.

Until a second implementation arrives, use the concrete class directly. The code is shorter, more readable, and exactly as complex as reality demands — no more.

---

A single-implementation interface is a layer added without a problem to solve. It looks like "good design"; it's really the prepayment of a decision you could have deferred.

The second implementation is what writes the interface — not the possibility of one.

## Sources

- [Interface Implementation Pair](https://martinfowler.com/bliki/InterfaceImplementationPair.html) — martinfowler.com
