6

According to Should interface names begin with an "I" prefix?, I know I should not add prefix "i" to interface because of some reasons.

However, I'm not raising new reasons to support or oppose the prefix "i" on interface. Instead what I don't understand is, why would the post use the tone "I don’t want" in "I don’t want my users knowing that I’m handing them an interface."?

I think the answers like "interface is no much different from an abstract class" is a bit contradict with "I don’t want my users knowing that I’m handing them an interface." : if interfaces really no much difference with classes, why would I still care users knowing if some type is interface or not?

Letting users know I'm handling interfaces may be none of users businesses, but even if users know something none of their businesses, it seems also no harms for users. Why would the severity be "I don’t want my users knowing that I’m handing them an interface." instead of "Users don't need to know that I’m handing them an interface."? What bad actions may take when users know I'm handling interfaces instead of concrete class? Or what are the bad impacts when a user knows a type is a interface instead of a concrete class?

1
  • 6
    Don't extrapolate too much from the tone. The author is just talking about what role he wants the class/interface to play in the design, and what information he wants to communicate, vs what he doesn't. He's just saying it shouldn't matter to the client that it's an interface, only that it's a polymorphic type that satisfies some abstract behavior. "even if users know something none of their businesses, it seems also no harms for users" - well, when users know (or rather, rely on) something that's supposed to be an implementation detail, it can harm you, if you want to supply future versions. Apr 19 at 22:55

10 Answers 10

55

why would the post use the tone "I don’t want" in "I don’t want my users knowing that I’m handing them an interface."

This is a cite from the "Clean Code" book by Robert Martin, a.k.a "Uncle Bob". And though Robert Martin is surely a respectable and experienced software engineer, he is often critized for his tone. Many people think it is too "schoolmasterly", especially in the mentioned book.

In the sentence you asked about, "I don't want my users knowing ..." puts Bob Martin's thought process into the center of the explanation, not the users' point of view. He could have also written "I don't want my software to be designed in a way that my users need to know ...", but that would have been far longer, less striking and less memorable.

My recommendation: just read everything what Robert Martin wrote with a grain of salt, don't take him too literally. His statements and writings are recommendations, not dogmas. Then you can learn a lot from them.

6
  • 25
    This is honestly the answer. Someone wrote a book and had an opinion, and now strangers on the internet are discussing it. You'll need to ask Bob Martin for clarification. Apr 19 at 14:44
  • 14
    I once kicked a coworker out of my office because he was following all his recommendations blindly (whether they made sense or not in the context of the project) and was insisting that we do the same. Apr 19 at 15:49
  • 3
    More gibberish from the man who emphatically promised everyone that following TDD rigorously magically implies "all your code works." It's not that Uncle Bob's "tone" is bad, it's that his ideas, all too often, are simply nonsense. Inexperienced developers who lack the experience to know what to take with a grain of salt are best off avoiding Robert Martin's work altogether. Apr 22 at 1:39
  • 3
    @MasonWheeler: and you really think the tone of your former comment is better?
    – Doc Brown
    Apr 22 at 5:26
  • 1
    One of my bigger issues with "Clean Code" is that Bob Martin provides no reasons why he thinks people should follow his advice. As far as I can tell he's just documenting his personal preferences and assuming they work for everybody. (Contrast that with something like Josh Bloch's "Effective Java" and the difference is marked). I found Bobs advice can be put into 3 roughly equal categories; obviously good ideas, obviously bad ideas and stuff I'm not sure about. Given the lack of reasons and the amount of bad advice I wouldn't take him on his word for the stuff I'm not sure about
    – Stormcloud
    Apr 22 at 12:57
25

Are you sure you understood the answer to the question you linked correctly? Because the answers agreed that putting an I in front of interfaces if that is the convention in your language of choice is perfectly fine.

That said, to answer your actual question as asked: Users of anything but an ancient stone age compiler will see the type description in their IDE. If your IDE says type: public interface ThisIsReallyNotAnInterfacePinkyPromiseItsTheRealDeal, does that make anything better? It just looks stupid. It is an interface. The compiler knows.

"I don't want my users to know" is a stupid reason: it doesn't work in practice and it is basically an admission that the code and architecture doesn't work properly, unless you lie to your users.

How about just building the best software you can, using the naming convention people are used to in that language. If they are used to ISomething let them have it, if they are used to Something and SomethingImpl then go for it.

In the end, that I will not make or break software. It's the cupholder in a car. Great if it works as you expect it in that brand of car, crappy if someone lied to you about it. In the end, being lied to by a sleaze salesman about it seems worse than just having no cupholder.

1
  • 2
    This is a good answer about any variation of Hungarian notation. Some organizations like it, some don't. It's rarely a big deal, so "when in Rome...."
    – Barmar
    Apr 20 at 18:28
