Z názvů rozhraní mizí prefixy I

před 3 lety od David Grudl  

V Nette se rozhraní pojmenovávaly s písmenem I na začátku (např. IRequest). Před pár lety započal nesmírně pomalý a dlouhodobý proces, který tiše při zachování zpětné kompatibility začíná rozhraní prefixů zbavovat. Jak přesně to probíhá a proč?

Konvence kolem nás

Nette používalo konvenci prefixovat rozhraní písmenem I od svého počátku. Názvy abstraktních tříd nikdy nijak neodlišovalo. U jiných frameworků (např. Symfony, CakePHP, Zend nebo PSR) se můžete setkat s odlišnou konvencí, a to používáním koncovky Interface (např. Psr\Cache\CacheItemInterface) společně s předponou Abstract pro abstraktní třídy (např. Psr\Log\AbstractLogger). A nakonec tu máme knihovny (např. Laravel nebo systémová knihovna PHP), které rozhraní ani abstraktní třídy nijak neodlišují (např. rozhraní Throwable nebo Iterator, abstraktní třída FilterIterator).

Kdybychom se podívali mimo PHP svět, prefix I používá třeba C#, naopak v Javě nebo TypeScriptu se jména neodlišují.

Zhruba před deseti lety, v době, kdy vznikla knihovna Nette DI, srdce všech moderních a čistě navržených aplikací nad Nette, jsem si plně uvědomil, že odlišování rozhraní a abstraktních tříd, ať už prefixem nebo koncovkou, je obrovská chyba. V té době už ale framework slavil 5 let existence a nebylo možné názvy rozhraní měnit, aniž by to způsobilo kolosální BC break. Pro zachování konzistence jsem u Nette používal prefixy dál, ale u všech ostatních projektů od toho upustil. (Nette bylo v té době ještě monolit, ale např. Nette Tester byl samostatný projekt a v něm už prefix u rozhraní nenajdete).

Nicméně stále jsem hledal cestu, jak by bylo možné prefix I bezbolestně opustit. Odlišování názvů rozhraní vnímám jako natolik podstatný přešlap, že mi stálo za to vynaložit velké úsilí do jeho nápravy. Zejména proto, že framework berou programátoři za vzor čistého návrhu.

Důvodům se věnuje samostatný článek Předpony a přípony do názvů rozhraní nepatří.

Jak dát Íčku sbohem?

Po několika letech se mi podařilo najít způsob, jak dát I pryč. Tiše a s plným zachováním kompatibility. Šlo o proces naplánovaný na mnoho let dopředu, který odstartoval s vydáním Nette 3.1.

Obvykle stačilo jednoduše původní rozhraní přejmenovat (např. Nette\Mail\IMailer na Mailer) a zároveň vytvořit alias (IMailer), aby fungovaly obě verze. Společně s tím jsem do zdrojového souboru přidal „skrytý“ kód, který vnímá pouze IDE a Composer. Díky němu funguje autoloading i pro alias a přiměje editor, aby jej v kódu přeškrtával jakožto deprecated s poznámkou, že se má používat verze bez prefixu. Takže veškerý dosavadní kód funguje beze změny a programátor je přitom veden, aby preferoval novou variantu.

V některých případech jsem rozhraní nepřejmenovával, protože bylo v plánu je změnit (např. nové Nette\Security\UserStorage se liší od starého Nette\Security\IUserStorage a v rámci přechodu lze obě používat současně), nebo protože chystám jiné řešení (např. Tracy\IBarPanel bude nahrazen novým rozšířením pro Tracy).

V některých případech odstranění prefixu nebylo možné, protože název byl už obsazený. To je třeba případ Nette\Security\IIdentity a Identity. Tady je potřeba, aby se nejprve zaužívalo SimpleIdentity jako nástupce Identity, a název se uvolnil. Taková věc se musí rozložit na několik major verzí a tedy mnoho let, aby proběhla opravdu bezbolestně. Ale není kam spěchat.

V Nette 4 tak zůstanou prefixované už jen Nette\Http\IRequest a IResponse, jako připomínka někdejší doby. A dále Nette\ComponentModel\IComponent a IContainer, u kterých si však nejsem jistý, jestli je jejich existence vůbec užitečná. Aliasy budou samozřejmě fungovat dál.

Komentáře

  1. Tolik snahy o znepřehlednění kódu v tak krátkém čase se opravdu jen tak nevidí…

    před 3 lety

Chcete-li odeslat komentář, přihlaste se