U předešlého článku se nám rozhořela pěkná diskuze :-) Rozhodl jsem se, že napíšu ještě jeden článek čistě na toto téma bez ohledu na PHP Jet. Tentokrát to bude pouze na téma návrh SW. Tak hurá do toho.
Jak jsem uváděl i v minulém článku, tak koncept DI je super věc a používám jí. Ale jako se vším, tak správný koncept se musí použít na správném místě.
Trvám na tom, že je nesmysl nějaký koncept používat všude. Veškerý dogmatismus je velice škodlivá věc. O to jde. Jde o tvrzení, že pro vytvoření „čistého, srozumitelného a udržitelného kódu“ (tedy aplikace) je nutné / dobré používat DI.
Otázka je, co je to ten „čistý kód“, ale držme se raději konkrétních situací.
Definice říká, že je to princip, kdy jedna komponenta používá druhou, aniž by znala její referenci. Tedy je to koncept pro určitou situaci a pro takovou situaci je to koncept velice užitečný.
Vzdalme se teď ze světa PHP, či jakýchkoliv jiných skriptovacích jazyků a ponořme se do světa jazyků jako je třeba C++.
Skriptovací jazyky nám umožňují tvořit mnohem vice dynamické aplikace (z hlediska jejich vnitřní struktury a chování). Nejsme omezeni překladačem. To je pro dané určení výhoda těchto jazyků a proto jsou tak hojně pro daný typ aplikací používané.
Ovšem já mám rád i staré dobré C (a v praxi jsem v něm pracoval a učí to mého syna) – vlastně nejdůležitější programovací jazyk na planetě, protože v něm je napsané i to PHP samotné a nejen PHP samozřejmě. V tom jazyce je člověk prostě blíž ke stroji. Však to znáte. Na vás je alokace i uvolnění paměti a tak dále. Používá se pointrová aritmetika. Prostě fajn zábava. A ano, vím že čisté C, není OOP jazyk, tak dejme tomu raději uvažujme o C++ – ať neslovíčkaříme. Jde tu o SW architekturu, ne konkrétní technologii.
Zpět tedy k „překládaným jazykům“. Když program překládám, tak jej samozřejmě linkuji s mnoha knihovnami atd. A může se stát, že potřebuji používat služby něčeho, co se mi natáhne dynamicky – třeba z dynamicky nahrávané knihovny na základě konfigurace (není to jediná cesta, pouze příklad).
V době překladu aplikace nemá tušení jaká přesně knihovna se konkrétně postará o danou věc. Např. jaký bude použit kodek na něco, či ovladač. Ale i tak aplikace musí to „cosi“ volat. A od toho může mít právě nějaký kontejner, u kterého je jasné rozhraní a je známo již v době překladu. Aplikace jasně zná kontejner, zná to i překladač a lze tak aplikaci přeložit. A do kontejneru je vložen poskytovatel samotné služby. Poskytovatelem služby – tedy tím co danou operaci opravdu provádí – může být právě dynamická knihovna (například) a kontejner se postará o potřebné náležitosti, nebo kontejner může být inicializován z venčí a tak dále. Ale to není podstata věci. Podstata věci je ta, že kontejner je známá entita a známé rozhraní, které zavolá konkrétní službu, která je však do určitého momentu neznámá.
Proto koncept DI vznikl. Aby bylo možné řešit takovou situaci v prostředí, kde je to vlastně technicky nutné.
A pochopitelně je víc cest, jak problematiku řešit.
Ovšem základní logika je tato:
Je to naprosto perfektní koncept a pro některé technologie vlastně nutnost.
Jednoduše se dá říct, že tento super-užitečný koncept není dobré používat na místech pro které postrádá smysl.
Ano, pokud je modelová situace taková, že aplikace potřebuje něco dělat, ale nemá tušení jak přesně se ta operace vykoná (například logování – krásný příklad), tak je rozhodně dobré tento koncept použít. Je to nejsnadnější cesta k vyřešení daného problému. A nejsnadnější cesta znamená kvalitní aplikaci. To platí pro jakýkoliv jazyk a jakoukoliv technologii.
Ovšem je kontraproduktivní používat tento koncept tam, kde pro něj není místo – tedy v situacích pro které není navržen.
Tam kde řeším jinou situaci použiji jiný koncept pro danou situaci vhodnější. Jednoduché …
A právě to jsou ty „čisté kódy“. Aplikace, které používají správné koncepty na správných místech.
Držet se dogmat nikdy není cesta k efektivitě. To i v lidském životě vede k problémům. Však se koukněte na náboženské a jiné fanatiky. To je vždy zlo. V technice by mělo být dogmatizmu co nejméně.
Pro jistotu opakuji: DI je super a má své nezastupitelné místo. Ale není dobré tento koncept dogmaticky používat všude, zejména tam, kde objektivně nemá své dané uplatnění a neplní svůj účel – aneb matku na šroubu také povolíte kombinačkami, ale není to ono, dá to práci a matka bude pořádně „ožvejkaná“.
Zde jsou důvody:
U toho posledního bodu se zastavím. Přemýšleli jsme někdy nad tím kolik paměti, I/O operací a instrukcí procesoru „sežere“ to, že se načítá konfigurace? A nedej bože když se musí nějak parsovat a případně řešit režijní operace s keší? Napadlo vás někdy kolik systémových prostředků „sežere“ registrace rout (mimochodem nedokážu si představit routovací pravidla pro mé projekty), nebo například tzv. služeb, middleware a toho všeho? Však jsem to v jednom ze starších článků ukazoval zcela názorně.
A teď je nutné zdůraznit PHP. PHP má tu výhodu i nevýhodu v tom, že pro každý požadavek aplikace znova nabíhá. Neřešme teď zda je to dobře, nebo špatně. Prostě to tak je. A pro každou prkotinu musí aplikace udělat poměrně dost věcí, „sežrat“ poměrně dost zdrojů systému. To vše je měřitelné. A ano, platí to i pro Jet.
Tak PHP prostě funguje. A s ohledem na to musí být náběh aplikace co nejjednodušší, nejrychlejší a nejoptimalizovanější.
A používání různých DI kontejnerů a dalších věcí, kde s růstem velikosti aplikace úměrně narůstá i náročnost a spotřeba zdrojů systému, jde přímo proti tomu. A to je problém. V online aplikaci dosti podstatný až řekl bych zásadní problém.
Jistě, je různé kešování a tak dále. Ale já říkám: Proč si problémy přidělávat dogmatickým používáním něčeho na to k čemu to není určené. A navíc tak porušovat jiné koncepty OOP.
Tož tak …
A omlouvám se, že nejsem neustále v diskuzi. Ale např. minulý týden jsem raději se synem blnul na horách. Díky za pochopení.
Ale čas si určitě zase udělám a do diskuze mrknu ;-)
Díky za přečtení a mějte se krásně!
Děkuji za článek.
Pokusím se uvést na pravou míru pár mýtů.
V části: "K čemu je koncept DI dobrý?"
1/ DI nevznikl jako koncept pro vytváření kontainerů.
2/ Ve skutečnosti váš příklad s kontainerem je nesprávný. Kontainer jak ho popisujete vlastně neřeší vůbec žádný problém. Pokud potřebuju nějaký adapter, tak ho zařídím aby měl stejné rozhraní jako ho požaduje služba. Nebudu na to vytvářet nějaký kontainer, až který by mi vynucoval nějaké rozhraní. Pěkný příklad zbytečného kontaineru je váš příklad logování. Kontainer, dle významu toho slova, se obvykle používá ve významu kdy seskupíte několik "logik" a adaptujete je tak aby ve výsledku poskytovali požadované rozhraní. Je-li těch "logik" jen jedna, tak tomu obvykle říkáme Wraper.
3/ Píšete: "Komponenty aplikace vědí jak onu servisní komponentu / službu volat a jak ji použít." - toto je vzor Service Locator nikoliv Dependency Injection. Praxe nám ukazuje, že SL je antipattern. Bezpochyby existují extrémě výjimečné situace, kdy může SL dobře posloužit. Ale na žádnou si nevzpomínám.
4/ Tedy závěrečné shrnutí je nesprávné, protože nepopisuje DI ale SL, a protože popisujete zbytečné používání kontaineru.
V části: "K čemu koncept DI není dobrý?"
5/ Zde není co vytknout. Jedná se o obecné principy se kterými asi všichni souhlasíme. Zřejmě vám to dávalo smysl v nějakém konceptu. Jediné, co by se tomu dalo vytknout, že to vlastně neodpovídá na otázku.
V části: "Proč není dobré používat DI všude?"
6/ Píšete "Přináší to do aplikace další složitost, která však není k ničemu reálně užitečná.". Nepravda. Praxe nám ukázala, že DI je velice zdravý koncept, který zjednodušuje aplikaci a zčitelňuje ji.
7/ Píšete: "Zatěžuje to vývojáře a odvádí jej to od řešení podstaty věci.". Naopak. Tím, že vývojář nemusí řešit kde sebere závislosti může se více soustředit na gró svého problému.
8/ Píšete: "Pokud používáte framework s nějakými konfigurovatelnými kontejnery a ještě ke všemu v nějakém nestandardním datovém formátu, tak vám to objektivně sníží technickou efektivitu aplikace." - Praxe ukazuje opak.
9/ Píšete: "Přemýšleli jsme někdy nad tím kolik paměti, I/O operací a instrukcí procesoru „sežere“ to, že se načítá konfigurace?" Ano, přemýšleli. Pár drobných to jistě bude. Praxe nám ukazuje, kolik zbytečného kódu je vyhozeno po té, kdy architektura začne respektovat DI.
10/ Píšete: "A nedej bože když se musí nějak parsovat a případně řešit režijní operace s keší?" - Snažíte se vyvolat dojem, jako kdyby to bylo nějak strašně moc. Můžete to podložit nějakými čísly? Mé zkušenost je na hraně měřitelnosti.
11/ Píšete: "A používání různých DI kontejnerů a dalších věcí, kde s růstem velikosti aplikace úměrně narůstá i náročnost a spotřeba zdrojů systému, jde přímo proti tomu. A to je problém. V online aplikaci dosti podstatný až řekl bych zásadní problém." Můžete to něčím podložit? Má praxe ukazuje, že toto není ten problém. Má praxe ukazuje, že problém je používání překonaných konceptů. Ani logicky to není pravda. DI kontainery jsou relativné levná záležitest Není důvod si myslet, že když to napíše programátor bude to lepší, než když se vygeneruje kontainer.
V části: "Závěr"
12/ Píšete: "DI je super koncept, který má své nezastupitelné místo." Zde jen doplním, že je vhodné se s tímto konceptem dobře seznámit. Vy nepopisujete to, co si pod tím pojmem představují ostatní. Ne, DI není Service Locator a už vůbec nijak nesouvisí s kontainery.
Což má ve výsledku dopad na zvláštní zmatení, kdy vy slovy kritizujete DI, ve skutečnosti kritizujete SL (a DIC a asi něco dalšího co jsem úplně nepochopil), a v kódu používáte (a jste po právu kritizován) SL.
13/ Dogmata jsou bez pochyby zlo, v tom se shodnem. Já ale DI propaguju proto, protože to má měřitelné výsledky, a od SL odrazuji, protože to má měřitelné škody. A samozřejmě, někdy pomůže něco naprasit, jistě. Ale stejně jako to funguje v Jazzu, musíte se nejdřív naučit hrát čistě, abyste mohl hrát falešně.
Děkuji za reakci.
Teď bych mohl rozebírat Vaše "vyvracení mýtů".
Ale taková diskuze by nebyla efektivní.
Porosím Vás o jinou věc:
Prosím sepište mi případovou studii z reálné praxe, třeba formou blogu, na které dokážete v jaké situaci, na jakém projektu a za jakých podmínek byl/nebyl daný postup správný/špatný a kde to dokážete zcela konkrétně kvantifikovat a podložit testy. Tedy bude to chtít dva podobné projekty stejného charakteru realizované dvěma přístupy a ty pak porovnané na základě reportů odpracovaného času, výkonnostních testů a aplikace a pak také reportů času servisních prací během životního cyklu aplikace.
To mě zajímá.
A vraťme se na začátek. Já reaguji na to, že kolega David Grudl v Nette, ale i jiních a jinde šíří myšlenky, které považuji na základě reálných zkušeností za mylné a troufám si tvrdit škodlivé. Škodlivé: používat něco všude, protože "hezký kód".
Vraťme se tedy k tomu na co reaguji a co vyvracím a to sem:
https://doc.nette.org/cs/dependency-injection/introduction
Prosím fakt mi sepište příipadovku z praxe na které je možné jednoznačně pomocí tvrdých dat čísel a reálných zkušeností dokázat, že uvedené je pravda a že to zvyšuje jak efektivitu vývoje, tak technickou efektivitu aplikace samotné.
Když půjdu obhajovat projekt před někým, kdo mi jej zaplatí, tak toho zadavatele budou zajímat pouze čísla a čísla vyjádřená ve financích. Ne slovíčkaření.
Dokažte mi tímto "cifršpiínským" stylem, že uvedené myšlenky jsou správné a přinesou objektivní a měřitelný benefit. To jest kolik to ušetří peněz jak při vývoji tak při provozu a kolik to ušetří systémových prostředků.
Velice rád si takovou případovku přečtu. A pokud v nerozporovatelných faktech dokáže že se pletu, tak to rád uznám a změním celé mé uvažování,.
Ostatně jako jsem to již udělal v jiných věcech.
Ale fakt chci čísla a fakta. Děkuji.
Například jako já zde vysvětluji a na číslech ukazuji, proč Jet nemá žádný NEON, YAML, či něco takového:
https://www.php-jet.net/doc/proc/proc-jet-pouziva-php-soubory-jako-uloziste-dat-a-zdroj-konfigurace
Tak takový článek, který podporuje tvrzení kolegy Grudla bych prosil. Pokud se pletu, rád bych to věděl.
Těším se na Váš článek!
Máte to nějaké pomotané. To vy tvrdíte, že vývoj bez DI je efektivnější, takže důkazní břemeno ja na vaší straně. Nenapadá mě jediný důvod, proč by BoneFlute měl povinnost vám vypracovávat jakési případové studie.
A k té konfiguraci v PHP: Ano, mít konfiguraci v PHP místo např. YAML je o něco efektivnější. Ale pokud nás až tolik zajímá rychlost, proč používáme tak neefektivní jazyk jako je PHP? Nebylo by lepší použít něco, kde se konfigurace načítá jednou za měsíc a ne stokrát za sekundu? Navíc tedy zcela opomíjíte nevýhodu konfigurace v PHP, a to, že se do takového souboru kromě konfigurace dá napsat naprosto cokoliv (a dřív nebo později to někdo udělá).
Tak ak mate konfiguraciu v PHP subore, tak je mozne ze sa bude nacitat aj menej casto ako raz za mesiac. Pretoze interpreter si ju ulozi do opcache a kedze bude volana pri kazdom starte scriptu (kazdy reqest sposobi novy start scriptu), takz tej opcache tak lahko nevypadne.
Ano mat v konfiguraciu v YAML je dobre koli prehladnosti, ale zaroven je dobre najneskor v pribehu CI vygenerovat prislusny PHP subor s konfiguraciou. Pretoze inak sa ten YAML parsuje stale dookola, miesto toho aby sa parsoval iba raz a tym klesa efektifita.
Schválně jsem nepsal "parsuje", ale "načítá", protože vím, že PHP kód se většinou cachuje. Tím "načítá" jsem myslel spíš třeba vyrábění instance a všechny ty ostatní věci, který cachovat nejdou.
Cachování naparsovanýho YAML configu za mě buď řeší framework (rozhodně by měl), nebo si to holt udělám ručně. Jasně, že parsovat YAML při každým requestu je sebevražda, ten formát je příšerně složitej. Ale generovat to už v průběhu CI je nějaký divný, zvlášť když ty konfigurační hodnoty jsou až v produkci (CI by produkční hesla do DB a podobný věci asi fakt znát neměl). V rámci deploye by to asi šlo.
Tak deploy je prave jedna cast CI cyklu. Rucny deploy sa uz v sucastnej dobe moc nenosi. Produkcne hesla je mozne mat ulozene tak, aby sa k nim proces ktory by nema, ani nedostane.
Dělali jsme studii na jednom z nejvytíženějších webů v Čechách a bylo zajímavé že načítání konfigurace z ini souboru byli rychlejší než z php (navzdory opcache). Logiku to dávalo. Každopádně to jen dokazuje, že je třeba posoudit případ od případu.
S čímž samozřejmě souvisí, že potřebujete principy které vám půjdou na ruku - DI, a nebudou vás omezovat - SL.
Nic to nemění na skutečnosti, že vyměnit parsování čehokoliv na cokoliv jiného je banalita nestojící za zmíňku. Zajímá mě jak snadné nebo těžké je ti udělat. Ne zda je to v základním balení.
Víte, já si čtu vaši prezentaci a dělám si rešerši. UI máte vcelku pěkné. Vnitřnosti špatné.
Když by se mě někdo ptal, zda bych PHP-jet doporučil, tak nedoporučil. Mám svědomí.
Ale. Já vám nebudu dělat žádnou studii, protože by to bylo proti mému businessu. Živíme se tím, že dávám dohromady projekty postavené na špatných principech jako je právě PHP-jet a přepisuju je do těch správných. Dokavad mi budou platit mé hříšné peníze, dělám to dobře.
Takže za mě, jen tak dál :-)
Píšete “ Například jako já zde vysvětluji a na číslech ukazuji, proč Jet nemá žádný NEON, YAML, či něco takového:”
Chybí vám tam porovnání s ini. Zjistil by jste, ze je rychlejší jak PHP.
Chybí vám tam kolik stojí test na zjištění existence prekompilovaneho souboru neon do PHP a jak se to promítne do celkové ceny. Zjistil byste, ze je to nula nula prd.
Přebívá vám tam absolutně subjektivní porovnání výhod a nevýhod která nejsou vůbec ničím podložena.
Ta tvrdá data jsou ty tři čísla. Ale zbytek textu se opírá o velké množství dat které tam nejsou a tím pádem jsem nucen je označit za hrubě spekulativní.
Takže sečteno podrženo takhle se fakta a čísla nedělají. Nepoužitelné.
Přijde mi, že vaše definice a představa DI je nějaká divná, a možná to je důvod veliké diskuze pod minulým článkem.
Dependency Injection znamená: Pokud třída potřebuje volat něco na jiné třídě/interfacu, musí si ho nechat předat v konstruktoru/parametru metody, místo toho aby si instanci vyráběla sama. Nic víc, nic míň. Nijak nesouvisí s tím, kolik má ta dependence implementací, jestli je to interface nebo třída, ani ničím jiným.
Díky tomu je na první pohled patrné, jaké dependence třída má. Nejsou v těle jejích metod schované žádně Něco::getInstance()
nebo jiná statická volání, která pokoutně získávají další dependence. Toto se velice hodí například v unit testech, ale pokud si dobře pamatuju jeden z prvních dílů seriálu, tak ty taky neuznáváte?
Například když z třídy vyřezávám část funkcionality do nové třídy v rámci refaktoringu, tak novou metodu neudělám static, i když bych třeba z pohodlnosti mohl. Rovnou novou dependenci "přiznám" a až ta nová třída sama začne potřebovat svoje dependence, nebudu muset přepisovat všechna místa, kde jsem volal NováTřída::nováMetoda
, ale jen jedno místo, kde se vytváří instance té nové i původní třídy. Což může být konfigurace nějakého DI kontejneru, ale taky naprosto obyčejný PHP kód plný new
- kód tzv. "dependency wiringu". Tohle místo může vypadat poměrně ošklivě a je to daň za použití DI, ale je to daň jediná a velice se to v dlouhodobém horizontu vyplatí. Je samozřejmě možné použít různé DI kontejnery, ale z mé zkušenosti to často ani není moc potřeba.
"Liskov substitution principle"! Kod ako ho navrhujete nie je SOLID, toto by bolo mozne, iba ak by PHP podporovalo pretazenie metod (tym aj konstruktoru) na zaklade parametrov.
Hu? Co z toho, co jsem napsal, není SOLID? A jak s tím souvisí počet konstruktorů? Možná jsi to blbě pochopil?
Pochopit mozem len to co napises, ak to myslis inak ako si to napisal, tak porucha nebude v primaci.
Pokud třída potřebuje volat něco na jiné třídě/interfacu, musí si ho nechat předat v konstruktoru/parametru metody, místo toho aby si instanci vyráběla sama.
Ako sa lisia konstruktory predka a potomka, kde potomok koli rozsireniu funkcnosti potrebuje dalsiu zavislost, o ktorej predok logicky nic netusi?
Zajímavý, že se tyhle "změny kontextu" a "porucha není v přijímači" dějou jenom tobě, zato hodně často. Ale určitě za to můžou všichni ostatní.
Jestli to správně chápu, tak tvrdíš, že konstruktor potomka musí mít stejnou signaturu jako konstruktor předka. Pokud je to pravda, tak jsi nepochopil LSP. Ten mluví o objektech, ne o třídách. Tzn. vytváření instance (konstruktor) opravdu LSP splňovat nemusí.
Ano musi mat rovnaku signaturu, inak by OOP fungovalo len v ramci dynamickych jazykov. OOP sa nedeli na svet PHP a ti ostatny. Aby boli principy OOP pouzitelne, tak musia byt jednotne napriec jazykmi ktore ho pouzivaju.
Nemáš pravdu, viz třeba tady: https://stackoverflow.com/questions/5490824/should-constructors-comply-with-the-liskov-substitution-principle
Jak s tím souvisí dynamicita jazyka nechápu už vůbec. Ale od tebe už začínám být zvyklej, že tvoje reakce jsou jak z generátoru náhodnýho textu.
No ak je tvoja studnica znalosti prave SO, tak sa moc necudujem.
Pouzivas nejake ine jazyky mimo PHP, pripadne C - -?
Tak prosím, najdi mi důvěryhdonej zdroj, kterej bude tvrdit, že konstruktor musí splňovat LSP (hlavně ať to není yegor256, ten chápe OOP a SOLID podobně zvrhle jako ty).
Budeš se možná divit, ale já naopak PHP skoro nepoužívám (mohlo ti to dojít z toho, jak na něj v podstatě všude nadávám). Teď zrovna mě živí Java.
Neznám jazyk, kde by konstruktor musel mít stejnou signaturu jako předek. (C++ má určité povinné konstruktory ale ve výsledku i zde mě tvrzení platí.) Konstruktor prakticky nikdy není součástí rozhraní. Prakticky nikdy by to nedávalo smysl. Bavím se o dynamických i staticky kompilovaných jazycích. Principy OOP se v žádném případě neopírají o konstruktory. Váš popis OOP nerozeznávám v žádné variantě objektového programování teoretického, praktického nebo nějak všelijak deformovaného stylu. Můžete dát odkaz na objektový styl ze kterého čerpáte?
Lenze konstruktor v PHP je sucastou rozhrania, skuste si bud reflection alebo zavolat konstruktor na instancii objektu. V PHP je konstruktor normalna metoda (polymorfna ako vsetky ostatne), volana PO inicializacii instancie objektu. Tak oni normalne jazyky s nezmrsenym OOP ani nemaju konstruktor (napr ADA). Maximalne tak metodu ktora sa vola default po vytvoreni instancie (_constructor v PHP, __init__ v Pythone).
> Lenze konstruktor v PHP je sucastou rozhrania, skuste si bud reflection alebo zavolat konstruktor na instancii objektu. V PHP je konstruktor normalna metoda (polymorfna ako vsetky ostatne), volana PO inicializacii instancie objektu.
Ano, zkusil jsem si to a je to bohužel opravdu tak - PHP mě klidně nechá ručně zavolat __construct na už existující instanci, čímž ji v podstatě zničí. Taky mě například nechá zavolat statickou metodu na instanci. Pokud z tohohle chování odvozuješ obecně platný principy LSP, tak asi nemá smysl s tebou dál diskutovat. Jak už jsem ti doporučoval jinde - zkus někdy i jinej jazyk než PHP, podle jeho bugů fakt nemá smysl chápat svět. SOLID a jeho části fungujou stejně ve všech jazycích, protože jsou to jen principy, kterým je třeba rozumět - ty ses je sice dokázal naučit a teď je prosazuješ s nadšením náboženskýho fanatika, ale bohužel jsi je vůbec nepochopil.
Jen se zkus zamyslet - ty tvrdíš nějakou věc, všichni ostatní tvrdí opak. Buď jsou úplně blbí všichni ostatní, nebo jsi úplně blbej ty - co je pravděpodobnější (odpověď závisí na úrovni sebevědomí a ignorance dotazovaného)?
Lenze to opakovane volanie ju neznici, ale reinicializuje. A ak odovzdavas zavislosti cez konstruktor, tak sa dostanes aj k vlastnostiam objektu ktore by mali ostat private. V spojeni s tym ze si cachujes konfig, podla ineho vlakna, tak mas prava zapisu na spustitelny kod, ktory ti volanim konstruktoru na uz existujucich triedach moze narobit vcelku slusnu paseku. Byt tebou, tak sa poohliadnem po velmi dobrej poistke pre pripad sposobenych skod.
Kolko ludi tvrdi opak? Tak 90%? Holt to koreluje s odhadom ze len 10% vie skutocne programovat, ostatok kod lepi, napr. pomocou stackoverflow a ma debilne navyky, nad ktorymi sa nedokazu kriticky zamysliet, nie to sa ich zbavit.
> Lenze to opakovane volanie ju neznici, ale reinicializuje.
Nic jako "reinicializace" objektu neexistuje (už to slovo samo o sobě je patvar). Kromě jazyků typu C++, který chápou objekt v první řadě jako místo v paměti a ne jako myšlenkovou entitu.
Jen abysme si to teda shrnuli: Ty tvrdíš, že konstruktor musí splňovat LSP, takže konstruktor potomka musí mít stejnou signaturu jako konstruktor předka, ale potomek může mít víc závislotí, takže jediný správný konstruktor je ten bez parametrů? A všechny závislosti se musí předávat jinak? Setterem?
> A ak odovzdavas zavislosti cez konstruktor, tak sa dostanes aj k vlastnostiam objektu ktore by mali ostat private.
Samozřejmě jsou private. Ale ten objekt je nevlastní, takže nijak nevadí, že tu stejnou referenci má i někdo jiný. Jak je předáváš ty?
> V spojeni s tym ze si cachujes konfig, podla ineho vlakna, tak mas prava zapisu na spustitelny kod, ktory ti volanim konstruktoru na uz existujucich triedach moze narobit vcelku slusnu paseku.
Jak mi zavolání new Třída()
způsobí paseku jinde? K existujícím instancím to přece přístup nemá. A tím "máš práva zápisu na spustitelný kód" myslíš koho? Nějakýho hypotetickýho útočníka, co mi místo configu vygeneruje new Třída()
? Jak to udělá? A proč by rovnou neudělal něco lepšího jako třeba remote shell?
> Byt tebou, tak sa poohliadnem po velmi dobrej poistke pre pripad sposobenych skod.
LOL.
> Kolko ludi tvrdi opak? Tak 90%? Holt to koreluje s odhadom ze len 10% vie skutocne programovat, ostatok kod lepi, napr. pomocou stackoverflow a ma debilne navyky, nad ktorymi sa nedokazu kriticky zamysliet, nie to sa ich zbavit.
S tímhle se dá výjimečně souhlasit. Ale asi ne tak, jak by sis myslel - protože ty jsi naprosto jasně v těch 90 %. V podstatě všechno, čím tady tapetuješ diskuze, je špatně nebo alepsoň nepřesně, a závěry z toho vyvozuješ naprosto scestný.
Máš třeba svůj github nebo tak něco? Tvůj kód bych si občas rád prohlídnul kdybych měl pocit, že už mi dlouho nekrvácely oči. (Můj sice zatím není moc aktivné, ale prosím: https://github.com/kostislav - to, co dělám v práci, bohužel opensource není)
No ja na opensource veru cas nemam. Takze Kostislav, nazrel som akurat do toho PHP repa. Takyto kod by cez code review vo firme s pricetnymi kolegami nepresiel. Nehovorim ani tak o komentaroch, i ked je lepsie vediet z komentaru co ta metoda robi, ako lustit spagetak. Ale chapem, popisat spagetak v metode do komentaru je niekedy nadludsky vykon. To ze jedna metoda by mala zastresovat jednu funkcionalitu by mal respektovat aj junior. Ktomu prechadzaniu pola cez foreach, mozno dobry napad v jave, php si ale v tomto pripade nad tym polom vytvara iterator. Preto je foreach dobry pre metody s yield, Reflection::getMethods vracia pole, tam by som pouzil array_walk. Toto ale nevedia zvedsa ani mediori, preto leju foreach vsade.
K odovzdavaniu zavislosti cez konstruktor. Preco by mali byt zavislosti posielane objektu cez konstruktor. Aby sme sa tomu vyhli (parameter passing) tak mame prave dependency injection. Naviac pri tomto postupe je nutne aby vsetky zavislosti boli este pred zavolanim konstruktoru v pamati inicializovane. Aj tie ktore nebudu pouzite. To ma negativny dopad nielen na vykon ako taky, ale aj na odozvu. Vacsina ludi opusti web ak nedostane odozvu do cca 10 sec. Google stranky s dlhou odozvou penalizuje este prisnejsie. To ze web odrati pomalostou urcite percento ludi vedenie ako tak prekusne, ale prepad vo vysledkoch vyhladavania ich rozladi zarucene.
Ako ich predavam ja? Nemusim mat globalny singleton, trieda ktora splna interface Configurable, ma konstruktor s jedinym parametrom - $configContext, ktory obsahuje parametre zavislosti a na poziadanie ich instancuje v pamati. Ked si to prezenies cez profiler (ak ti teda cachegrind nerobi problem) tak zistis ze je tam dost drasticky rozdiel.
> No ja na opensource veru cas nemam.
To je nakonec vlastně dobře :-) Takže když tě shrnu: "Kód na ukázání nemám, zdroje podporující moje nesmyslný tvrzení taky ne, ale rozumím všemu líp než všichni ostatní a já jedinej mám pravdu". Tak určitě :-D
> To ze jedna metoda by mala zastresovat jednu funkcionalitu by mal respektovat aj junior.
Máš na mysli nějakou konkrétní, která tě uráží? Některý by se asi daly rozdělit, ale nic úplně hroznýho bych tam nečekal...
> Ktomu prechadzaniu pola cez foreach, mozno dobry napad v jave, php si ale v tomto pripade nad tym polom vytvara iterator.
No a? Jako že se alokuje o jeden objekt víc? To nemá absoultně smysl řešit. Důležitá je čitelnost. Pokud chceš takhle pitvat performance na úkor všeho ostatního, použij vhodnější jazyk. Btw v Javě se ten iterátor vytváří taky.
> tam by som pouzil array_walk.
Kterej místo iterátoru zase musí vytvořit instanci té anonymní funkce. To sis vážně pomohl.
> Preco by mali byt zavislosti posielane objektu cez konstruktor. Aby sme sa tomu vyhli (parameter passing) tak mame prave dependency injection.
Možná by sis měl přečíst aspoň definici DI.
> $configContext, ktory obsahuje parametre zavislosti
Takže místo DI používáš Service Locator a ani o tom nevíš. To jsi mohl říct rovnou a mohli jsme si celou tuhle diskuzi ušetřit....
Tady musím reagovat. Konstruktor potomka nemusí být stejný, problém je, když musím změnit konstruktor předka, protože přibyla další dependency. Pak musím taky změnit všechny volání konstruktoru předka ve všech konstruktorech potomků a typicky přidat dependency do konstruktorů potomků.
Tohle peklo vidím na stávajícím projektu u datových objektů. Řešení je použít builder pattern u datových objektů, problém je, že třeba Lombok u Builder stále upravuje konstruktor místo, aby si vzal atributy přímo z Builder. U DI komponent je to horší, Builder snad DI implementace ani nepodporují. Dá se použít DI setter, který bude ale fungovat jenom do doby, než potomek tu metodu přepíše a nebude volat super, bo v době implementace metoda v předku ještě neexistovala. Dá se i předat DI factory samotná, ale to už trochu porušuje princip IoC.
Takže tady nějaké problémy jsou. Nenastávají příliš často, ale řešení příliš dobrá nejsou.
Navíc tomu nepomáhá zneužívání dědičnosti na reusable kódu. Když by se používala jen tam kde má, těch konfliktů by vznikal zlomek.
Tohle je pravda.
On Lombok obecně s dědičností moc dobře nefunguje (i když mám dojem, že by mohl, kdyby autoři tak nelpěli na podpoře Eclipse compileru).
Navíc teda použití Builderu má oproti konstruktoru tu nevýhodu, že zapomenutá dependence selže až za běhu místo hned při kompilaci.
Je možné, že třeba Spring by se dal ohnout, aby podporoval Builder (jistý si ale nejsem, v některých ohledech se dá ohnout dost, ale v jiných hodně málo), ale out of the box to zdá se opravdu neumí.
Ve své odpovědi jsem tohle neuvedl, protože mi to vůbec nedošlo - v našem kódu totiž děděičnost nepoužíváme, tak jsem na tenhle problém nikdy nenarazil.
Ad kod plny new: Toto je maximalne blby napad, kazde new alokuje pamat. V pripade vyvoja, ked ku aplikacii pristupuje jeden clovek, tak je to nepostrehnutelne. Pri nasadenina server kde k aplikacii pristupuje tisice uzivatelov je alokacia extremne draha zalezitost, vzhladom k tomu ako funguje chranena pamat. A to i v pripade kontajnerov, alevo virtualu s dynamicky alokovanou pamatou.
Přesně tak. Je vlastně s podivem, že princip DI není více zakomponován např. do objektově orientovaných programovacích jazyků. Že se stále drží toho operátoru new
, který není ničím jiným, než maskovaným: „Potřebujeme něco udělat. Dobře, takže musíme začít tím, že si alokujeme potřebnou paměť.“
Pokud má objekt dělat jenom jednu věc, nezbývá mu nic jiného, než závislosti, které potřebuje, dostat nějak zvenku, třeba v konstruktoru. Jakmile si své závislosti sám vytváří, dělá ten objekt dvě věci – vytváří si závislosti a vedle toho dělá i to, pro co byl původně určen.
Podival jste se opravdu jak ty DI kontejnery v Nette / Symfony funguji pod poklickou? Protoze oni ty yamly / nenony se parsuji prave jen jednou vznikne z nich stare dobre PHP ktere je jeste navic plne optimalizaci takze se instance vytvari az kdyz jsou skutecne potreba a ne do zasoby coz se rozhodne neda rict o
Product::setDb(new Db())
ktere pravdepdobne skutecne musite vykonat s kazdym requestem prestoze se zrovna Product nepouzije
Kdyz to prezenu tak vysledkem toho DI v nette / symfony je obycejne pole kde klicem je Jmeno Servisy a hodnotou pak tovarna. Tento soubor se drzi v opcache takze ziskani servisy je bleskovka dokonce si tvrdim rict ze to bude rychlejsi nez vami popisovany reseni. Jedine co by se dalopovazovat za problem je pamet praxe ukazuje ze i ve velkych projektech se jedna o stovky Kb max nizsi jednotky Mb (ktere jsou navic v novem PHP sdilene prave v opcache takze to ani neni per request).
Tim padem argument performance opravdu odpada.. k dalsim pozdeji :)
To by ale fungovalo len v pripade ze aplikacia ma moznost zapisat ten PHP script na disk, opcache pracuje na zaklade cesty k scriptu. To ale pridava zbytocnu zranitelnost, pretoze pripadny utocnik uz nemusi riesit nutnu eskalaciu prav pre zapis, rovno mu ich ponuknete.
Snad všechny frameworky vyžadujou write permissions na nějaký "var" nebo "cache" adresář. Potřebujou uložit zkompilované templaty, konfigurace a všechny tyhle další věci (díky tomu, že PHP prostě funguje od základu blbě). Samozřejmě pokud není server nastavený úplně kravsky, tak to nijak neovlivní nemožnost zapisovat kamkoliv jinam. Nebo jak mi jeden adresář vlastněný uživatelem www-data ovlivní zranitelnost zbytku systému?
Njn, to potrebuje kazda aplikacia, len tie rozumne vytvorene alplikacie to pouzivaju ako variable alebo cache, nikdy tam nemaju nastavene prava vykonat kod a spravidla v cache nema byt nic co nejakym sposobom zmeni chovanie systemu.
To nie je tym ze by PHP fungovalo blbo, aj s PHP sa da pisat bezpecny kod. Blbo od zakladu fungovalo smarty a dalsie frameworky ktore idu v jeho odkaze.
Nepsal jsem nic o bezpečnosti kódu v PHP. A prostě funguje blbě už ze svojí podstaty - v normálním jazyce by se ta šablona zkompilovala jednou a výsledek by se držel v paměti. Ale protože PHP má model "shared-nothing" mezi requesty, musí se zkompilovaná šablona někam uložit. A protože je potřeba, aby to bylo relativně efektivní (protože zase, bude se načítat při každým requestu), tak se musí uložit jako spustitelný PHP kód.
Tak aj v pripade PHP je mozne tu sablonu skompilovat raz a drzat ju v pamati opcache, to je potrebne ale urobit uz pri deploy (napr, v ramci CI). Kedze sa ta sablona zmeni az pri dalsom deploy, tak kompilovat ju az na servri a pouzit vlastnu cache nema zmysel, hlavne ked to do kodu zavadza bezpecnostnu dieru.
PHP nie je shared nothing, mate moznost pouzit shared mem, tu je nutne pouzit aj v inych jazykoch, ak aplikacia bezi vo viacerych vlaknach. Njn, kto so shared memory nevie, moze pouzit adresar na disku...
Ty by ses měl někdy podívat i mimo hranice PHP, abys zjistil, jak fungujou normální jazyky.
Jestli kompilaci dělat při deployi nebo just-in-time při prvním requestu je celkem jedno, a žádnou bezpečnostní díru to nezavádí, to už jsme řešili jinde.
Ano, v PHP se dá použít opcache. A právě proto se všechno musí předkompilovat do PHP skriptů. Protože prostě bez držení věcí v paměti se výkon získat nedá a nic jinýho než zkompilovanej PHP kód mě PHP v paměti držet nenechá. Vracíme se pořád k tomu samýmu. PHP je špatně už z principu, jen ty nic jinýho nejspíš neznáš, tak to pořád nechápeš.
To o těch "jiných jazycích" a více vláknech nemá smysl komentovat - zkus se podívat třeba na Javu/C#/Erlang/Rust/Go, jak může vypadat příčetný vícevláknový program, který nemusí používat žádný hacky typu "shared mem".
Tak nebo tak podle me odbihame, predpokladam ze se schodneme na tom ze vytvoreni DI kontejneru neni z pohledu performance zasadni problem.
Hlavni disuze by podle me mela smerovat k vyhodam / nevyhodam ServiceLocatoru a jinych reseni.
Na porovnavani jazyku tu je spousta jinych clanku :)
ta moja prvotna reakcia bola k moznosti spracovat yaml/neon iba raz, na strane serveru to vyzaduje nutnost mat pristup pre zapis do kodu ktory sa vykonava.
Co sa tyka kontajnerov, suhlas, ak su dobre implementovane tak prinasaju len vyhody.
Pravda, svoje využití má. Ale řekl bych, že spíš na menší weby s nízkým provozem, kde by se věci držet v paměti ani nevyplatilo. Jakmile se začne řešit performance (nebo nedejbože vlastní server), je nejspíš čas přejít na jiný jazyk.
Stejně jako když v bash skriptu je potřeba vytvořit funkci, tak to většinou znamená, že je čas ho přepsat třeba do Pythonu.
Malokdy je suktecny performance problem v PHP nechcu ho tady obhajovat sam preferuji jine jazyky ale pravda je ze pro PHP je mrte hostingu. Tim ze se vzdava multi-threadingu tak je mnohem pristupnejsi pro zacatecniky. Vetsina web-requestu multi threading skutecne nevyuzije..
Ale zpet k performance prvni facebook (pravda tam se od PHP uteklo ale i ta verze co v PHP byla napsana tak byla rozsahem rozhodne VELKY) , wikipedie nemyslim si ze jsou to male projekty a performance zvladaji.. ono kdyz si vezmete prumernou webovou aplikaci tak samotny HTTP request je relativne pomala zalezitost, pak tam mate vetsinou naky dotaz do DB to je taky docela dost pomale (at je ten dotaz sebe rychlejsi tak je tam sitovy roundtrip) a to co je mezitim na celkove performance zase tolik neprida.. Samozrejme pokud lovime kazdou ms tak je PHP mimo ale na vetsinu beznych veci to opravdu staci.. A on i ten typovy system tam pomalu zacinaji dopatlavat... osobne za dve nejvetsi chyby jazyka povazuju
1) Naprosto chaotickou standardni knihovnu..
2) datovy typ Array ktery je v PHP kombinaci Mapy, Setu, Listu ... to je takovy paskvil ze se z toho chce brecet.
A pokud se opravdu stane, že ten problém je PHP, a že to nejde rozumě optimalizovat, tak existují alternativy v podobě zephir-lang.com.
Dělal jsem na celkem velkých věcech, ale nikdy jsme se do této fáze nedostali.
Njn, len problem je ten ze vacsine nevysvetlis ze slovnik nie je pole aj ked sa nazyva array :D Si pamatam ked sa objavilo nette, okrem inych dristov aj "pole su spatna" preto v scripte ktory sa vykona a skonci, stale dookola, budeme do konstruktora pchat instancie objektov, nie slovnik...
“ To by ale fungovalo len v pripade ze aplikacia ma moznost zapisat ten PHP script na disk,”
Což je vždy.
Su firmy kde je nastavena urcita politika zabezpecenia a cez tu vlak nejde, iste videl som servre kde je selinux default vypnuty, a vsade mozne pouzity chmod a+w... To ako ste sa niekde v diskusii vyjadril ze ste ten co vsetky weby dava do late, tak by ste sa mohol podelit ako dokopat security team aby vam dal write prava na cely adresar aplikacie VZDY...
Myslím, že se obecně DI trochu přeceňuje - není to nic víc než trošku chytřejc použité interfejsy. I tak si ale myslím, že hlavní koncepční tahák pro DI je Inversion Of Control - pokud v článku nic nepíšete o IOC, pak je to marné. "Kontejnery" nejsou vůbec podstatné a v jiných prostředí ani nejsou. Taky by mohlo zaznít něco o lifecycle management a testovatelnosti kódu...
Samozřejmě že DI je banalita největší. A přesto je možné to chápat špatně. Asi by nám to obecně bylo jedno, když by tu autor neprosazoval tak profláklé antipaterny.
... nechal jsem si to projít hlavou, co na to napsat, takže trochu pozdní reakce...
Z velké části tady mícháte jabka s hruškama, co je container, co je DI, atd, to už napsal někdo výše.
Jak jsem psal u předchozího článku - vy tam DI defakto máte, akorát řešené svérázným způsobem a implementované pomocí globálních proměnných v rámci datového objektu (neviděl jsem implementaci Product, takže nevím, jestli je tam problém navíc, že jde přímo do DB nebo je tam ještě abstrakce nad tím). Tak jako tak, důsledkem je, že nelze například separovat Product od konkrétní repository, bez toho, aby aplikační kód přenastavoval dependency za běhu. Což znamená (nejen tady), že runtime konfigurace závisí na aplikačním kódu, místo, aby to bylo opačně - což přirozeně znemožňuje nebo komplikuje customizaci a reusability. O testech ani nemluvě (ale ty asi půjdou v Php nějak řešit). Kromě toho je značně nejasné, jaké jsou další zodpovědnosti Product, pro které musí mít další procesní i datové závislosti.
Z jednoho komentáře, jestli používat ini/json/native code. Ano, php kód bude asi nejrychlejší, to ale přímo neovlivňuje DI samotné. Hesla by třeba neměla být ani součástí kódu ani jiné konfigurace lokální - ideálně by měla autentifikace přes role nebo uložena v secret storage, pokud daná technologie podporuje jenom password authentication (viz třeba AWS Secrets Manager). Ohledně performance - v Java to je třeba naopak - JSON a XML budou rychlejší než Java konfigurace - pro benchmarks viz třeba https://github.com/kvr000/zbynek-java-exp/tree/master/benchmark/deserialize-benchmark/ , Java tam z nějakého důvodu chybí, ale byla značně pomalejší). Výhodou konfigurace v kódu (a důvod, proč ji většina moderních DI implementací podporuje a preferuje) je větší flexibilita, možnost implementovat podmínky apod, což je ve starém XML (Spring 2) dost komplikované. Ale v prvé řadě, pokud budu chtít řešit performance, tak nepoužiju Php :-D .
Ohledně výkonu DI - existují i compile time DI - například Dagger pro Java. Pokud budu chtít, udělám si DI v jakémkoliv jazyce manuálně - jednoduše si zavolám konstruktory ručně a předám jim dependencies na začátku aplikace - v C++ jsem to kdysi u některých projektů dělal - projekt měl nějaké jádro, které záviselo na platformově specifických komponentách, případně na testovacích komponentách - to je zcela validní přístup. Nevalidní je, pokud si ty aplikační komponenty začnou dependence nastavovat samy.
Pořád píšete, že děláte na velkých projektech a chcete čísla. Tak zkuste napsat, jak velké ty projekty jsou (LoC), kolik komponent v nich je, jaké jsou závislosti. IMHO posuzujete na relativně malém projektu REST+SQL+nějaké third party, kde jsou ty závislosti nejspíš poměrně jednoduché. Pro srovnání, teď dělám na projektu, který má hodně přes milion řádku (záměrně nechcu být ani řádově konkrétní) jenom v části Java, 150 externích third party knihoven (řekněme reálně 20 z top level), desítky DI modulů. Tento týden jsem opravoval DI hell vzniklé přesně podceňováním DI patterns po dobu několika let, což znamenalo 500 změněných aplikačních modulů a testů. Stálo to spoustu času a peněz, ale vliv na budoucí vývoj je nevyčíslitelný.
"udělám si DI v jakémkoliv jazyce manuálně" - vtírá se mi myšlenka, že tak trochu popisujete DIC. DI je IMHO ten princip/pattern, že si necháváš ty závislosti dodat. Zatímco to reálné dodávání, jak to nakonec bude řešené je už jen nudnej detail, řešený třeba ručně, nebo pomocí DIC.
Bazíruju, sorry.
Možná se hodí připomenout rozdíl mezi vzory "service locator" a "dependency injection":
"Když použijete lokátor služeb, každá třída bude závislá na vašem lokátoru služeb. To není případ vkládání závislostí. Injektor závislostí bude obvykle volán pouze jednou při spuštění, aby se vložily závislosti do nějaké hlavní třídy."
Hmm ted jsem dlouhou dobu delal s DI.
Do nove servicy jsem to dal taky hned jak zacala rust … ze prej ne e ze to neni potreba.
Ted se rozrostla a prej ze tam musime dat DI, protoze to kazdyho stve, jak chodi sem a tam a nejen ze upravuje kody, ktere by DI jednoduse vyresilo (a ktere neprinasi zadny prinos krome zpomalovani vyvoje), tak jeste k tomu musi chodit sem a tam pres unit testy a resit je taky.
Takze maly veci bez DI v pohode.
Jak to roste, usnadnuje DI praci, a to tak, ze hodne.
A mimochodem vyvojari jsou celkem blazni, takze pouzijiu DI tam kde je to uplne zbytecne a naopak. Kupodivu je to v realnem zivote tak trochu jedno - jsou vetsinou jiny problemy.
Za me po oetech zkusenosti DI jednoznacne ano, a to predevsim na vetsi aplikace nebo na aplikace, kde je slusna sance, ze ze to v dohledne dobe rozroste.
Ok je vikend mam vic casu takze jsem to procetl jeste jednou a poskytnu ucelenou odpoved:
Zde jsou důvody:
--- Přináší to do aplikace další složitost, která však není k ničemu reálně užitečná.
Slozitost to naopak ubira protoze komponenta NENI zavysla na zadnem externim kontejneru jako jednotce je ji to JEDNO protoze vsechno dostava ZVENKU. Muzu vymenit 1 DI mechnizmus za druhy a komponente je to jedno. Pripadne ji muzu predat zavyslosti rucne opet je to jedno.. co JE komplikovane je samotny DI kontejner (napsat ho rozumne efektivne neni prace pro kazdeho, proto ho kazdy nepise a pouzije uz hotovy, overeny, otestovany), me jako uzivatele to ale nezajima..
--- Zatěžuje to vývojáře a odvádí jej to od řešení podstaty věci. Prostě další věc na kterou musí myslet aniž by to přineslo reálný užitek a potřebnou efektivitu.
Opet neni pravda jako vyvojarna to prave diky DI kontejnerum vubec myslet nemusim protste pridam parametr do konstruktoru a DI kontejner se o vse postara sam, ja pracuju ze svou jednotkou a o nic se nestaram, kdyz zavyslost dale nepotrebuju proste ji uberu jak jsem psal driv povetsinou musim udelat zmenu prave na 2 mistech v samotne sluzbe a pak v jejim unit-testu.
--- Pokud používáte framework s nějakými konfigurovatelnými kontejnery a ještě ke všemu v nějakém nestandardním datovém formátu, tak vám to objektivně sníží technickou efektivitu aplikace.
Toto proste neni pravda.. evidentne s tim nemate zkusenost
Přidám: Krásná demonstrace loose couplingu - Když vytvořím nějakou vymazlenou logiku v nějakém prostředí respektující DI, tak ji mohu s minimálními úpravami vzít a přestěhovat klidně do php-jet. Když tuto logiku napíšu stylem, který je pro php-jet doporučován, tak když tu logiku budu chtít přesunout jinam tak mám smůlu. Strávím spustu a spoustu času na vyškubání těch vnitřních závislostí.
Dávám za „prostředí respektující DI“, dlouho jsem pro to hledal trefné označení a tohle budu používat.
> Definice (vzoru DI) je princip, kdy jedna komponenta používá druhou, aniž by znala její referenci.
Nemůže být problém už v té definici DI? Uvedená definice totiž odpovídá spíše návrhovému vzoru "service locator" (SL), protože DI komponenty reference znají už v době vzniku své instance. Pokud bych zaměnil původní výrazy vzoru DI za SL, tak kontroverzní výroky z toho článku začnou dávat najednou větší smysl.
Dlužno dodat, že podobně zavádějící definice je uvedena bohužel i na české Wikipedii: https://cs.wikipedia.org/wiki/Vkl%C3%A1d%C3%A1n%C3%AD_z%C3%A1vislost%C3%AD
Pak by se dalo souhlasit i s výrokem:
> SL je super a má své nezastupitelné místo.
Jedná se o případy, kdy je třeba získávat nové instance komponent. Tam v DI nevystačíme.
Ten wiki článek je teda hodně špatnej. Resp. ty příklady jsou docela OK (i když ne moc smysluplný), ale to vysvětlení je úplně mimo.
"1. Vkládání rozhraním" je taky popsaný úplně blbě, protože ho autor článku nejspíš nepochopil, tak se to snažil okecat (zdá se, že v tom původním článku je to prostě setter nadefinovaný na interfacu - k čemu to je, moc nechápu).
> Pokud bych zaměnil původní výrazy vzoru DI za SL, tak kontroverzní výroky z toho článku začnou dávat najednou větší smysl.
Bohužel nebudou. Protože on na jednu stranu ten vzor kritizuje, a zároveň ho obhajuje a v kódu používá.
Přečteno 15 401×
Přečteno 12 857×
Přečteno 12 855×
Přečteno 12 405×
Přečteno 11 728×