Impl Classes Are Meaningless
For those who don’t know the topic of this article, it essentially involves a practice that looks like this:
public interface FooService {
// some methods
}
public class FooServiceImpl implements FooService{
// some methods
}There’s an interface called FooService and only one implementation named FooServiceImpl, and this pattern is repeated for every class of a system. Sometimes you may also find a naming convention that calls the interface with an ‘I’ prefix, e.g. IFooService and the respective class without the prefix. It actually makes no difference at all.
This is a practice discussed a lot but still widely used in the Java and C# developer community. It is discussed in Martin Fowler’s Patterns of Enterprise Application Architecture, published in 2002, as a problematic practice, so we can say that it has been around roughly for more than 20 years. I first encountered this when I was working on a project, noticing that each service class, all suffixed with 'Impl', had its own interface. This confused me because I knew interfaces were intended to be implemented by multiple classes, providing higher abstraction and diverse implementations. Doing some research, I discovered the history of this practice, the common arguments behind its usage, and why it is obsolete.
This practice is indeed a misinterpretation of the Separated Interface pattern, which is about the separation of the interface and its implementations in different packages to reduce the coupling between parts of your system1.
How the Separated Interface pattern really works
Before addressing the common arguments behind the ‘Impl’ thing, I think it’s extremely important to clarify how the Separated Interface works.
There is a wonderful article that explains it perfectly (the website is full of great articles about design patterns). I will reuse some of the examples and definitions here since they are so well-written and simple to understand.
Separated interface pattern encourages to keep the implementations of an interface decoupled from the client and its definition, so the client is not dependent on the implementation.
But what does it mean, exactly?
Let’s say that our client, InvoiceGenerator, is defined like this:
public class InvoiceGenerator {
private final TaxCalculator taxCalculator;
private final double amount;
public InvoiceGenerator(double amount, TaxCalculator taxCalculator) {
this.amount = amount;
this.taxCalculator = taxCalculator;
}
public double getAmountWithTax() {
return amount + taxCalculator.calculate(amount);
}
}
We can understand that its basic functionality is to calculate an amount, maybe the price of a product, including its tax amount.
Pay attention to the TaxCalculator, which is not a concrete class but an interface defined as follows:
public interface TaxCalculator {
double calculate(double amount);
}Then in a different package there are multiple implementations of the interface.
public class ForeignTaxCalculator implements TaxCalculator {
public static final double TAX_PERCENTAGE = 60;
@Override
public double calculate(double amount) {
return amount * TAX_PERCENTAGE / 100.0;
}
}public class DomesticTaxCalculator implements TaxCalculator {
public static final double TAX_PERCENTAGE = 20;
@Override
public double calculate(double amount) {
return amount * TAX_PERCENTAGE / 100.0;
}
}As you can see, the client is completely independent from the implementations.
This diagram explains the concept well:
Do you see the ‘Impl’ suffix or the ‘I’ prefix here? No, because the purpose of a separated interface is to break dependencies or to have multiple implementations hidden, not to establish a one-to-one relationship between classes and interfaces.
This issue is explained by Martin Fowler:
I come across many developers who have separate interfaces for every class they write. I think this is excessive, especially for application development. Keeping separate interfaces and implementations is extra work, especially since you often need factory classes (with interfaces and implementations) as well. For applications I recommend using a separate interface only if you want to break a dependency or you want to have multiple independent implementations. If you put the interface and implementation together and need to separate them later, this is a simple refactoring that can be delayed until you need to do it.
Having an interface for every class of your system, especially with the ‘Impl’ suffix, causes real damage:2
It hides the cases where you actually do provide multiple implementations.3
Let’s say you need another implementation, how would you name it? ‘FooServiceImpl2’?
It doubles the amount of files in your system, adding unnecessary cognitive load.
I’ve seen systems with two packages, one for interfaces and one for implementations, in which the latter one was absurdly full of ‘Impl’ classes. That tells you that there was close to zero thinking about design.
If you know a design pattern, it’s not a good idea to use it everywhere in your codebase. Design patterns exist because they solve specific problems. Before using one, you have to ask yourself if that solves the problem that the pattern is intended to solve, otherwise you are acting merely as a code monkey.
Adam Bien summarizes this crucial point perfectly:
If you introduce interfaces intentionally - and not as a general rule, you will considerably reduce the number of files. Your code becomes easier to understand and so maintain. An interface will become an artifact to hide multiple implementations and not a general plumbing.
There are always exceptions from the rule. If you are building products, frameworks, containers or platforms the need for extensibility is greater, than in standard (enterprise) projects.
"Contract First", "Coding To Interfaces" or "Decoupling" is not a reason to introduce an interface for everything - its just a fancy term. The answer to the question like: "We have to decouple this legacy adapter, because..., so an interface is a good idea at this place" is a true explanation of a requirement.
I think it’s important, for coverage of this topic, to point out that in Patterns of Enterprise Application Architecture there is an example with an Impl class, as you can see:
This Martin Fowler’s article adds more insight to the issue of interface implementation pairing.
Regardless, there can always be better naming and better alternatives to the suffix. If you can’t find a good name, that’s a problem you need to solve.
If there really isn’t a good implementation name, it might mean that the interface is poorly named or designed.
Perhaps it’s unfocused because it has too many responsibilities; or it’s named after its implementation rather than its role in the client.4
Historical reasons and common arguments
This is not a bad practice strictly on a software design level, it is also obsolete. Some of the reasons for this coincide with the common arguments used to support the ‘Impl’ practice.
Unit testing
One of the common arguments behind the ‘Impl’ practice is that facilitates and is necessary for unit testing, so that you can mock interfaces instead of concrete classes. However, this is no longer true.
Nowadays libraries like Mockito allow you to mock concrete classes and you don’t need interfaces.
Dependency Injection frameworks
I’ve read that interfaces are needed for DI purposes, but this is legacy and even back in the day you had to find workarounds to manage this requirement.
Fortunately, this is no longer true since Java EE 6 came out. The same applies to Spring.
Additional thoughts
I think one of the reasons why this anti-pattern is still used is due to repeating what had been done in the past, without thinking about design or asking if that pattern is correct or not.
Since design requires time and thought, often developers never think about it because they work in an environment that rewards short-sighted programming, where the developer favored by the managers is the one who closes tasks the fastest.
It is common that if developers do not know a concept and have no time to research or study a little about it, they will certainly reiterate some patterns that they see in the codebase.
But reiterating a pattern puts you in a position where you think less about design, particularly if the pattern is so specific like “every class must have its interface”.
Another misconception that I often see is about contracts (interfaces) and implementation.
Sometimes people tend to forget about what ‘public API’ means when talking about classes: the public API of a class is its contract.
That’s why in Java there are the private/public keywords, so you don’t always need an interface to define the contract of a class.
If you want to read more about how contracts and implementations work, I suggest the book “A Philosophy of Software Design” by John Ousterhout, especially the paragraphs about modular design.
On the other end, if you want to read more about the ‘Impl’ problem, you can read this article and those in the footnotes.
Steve Freeman, Nat Pryce. Growing Object-Oriented Software, Guided by Tests. Addison-Wesley Professional, 2009.



