Premature keyword interfaces mitigate some problems:
- Enables multiple inheritance in languages that need keyword interfaces for that (Java & C#)
- Eliminate the need to change the name in using clients (I prefix, C# only)
Both are only important if you must strictly follow the open closed principle. This encourages not making changes to tested working code. That is far more important when you have published code libraries that get updated separately. If you can change every class you feel like changing every version the only real cost is redoing your testing. Refactoring tools make the actual code change trivial.
Premature keyword interfaces cause their own problems:
- Indirection can solve any problem except too much indirection
The "everything gets an interface" mentality creates piles and piles of ceremonial code that can be created without thinking. There's even an "extract interface" refactoring to do this for you. This is not fun to work with when you just want to add a new field. Ideally, the decision that a field should exist should happen in only one place.
Let's be honest. The keyword interface is a terrible patch to these languages broken type system that was created before they knew how to support multiple inheritance properly.
But the Dependency Inversion Principle says to depend on abstractions!
- High-level modules should not depend on low-level modules. Both should depend on abstractions (interfaces).
- Abstractions should not depend on details. Details (classes) should depend on abstractions.
Exactly right. But nothing in that says your abstraction must be a keyword interface.
A keyword interface is when you actually type out the word "interface". Interfaces come in many other forms than that. Every class that doesn't disable inheritance is an interface. So sorry but String
is not an interface. But most all of your other classes are. You don't need everything to have a keyword interface
What makes it tricky is realizing when your class makes a good abstraction and when it doesn't. Protected constructors help keep clients from knowing that your class is concrete. If clients don't know your concrete you are an interface. That's all there really is to it. Lazy architects try to skip needing to check for this by insisting on giving everything a keyword interface. But a little work checking this now will allow you to put off creating a keyword interface before you actually need it to support polymorphism.
An example from my Java damaged brain:
class Report {
public print() {
System.out.println(
"Succeeded: " + result.succeeded() + " " +
"Response Message: " + result.responseMessage()
);
}
Report(Result result) {
this.result = result;
}
Result result;
}
Looks like Report
depends on Result
right? Yeah but so what? Who said Result
was concrete? Report
doesn't use new
on Result
. For all Report
knows Result
is a keyword interface. Report
might be a composition containing many objects. We don't know. That not knowing is what you need to preserve. That not knowing is what makes Result
an abstraction. You don't have to give everything a keyword interface to do that. Do that when you need to do that.
If your programmer tries to invoke SOILD as an excuse for this let me show you a little something from Mr Martin himself:

Note that the models have no interfaces on them at all. That doesn't mean the models will never change. Just preserve the ability to add interfaces later and there's no need to add them now.
The interfaces you do see here are protecting clients from knowing exactly what behavior they depend on across a boundary that is likely to see independent changes. The models have no behavior so the boundary isn't as important to them.