11

The top answer of "because that's how uncle Bob chose to phrase it" is correct, but I'd like to expand on why we would come up with the I prefix in the first place, before uncle Bob railed against it.

I would like to offer the interpretation here that the origin of the I prefix for interfaces is not because we want consumers to know it's an interface, but rather that it was introduced as a way to avoid needing to come up with two synonyms in the case where there is currently only one implementation of said interface and developers are struggling to describe the interface differently than the implementation.

Let's start from a point of agreement: even if only one implementation currently exists, we should already use an interface as an abstraction on top, so that we can later introduce different implementations of the same interface. If you disagree with this premise, you're not going to agree with anything going forward.

So, we have a class called FooCalculator. What should we name its interface? Now that there's only one possible implementation, it's hard not to describe the interface as one that "calculates Foos". But we can't reuse FooCalculator here (and I'm specifically ignoring namespacing as a solution here, because at the end of the day, while clever, it would still negatively impact readability).

We could come up with a synonym... well, a calculation is also called a computation, to we could use FooComputer as the interface name.

I put good money on it that it won't take long for you to reference the interface when you needed to reference the class and vice versa, because the names are interchangeable and which is which is purely an artifact of which we wrote first and which name we came up with first. That's not a good naming system.

Instead of looking for synonyms, we could instead reuse the name, referring to the interface as "the interface of the Foo calculator", which is actually a very apt way to put it. Well, that's exactly what IFooCalculator tells you: I-Foo-Calculator.

Note that you could also invert this and use the "real" name for the interface. This is why you see some languages sometimes favor FooCalculator for the interface and FooCalculatorImpl for the implementation. It's the same solution, but the other way round.

This would be different if we already had multiple implementations that we wanted to build from the get-go. For example, if we're thinking of implementations of different ways to calculate Foo, e.g. one by a very expensive process, the other by a much easier approximation, a third by asking an external API, ...; then it would be natural for FooCalculator to the be interface and PreciseFooCalculator, ApproximateFooCalculator and OnlineFooCalculator to be the implementation names. No conflict here.

But this is not how most codebases work. We don't start with multiple implementations, we start with one and we prepare for future extension. Annoyingly, we are already forced to come up with a name even though we only have one implementation, and it's really difficult to figure out the link by only observing one thing, plus it might even be the case that we don't even know how we might want to create variant, making it impossible to come up with a correct name before we even know what it is that we're trying to capture and express. Maybe the variation isn't that there's multiple ways of calculating Foo, but that we want to be able to calculate Bar the same way. That's a different scenario that would lead to a different shared interface name.

2
  • To add to this - "We don't start with multiple implementations, we start with one and we prepare for future extension" can't be solved with YAGNI. Often, these interfaces are made for the purpose of dependency inversion - there will never be multiple implementations of FooCalculator, but we want to be able to swap out a binary to update the version of FooCalculator without having to rebuild its consumers.
    – Tim C
    Apr 22 at 19:55
  • @TimC: Hot-swapping binaries is way more uncommon than the use cases for interface abstraction, even if a single implementation. Also, it doesn't really add anything to the equation, because you can just as easily hot-swap the binary with a class implementation. Secondly, if there is provably never a second implementation, then the interface is actually irrelevant to have. However, it's impossible to really judge the future to that degree of certainty. Mocks are often the immediate secondary implementation to justify the interface's existence even when only one real implementation exists.
    – Flater
    Apr 23 at 23:45
7

I don’t want my users knowing that I’m handing them an interface because I don't want them to break when I change my mind and hand them something else.

Oh sure, in many languages this is a pipe dream. Even if I prefixes weren't giving away what this really is, the byte code does anyway. Java doesn't have the I wart tradition but a switch will still break using code, unless you recompile.

So if it's a pipe dream why should anyone care? Because people are still writing languages and some day they may fix this. In any case it's nice to know the difference between the ideal and what we've learned to live with.

But if you’re stuck in a language where the compile gives it away anyway then forbidding the I isn’t getting you much. So stick to the convention of the language.

3

An interface, particularly on an incoming parameter, says “I need x,y,z and I don’t care how I get it)”, it’s a declaration made by the recipient (aka function or class).

And it is absolutely the recipient’s responsibility to say what it needs (in languages where that is possible).

So, frankly, both versions are simply dead wrong and ass-backwards. Callers need to know the requirements, and interfaces describe the minimum requirements.

1
  • very good example where you do want it to know. If it’s an interface you can construct your own instead of searching how to get it.
    – Dirk Boer
    Apr 21 at 22:00
2

Ideally "I want users not to know" and "Users don't need to know" are aligned.

