Ako služby ovplyvnili správanie injekcie pri závislostiach vývojárov - Flagbit Blog

Prinajmenšom od neustále rastúcej popularity jednotkových testov, najmä prostredníctvom PHPUnit, hrá v každodennom živote vývojárov riešenie závislostí tried prostredníctvom vkladania závislostí v PHP čoraz dôležitejšiu úlohu. Triedy, ktoré majú jednu alebo viac závislostí na iných typoch tried, sa prenášajú, keď sa vytvárajú prostredníctvom konštruktora alebo prostredníctvom volaní metód za behu. To zlepšuje udržiavateľnosť jednotlivých tried a závislosti sa dajú ľahšie vymeniť, ak sa zmenia požiadavky. Vylepšená je aj testovateľnosť jednotlivých komponentov, pri ktorých je možné závislosti tried nahradiť jednoduchými testovacími dvojkami. Nevýhodou je však zvýšený počet štandardných kódov, keď musia byť rovnaké objekty vždy vytvorené v rôznych bodoch projektu, aby sa pokryli rovnaké závislosti.
Takzvaný vyhľadávač služieb bol predstavený so súčasnými rámcami PHP. Úlohou vyhľadávača služieb je interne vyriešiť a vytvoriť inštanciu závislostí od služby. To znamená, že inštancie objektov je možné vytvoriť pomocou služby bez toho, aby ste museli pridať štandardný kód na vyriešenie závislostí v obchodnej logike. Vyhľadávač služieb ďalej zaisťuje jednu inštanciu volanej služby v rámci požiadavky, aby sa zabránilo zbytočnému generovaniu objektu bez nevýhod klasického singletonu.
V priebehu času však jednoduché použitie lokátora služieb viedlo k použitiu injekcie závislostí v smeroch, ktoré sa dajú technicky rýchlo implementovať, ale ktoré celkom neplnia svoj účel. Rozpustenie závislostí sa zmenilo na farebné spájanie tried.
Ďalej by som rád stručne predstavil prípady, s ktorými som sa každú chvíľu stretol. Spravidla to nemusí na prvý pohľad vyzerať zle, ale môžu mať nevýhody v ďalšom vývoji.
Vstrekovanie lokalizátora služby
Pravdepodobne najznámejší zlozvyk pri používaní a Vyhľadávač služieb je pridať to ako závislosť do svojej triedy. Zvyčajne je tento vzor sprevádzaný argumentom „Možno ešte potrebujem niektorú zo služieb“, čo je známkou toho, že jeho vývoj nebol dostatočne naplánovaný. Žiadna trieda nikdy nepotrebuje všetky služby. Na Googli niekedy nájdete aj komentáre, ktoré si myslia, že je v poriadku, ak je výrobcovi pridelený vyhľadávač služieb. Aj továreň potrebuje len málo služieb, aby fungovala. Ak existuje závislosť na viac ako 4 ďalších službách, mali by ste znova premýšľať o úlohe a štruktúre továrne.
Zložitosť je zrejmá najmä pri písaní jednotkových testov. Triedu možno zvyčajne použiť na identifikáciu závislostí od hlavy metódy metód konštruktora alebo setra. Pri pridávaní vyhľadávača služieb musí byť nielen pre toto, ale aj pre všetky skutočné závislosti, ktoré sú z neho načítané, vytvorené testovacie dvojité. Z kódu je tiež ťažké zistiť, aký je skutočný typ služby. Pretože trieda v PHP môže obsahovať aj metódy, ktoré nepochádzajú z rozhrania, zameniteľnosť tried s rovnakým rozhraním už nie je zaručená.
V ideálnom prípade by sa závislosti mali prenášať a nemali by sa brať z iného objektu.
Ak sa pozriete napríklad na Symfony 2, uvidíte, že tu sa priamo používa aj lokátor služieb. Najznámejšie príklady sú radiče a príkazy, ale iba ak implementujú rozhranie ContainerAware, čo je štandardne tento prípad. Existujú ale aj možnosti, aby sa tomu radiče a príkazy vyhli.
Protokolovanie
Protokolovanie informácií môže byť pre jeden projekt dôležitejšie ako pre iný a môže sa líšiť v množstve informácií. Preto často existuje prístup k trvalému vloženiu inštancie loggeru ako závislosti do služby triedy. Len vo veľmi málo prípadoch je však záznamník skutočne závislosť, pretože najskôr si musíte položiť otázku: „Bude moja funkcia fungovať aj bez záznamníka?“
V závislosti na rozhodnutí o dizajne môže stačiť hodiť výnimku v rámci triedy a okrem spracovania chýb pridať záznam do bloku catch.
Ďalšou možnosťou je zhromaždiť správy, aby sa mohli neskôr odoslať, ako je známe napríklad z validátorov. Aj tu je možné záznamy protokolu vytvárať mimo triedy, a tak je možné protokolový záznam extrahovať ako závislosť.
Je pravda, že nejde o porušenie hrubej závislosti, ale ak je ľahké udržať záznamníka mimo triedy, potom by to mal vývojár urobiť. Je to nepotrebná súčasť automatizovaných testov a je irelevantná pre funkciu testovanej triedy.
Príliš veľa závislostí
Každý, kto sa pozrie na množstvo závislostí v konštruktore svojej triedy a cíti sa s nimi nepríjemne, pravdepodobne tento problém rozpoznal. Jednoduché spracovanie konfigurácií služieb uľahčuje pridávanie nových závislostí, pretože vývojár sa pri vytváraní inštancií zvyčajne nemusí obávať výsledných zmien. Počet závislostí môže s postupom projektu stúpať a vytvárať tak zložitosť, ktorá sa zdráha dotknúť a zmeniť.
Mnoho kontajnerov na vkladanie závislostí ponúka možnosť nastavenia závislostí služieb pomocou metód nastavenia v konfigurácii. Výsledkom je, že niektorí vývojári majú tendenciu nastavovať závislosti pomocou metód setra namiesto konštruktora, čo však problém nevyrieši. Naopak: Nastavovače musia byť nastavené explicitne a iba vtedy, keď objekt už existuje. Konfigurácia služby akceptuje použitie nastavovačov, ale túto triedu je možné použiť iba s vedomím týchto nastavovačov, napríklad pre testy jednotiek, a pokiaľ nie sú stanovené povinné závislosti, musí sa vývojár postarať aj o spracovanie chýb. . To zbytočne zvyšuje postihnutú triedu. Nič z toho nie je potrebné pri vkladaní závislostí cez konštruktor. Ako by sa mal tento problém vyriešiť?
Je to dobré znamenie, že trieda robí viac, ako by malo byť.
V takom prípade je potrebné rozdeliť ich úlohy, ktoré potom predstavujú skutočné závislosti pôvodnej triedy. Nemožno vylúčiť, že pôvodná trieda sama osebe už nie je potrebná, a teda nie je použiteľná, pretože jej jedinou úlohou je vykonávať úlohy svojich závislostí.
Riešenie závislostí
Nie každá závislosť musí byť vyriešená prostredníctvom konfigurácie služby, a už vôbec nie priamej závislosti pre triedu. Napriek tomu sa vkladajú prostredníctvom konštruktéra prostredníctvom služby. Rýchla a ľahká konfigurácia služieb znamená, že zmeny je možné vykonať rýchlo bez toho, aby ste museli meniť miesta v kóde, ktoré volajú službu. Toto vyzýva vývojára, aby vyriešil všetko, čo sa týka konfigurácie služby pre dotknutú službu.
V nasledujúcom príklade má trieda Foo závislosť na $ myService, ktorá sa odovzdáva v konštruktore.
V príklade sa však táto závislosť používa iba v metóde doSomething. Ak závislosť nie je potrebná na samotnej triede, ale iba na jednej z jej metód, malo by sa zvážiť, či by nasledujúci prístup mohol byť lepším riešením:
Nevýhoda: Triedy, ktoré používajú Foo a jeho metódu doSomething, majú závislosť na $ myService.
Ako druhý prístup je tiež potrebné zvážiť, či úloha metódy doSomething nepatrí do svojej vlastnej triedy a či musí byť nakonfigurovaná ako samostatná služba. Táto nová služba však nemusí nevyhnutne závisieť od triedy Foo.
V tomto príklade kódu bola úloha metódy doSomething úplne odstránená z triedy Foo a implementovaná do novej triedy „Qux“, ktorá ako služba v predchádzajúcom príklade závisí od $ myService.
Samozrejme, tento príklad je jednoduchý, pretože v prípade refaktoringu stoja v ceste ďalšie prekážky. Keď sa zmení štruktúra triedy, zmeny sa musia vykonať na všetkých miestach, ktoré používali Foo. Zmena štruktúry triedy je ešte zložitejšia, ak je určená rozhraním.
Vkladanie závislostí a služby
Injekcia závislostí je zastrešujúci pojem, ktorý má mnoho rôznych foriem implementácie. O tom, ktoré z formulárov sa majú v konkrétnom prípade použiť, nemôže rozhodnúť kontajner na vkladanie závislostí alebo vyhľadávač služieb, ale musí o nich rozhodnúť samotný vývojár. Rámečky nám ponúkajú funkcie, ktoré nám pomáhajú s vývojom, a mali by uľahčiť mnoho zdĺhavých krokov. Ako sa používa, je stále na nás.