This post discusses the disadvantages of using the ‘I’ prefix for interfaces in static-typed languages.
That’s very interesting. I would have leaned toward the name
SqlPersonRepository instead of
PersonRepository because the latter implies that there is only one possible implementation, which would be a code smell.
It also makes sense that if we’re depending on an abstraction, we don’t need to know whether it’s a class or an interface. If we need to know that when we use it, or think we do, then we’re not quite getting the concept.
But ultimately I don’t think the problem is that developers don’t understand interfaces. The problem is that they don’t understand abstractions. There’s a tendency to write a class, create an identical matching interface, and inject that interface everywhere. The interface can be mocked, which is good, but because it’s a 1:1 representation of a concrete class, a class that depends on the interface is still coupled to the concrete class.
The “I” prefix is like the underscore in front of a field name. It’s a handy shortcut that makes it easier to understand how the code is written. It’s so ingrained that its absence alone might confuse someone.
re: SqlPersonRepository, that is exactly what I am advocating in the post. Call the Interface PersonRepository, then call the implementation SqlPersonRepository or InMemoryPersonRepository or…
re: not understanding abstractions: your absolutely right. Since Interfaces are the most commonly used abstractions (at least for .NET developers) I think helping them understand the real power of interfaces by forcing them to name the implementation something else, helps. At least that’s been my experience when training newer developers.
re: 1:1 representation: I am not sure I follow. Are you saying that because devs “think” of them as a 1:1 representation it still is coupled (in their mind)?
re: ingrained: I agree. It’s not easy to get devs to let go of the “I”, but even if you just train junior devs to do a sample without using the “I” I think it can help them understand the power that interfaces have for decoupling code.
Isn’t it something of a contradiction to be advocating against Hungarian notation because “modern IDEs” but advocating for a name like SqlPersonRepository? Surely the IDE gives you everything you need to know?
Modern IDEs aren’t the reason Hungarian notation fell out of fashion. If you call a variable rgiValues (array of integers) and you want to change the type to a generic list then you have something that is named incorrectly. That is an issue when your code/libraries/api’s are being called by other developers.
Other reasons we don’t need Hungarian notation include that we are writing much smaller methods on larger displays and declaring variables close to where they are used so the context is obvious. I still prefix my member variables with an underscore which is an immediate visual cue as to where to find the definition/declaration.
Adding an “I” to the name of an interface also provides a visual cue - if I see code where someone is injecting something other than an interface into a constructor then that can be a code smell.
Not a contradiction at all. Calling the Implementation something meaningful to how it is implemented is helpful. The IDE won’t tell you that the PersonRepository that is an implementation of IPersonRepository is saving to a database, to an in-memory list, or if it is just a mock of the IPersonRepository. But calling the interface PersonRepository means you are forced to call the implementation something else. Why not use that to communicate something to maintainers of the code?
I Agree that it is not modern IDEs that drove the decision to drop Hungarian Notation. But getting IDEs that help communicate whether something is an interface or a concrete class helped to kill the most prevalent argument at the time. which was, “How will I know it’s a string value if I don’t call it ‘strName’?” I heard that more than once in those days.
I totally agree with this. I too heard too many times “how can I know this thing’s type?”. Then I reply with the IDE argument. And comes inevitably, “ok, but what about notepad or paper?”. And then I come with the real argument: you don’t need to know this, focus on the variable meaning, its purpose. Especially when reading code: you don’t need to type check it in order to understand it. And when writing it… You’ve got a fancy IDE! Same argument I use toward people reluctant to use var or remove underscores from privates… All these naming conventions and explicit typing are noise preventing understanding of what’s important.
So, I definitely should adhere to the no-I-in-interfaces… I have, though, another rule: in Rome, do like Romans… I like consistency and the .net fx is full of IWhatever… So I stick to it when writing C#…
Anyway thanks for the article, I had nevergiven a thought to this ‘forces you to come with a good name’ argument.
I think I understand what @scotthannen says with the 1:1 representation. I don’t think that devs think of them as 1:1 representations, but rather they don’t understand interfaces are ‘more abstract’ abstractions than classes. I’d dare try to explain my understanding:
When developers don’t fully grasp the concept of interfaces, they tend to - in a pavlovian way - create IFoo + Foo (and sometimes an intermediate BaseFoo abstract class…) each time they need to implement a foo concept; in their mind they think of Foo implementation, then extract its whole public surface into IFoo.
Therefore, IFoo is usually the totality of Foo’s public interface and clearly not thought as a reusable, minimalist concept. Hence even if a consumer depends on IFoo, it, in fact, depends on Foo’s public interface.
Suppose I’d introduce a Bar class that does something similar to Foo and should be consumed by my same consumer that consumes IFoo. It will be difficult to have it implement IFoo because IFoo exposes members (deduced from Foo’s public interface) that make no sense in Bar… IFoo should be rethought, refactored in order to eliminate anything that’s not part of the foo/bar common concept… and this will probably break. The other option would be to implement all of IFoo in Bar with “return null” or “throw NotSupportException” every time IFoo’s member does not match anything meaningful in Bar. Worst!
I couldn’t agree more with this post.
I dropped the
I prefix from interfaces several years ago, and I like that it forces me to think about the name of the implementations more.
SqlPersonRepository : PersonRepository example was perfect.
I’ve seen this discussed years ago as well. There are good reasons, but it’s also ingrained now to identify when something is an interface without having to use Intellisense. I guess I see both sides of the argument. Also remember there was a good type of Hungarian Notation (Apps Hungarian? I forget which was Apps and which was System but the original version of Hungarian Notation was to indicate things about the type that you needed to know, rather than identifying its type), it was just perverted to be the str/int garbage. I’d actually argue that the I prefix is the good kind of Hungarian Notation (as good as it can be nowadays of course) so isn’t quite as bad as the datatype prefixing.
I agree it doesn’t make sense to prefix variables with str or cls mainly because cls doesn’t really tell me much about the variable (along with color,go to definition, and tooltips that tell you the type) but also when you change the type to something else a lot of times you forget to change the variable name but, for the love of god, what did that I in Interfaces ever do that was so wrong. Its a convention a lot of dependency resolvers use this convention to link interfaces to classes. It is like the i in for loops. It is ingrained into our lexicon. Let the I’s have it. Oh also, who uses repositories anymore? It is all about Query Objects. When you have to add methods to extend things it is a bad design, breaks many solid principles and makes me sad. Again if you have to add methods to classes and in turn their interfaces this is not the poor I’s fault this is a problem with Repositories in general.
I don’t disagree in theory, but I have two concerns: 1) The standard lib and all the microsoft extensions use the I prefix for extensions, and choosing to do different in your own code violates the principle of least surprise. 2) The I prefix tells me “this thing is an interface, which is available for multiple inheritance and doesn’t provide any inheritable code and never requires the override keyword”. Interfaces are pure abstractions, but they do need to be separated and distinguished from abstract classes, which might not be. (Though, if we all agree to stop using abstract classes and prefer delegation over inheritance in almost all cases, this criticism of your post disappears).
I’ve been pushing this for years, like, 10+. Sadly the herd of Microsoft developers just struggle to break free from the mainstream.
I think you should figure out more arguments to put in your harmful list, if you think there is any real value in skipping the I.
I have seen a lot of RepositoryImpl style classes to deal with the naming issue, true it forces you to think of another name, albeit not necessarily a good name.
So at the bottom line I think it will boil down to developer experience and competence, and dropping the I is just a personal preference.
I’ve been over our production code. There are a few cases of interface abuse where we had an ISomething that was only ever provided by a Something, a lot of collection-based interfaces (think kind of like ICollection vs Collection – yes this stuff comes up a lot), and a small number of well-architected interfaces that quite probably could be improved by dropping the I prefix.
But removing the I prefix from the collections interfaces would impede learning too much. They’re modeled after the stock ones with their frozen names.
Or if you follow something like onion architecture, your implementation of
IPersonRepository is still called
PersonRepository but it’s implementation is in an infrastructure layer project (or even just a namespace) like
MyProject.Data.Sql. Same non-problem solved and you have a better architecture. Next.
Totally agree. Fortunately, TypeScript (and to a lesser extent Flow) are re-introducing a new generation of developers to interfaces and they seem to have broken away from the ‘I’ prefix. Now all that remains is to teach interfaces as a data and operational modelling tool, an aid to large-scale programming, etc. etc.
Long Time Fan of the no “I” since reading http://memeagora.blogspot.c…
Dropping the I from interfaces makes perfect sense.
However, shunning the concept of Hungarian notation entirely is stupid. It obviously has its uses. And no, you cannot rely on the pretty colors for everything Hungarian notation can do. Especially if you are colorblind, but even for people with good vision.
Until we will have telepathic programming or something, Hungarian notation will have its uses.
Not in naming interfaces, though.
While I agree with most of what you said, I think you make a stronger argument for properly naming than against not prefixing interfaces with
SqlRepository et al are more declarative than just
PersonRepository, and this is a trend that Microsoft themselves are picking up on in their newer code too.
The biggest caveat with not using the
I prefix in C# would be consistency. As you mentioned, almost all of the interfaces in .NET are prefixed with an
I. Therefore, not using it in your application code would be counter intuitive at the very least. Granted it’s not difficult to figure out whether you’re dealing with an interface or a class (and most of the time, it doesn’t even matter), I value consistency in code style over naming pedanticism.
BTW I still print my code and elaborate it in the bed, in train, etc. For me all those “colorful” arguments is nothing.