Any information you pass to users of a library/API etc. needs to be parsed by the users. That costs time, brain power and potentially leads the users into the wrong directions because they assume an intent that was not what drove the decision. Any information that is not necessary for the users to know to successfully interact with your software is at best just a distraction (that might mean they spent a tiny bit more time understanding everything) and at worst something they will incorporate explicitly into how they work with your software and that constrains you in your later choices. As an ideal programmer you want to achieve the optimal product, thus anything that hinders a user's adoption of your software is something you don't want to add. Thus, any information that isn't necessary for the users, you don't want to send their way, because it is not "no harm". Even if it does nothing bad on its own, it likely costs time.

Note that nearly no rule is set in stone and thus there can be exceptions for most rules and arguments, typically they arise from different goals that contradict each other. But "I don't want my users to know" is pretty equivalent to "The users don't need to know" because you should want to provide something that is easy to adopt by users and thus ideally what you want to deliver matches exactly what users need to know. Sometimes there might be other "wants" on the development side that - at least on surface level - contradicts providing the best product for a user, e.g. because a little imperfection for now saves time or makes the software more maintainable etc. Though, ideally there is still a wish from developer side to avoid this, there is just a competing goal that is stronger in that particular case. In this case however, both align anyway.

0

In Swift, there are two ways: Either you pass an arbitrary object that implements the interface. The receiving code knows it’s an instance of some class but doesn’t know which class. And tomorrow I can pass an instance of a different class implementing the interface.

Or you pass an “existential interface”. Actually “existential protocol” because Swift calls interfaces protocols. That is a new object containing an instance of the protocol itself, with the underlying object stashed away somewhere.

In each case, the user knows their method parameter is an interface or an instance implementing the interface because tHat is how the method parameter is declared. But whether it’s an interface or a class instance doesn’t make any difference to you.

0

I'm in full agreement with Doc Brown but I would like to add that the quoted phrase is pretty confused if you take it at face value. FWIW, I think a much better way to say it would be "it shouldn't matter" to client code (or coder) whether a declaration is in terms interface or a class. I would expect interfaces to be the norm, though.

Assuming "hand" means 'pass or return', the real issue with the quote in question is that you can't 'hand someone an interface'. In mainstream OO languages, you can only "hand" someone an object.

I've always thought the Uncle Bob was a little overrated. This is a good example of why, perhaps. I'm sure he knows that you can't pass or return interfaces. He's just using sloppy language, which is fine until he got a massive following of people who treat his guidance as sacrosanct.

-1

It's because it's none of their business that you have "I don’t want my users knowing". It isn't harmless.

The harm comes when you want to change between giving them a class and giving them an interface. If you have to change the name to fit a naming convention, then the user has to be changed to match the new name.

7
  • 2
    Wouldn't changing the type be a breaking change anyway, that the user has to accomodate? In most languages I know it would be a major red flag if a library changed a type but gave the new type the same name as an old type. That seems like a nightmare to maintain. Is it maybe in inhouse projects that get recompiled every time anyway?
    – nvoigt
    Apr 19 at 11:25
  • @nvoigt You might have to recompile, but there's no breakage when swapping interface Foo { int Bar(double); }; for class Foo { public int Bar(double); ... } or vice-versa.
    – Caleth
    Apr 19 at 12:07
  • 4
    @Caleth in languages without multiple inheritance but with ability to implement multiple interfaces this will break any class that implemented that interface and already inherits another class. Apr 19 at 20:02
  • 1
    @MaciejStachowski: And in other languages, it'll break even if they aren't inheriting any other class, because the syntax is different.
    – Ben Voigt
    Apr 20 at 4:04
  • 1
    Only if you're not allowing the users to implement the interface themselves. But that's not always (arguably, not often) the case - even though Microsoft maintains the .NET Framework I can still implement my own IEnumerable<T> however I see fit, and if they suddenly changed it to an abstract class it would make a lot of people very upset. And that's discounting all sorts of reflection shenanigans. Apr 22 at 8:20
-1

In general, the primary reason the author of a type "doesn't want users of the class to know X about it" is the more users know about a type, the more likely they are to use it in a manner that would be incompatible with some later change the original designer would like to make. A decision to reveal certain details about a type should generally only be made after a careful evaluation about compatibility with possible future design changes. Keeping the details private means there is no need to perform such evaluation.

I don't really think that principle applies here in languages which make a distinction between classes and interfaces, since interface types can be used in some ways class types cannot, and vice versa. Given a class type with no exposed fields, it's generally trivial to create an interface type that could be used by someone needing an interface with the same properties and methods, and if the creator of a class would expect some clients might need such an interface, the creator of the class should supply one from the beginning, and should make it obvious which of the two types being defined is the class and which is the interface. Code which passes references should use the interface type, but code which needs to extend functionality of existing methods should inherit from the class type.

Your Answer

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

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