I-prefixes disappear from interface names
In Nette, interfaces were named with the letter I
at the
beginning (e.g. IRequest
). A couple of years ago, an extremely
slow and long term process began, which quietly while maintaining backwards
compatibility is getting rid of these prefixes. How exactly is this happening
and why?
Conventions Around Us
Nette has used the convention of prefixing interfaces with the letter
I
since its inception. Abstract class names were never
distinguished in any way. In other frameworks (e.g., Symfony, CakePHP, Zend, or
PSR), you may encounter a different convention – using the
Interface
suffix (e.g., Psr\Cache\CacheItemInterface
)
along with the Abstract
prefix for abstract classes (e.g.,
Psr\Log\AbstractLogger
). And finally, we have libraries (e.g.,
Laravel or the PHP system library) that do not distinguish interfaces or
abstract classes at all (e.g., the Throwable
or
Iterator
interfaces, the FilterIterator
abstract
class).
If we looked beyond the PHP world, the I
prefix is used for
example in C#, while Java or TypeScript do not distinguish names.
About a decade ago, when the Nette DI library was created, the heart of all modern and cleanly designed applications built on Nette, I fully realized that distinguishing between interfaces and abstract classes, whether by prefix or suffix, is a huge mistake. However, at that time, the framework had already been in existence for 5 years, and it was impossible to change the names of interfaces without causing a colossal BC break. To maintain consistency, I continued to use prefixes in Nette, but abandoned them in all other projects. (At that time, Nette was still a monolith, but for example, Nette Tester was a separate project and you won't find a prefix at the interface there).
Nevertheless, I was still looking for a way to painlessly abandon the
I
prefix. I consider distinguishing interface names to be such a
significant misstep that it was worth putting great effort into correcting it.
Especially since the framework is taken by programmers as a example of clean
design.
The reasons are the subject of a separate article Prefixes and Suffixes Do Not Belong in Interface Names.
How to Say Goodbye to the I-names?
After several years, I managed to find a way to remove the I
.
Quietly and with full backward compatibility. It was a process planned many
years ahead, which started with the release of Nette 3.1.
Usually, it was enough to simply rename the original interface (e.g.,
Nette\Mail\IMailer
to Mailer
) and create an alias
(IMailer
) at the same time, so that both versions would work. Along
with that, I added “hidden” code to the source file, which is only
recognized by the IDE and Composer. Thanks to this, autoloading works for the
alias, and it forces the editor to strike through it as deprecated
with a note to use the version without the prefix. Thus, all existing code works
without change, and the programmer is guided to prefer the new variant.
In some cases, I did not rename the interface because it was planned to be
changed (e.g., the new Nette\Security\UserStorage
differs from the
old Nette\Security\IUserStorage
, and both can be used
simultaneously during the transition), or because I am planning a different
solution (e.g., Tracy\IBarPanel
will be replaced by new Tracy
extensions).
In some cases, removing the prefix was not possible because the name was
already taken. This is the case with Nette\Security\IIdentity
and
Identity
. Here, it is necessary for SimpleIdentity
to
be used first as a successor to Identity
and the name to be
released. Such a thing has to be spread over several major versions and
therefore many years to go really painlessly. But there is no hurry.
So in Nette 4, only Nette\Http\IRequest
and
IResponse
will remain prefixed, as a reminder of a bygone era. And
also Nette\ComponentModel\IComponent
and IContainer
,
for which I am not sure if their existence is useful at all. The aliases will,
of course, continue to work.
Sign in to submit a comment