Nefungující DI ve vztahu Prezentér <⇒ Model
- zachrdlapetr
- Člen | 49
Šaman napsal(a):
zachrdlapetr napsal(a):
Články o DI jsem si přečetl, ale i po přečtení to stále vnímám jen jako způsob práce. Rád bych v tom viděl trochu víc, a to pro mě znamená mít důvody, kdy můj způsob práce se zcela bez pochyby ukáže jako nefunkční.
…
Máš prosím nějaký nějaký ultimátní příklad, který můj způsob práce roznese? Abych neměl vůbec žádnou pochybnost, že předávání všeho přes DI je pro mě jediná cesta.
Jasně, že to není jediná cesta. Je to jen způsob práce.
Ale je to cesta, která se ukázala jako funkční i v případech, že komplexita projektu začne narážet na limity mnoha jiných řešení.Základem jsou pravidla „každá třída má dělat jen jednu věc“ (Single responsibility principle) a „jedna věc by se měla řešit jen na jednom místě“ (Don’t Repeat Yourself).
Tvůj přístup porušuje obě. Komponenta kromě své logiky řeší i vytváření dalších objektů. A vytváření těch objektů je rozdrobeno do mnoha komponent. A dokonce ani neexistuje soupis všech míst, kde třeba takový mailer (jak píšeš výše) vytváříš. Pokud budeš chtít udělat jedinou změnu, znamená to projít a změnit až desítky tříd. Zachraňuje tě jen fulltextové vyhledávání…Tohle už nesouvisí přímo s Nette, ale obecně s OOP programováním. Nette ve skutečnosti nic takového nevyžaduje a předávej, či vytvářej si to jak chceš. Jen ti s tím pak málokdo bude ochotný radit, protože většina Nette programátorů a aplikací využívá postupů, které u tebe nebudou.
Ještě přidám jeden volně související odkaz: Návrhové principy: SOLID
Základ: s tím souhlasím. komponentu beru jako konektor mezi modely a směrem do prezentéru. prezentér jako konektor mezi modely a komponentami a směrem do pohledu. jako opakování to nepovažuji, když potřebuješ jeden model v různých komponentách, tak se zdvojení nelze vyhnout. jediný rozdíl je v instanci.
Změna: to přeci znamená projít kód i když máš továrničku. Buď se mění modelová třída celá (metody) a pak to musíš změnit i v interface i v komponentách. Nebo se mění nějaká závislost (ty jsem řekl, že mezi modely nechci) a pak nemusíš měnit interface, ani komponentu bez ohledu jestli je tam modelová třída vstříknuta nebo se vytváří pomocí nové instance.
Návrhové principy: kouknu na to
- zachrdlapetr
- Člen | 49
Rob Bob napsal(a):
@zachrdlapetr využíval jsi někdy při programování rozhraní (Interface)?
ano. používáme ke standardizaci.
- David Matějka
- Moderator | 6445
Změna: to přeci znamená projít kód i když máš továrničku. Buď se mění modelová třída celá (metody) a pak to musíš změnit i v interface i v komponentách. Nebo se mění nějaká závislost (ty jsem řekl, že mezi modely nechci) a pak nemusíš měnit interface, ani komponentu bez ohledu jestli je tam modelová třída vstříknuta nebo se vytváří pomocí nové instance.
kdyz menis implementaci (treba toho maileru), ale rozhrani zustava stejne, tak v pripade DI a tovaren nemusis nikam zasahovat – ani do presenteru, ani do komponent. pouze zmenis v configu tu implementaci, ktera se ma pouzit. to, co pouzivas ty, tak musis projet vsechny komponenty a prepsat instancializaci toho objektu
- zachrdlapetr
- Člen | 49
Rob Bob napsal(a):
Tak ještě znova – představ si situaci, kdy budeš chtít komponentu využít na více místech (znovupoužitelnost je důležitá vlastnost komponent), ty na více místech v kódu budeš mít tedy něco jako:
<?php public function createComponentZobrazitTestControl() { return new \App\Controls\TestControl($this->database); } ?>
V budoucnu třeba přijde požadavek rozšířit funkčnost komponenty o logování – pak bys musel nějakou třídu Logger předat nejprve do všech presenterů (který ho navíc ani sám nevyžaduje), kde chceš používat komponentu, a navíc všude přepsat kód z
return new \App\Controls\TestControl($this->database)
nareturn new \App\Controls\TestControl($this->database, $this->logger)
místo toho abys to upravil na jednom místě – v továrně pro TestControl. V presenterech už bys měl totiž všude jenom univerzálníreturn $this->testControlFactory->create()
. Presenter nepotřebuje znát jaké třídy komponenta využívá.Mysli dopředu, že bude někdy potřeba aplikovaci upravovat, škálovat atd., což ti korektní používání DI (a dalších OOP návrhových vzorů, nevymýšlej kolo) do budoucna usnadní. To stojí za to minimum práce navíc, když ty třídy píšeš poprvé.
Pokud by se to týkalo všech vložených komponent TestControl, tak bych Logger přidal pouze do jediné komponenty TestControl jako novou instanci. Pokud jen jedné, tak se stejně musí udělat jiná komponenta. Z mého pohledu se mění pouze vytvoření instance. Vycházíš z předpokladu, že mám všechny modely naskládané jako inject v BasePresenter. Ale já je tam v mé variantě mít nemusím, protože je volám až z komponenty jako vlastní instanci komponenty.
Myslet dopředu: to dělám a nechci udělat zbytečně komplikovanou aplikaci. ty přístupy, které se teď učí budou za 5 let zase jiné. rád bych přešel, ale zatím mi ty argumenty nezarezonovaly. Slyším na ztrátu a zisk :)
- David Matějka
- Moderator | 6445
Vycházíš z předpokladu, že mám všechny modely naskládané jako inject v BasePresenter.
proc bys to tam musel mit? do presenteru predas akorat tovarnu na komponentu. ty sluzby, co pozaduje komponenta, tomu preda DI kontejner pres tu tovarnu
- CZechBoY
- Člen | 3608
zachrdlapetr napsal(a):
Myslet dopředu: to dělám a nechci udělat zbytečně komplikovanou aplikaci. ty přístupy, které se teď učí budou za 5 let zase jiné. rád bych přešel, ale zatím mi ty argumenty nezarezonovaly. Slyším na ztrátu a zisk :)
to je zajímavý, zjistil jsem, že dependency injection „vzniklo“ až asi v roce 2004 – v rychlosti jsem nenašel nic staršího než zdroj 29 na wikipedii (Martin Fowler (2004–01–23). „Inversion of Control Containers and the Dependency Injection pattern – Forms of Dependency Injection“) https://en.wikipedia.org/…cy_injection#…
- zachrdlapetr
- Člen | 49
David Matějka napsal(a):
přesto však když komponentu volám, tak ji musím nakrmit závislostí a to je pro mě stále ten krok navíc.
nemusis, o to se prave stara ta tovarna
po této větě jsem musel jít do dokumentace a něco ověřit. klíčová věta byla „nemusis, o to se prave stara ta tovarna“. já se koukal na několik projektů a oni tam prostě do prezntéru injectnuli model a pak v createComponent cpali setterem všechny závislosti manuálně. A i když měli interface, tak to nebyla továrna.
Pak to beru. Rozdíl je jeden řádek navíc v komponentě, se kterým problém nemám + továrničky + neřešení v prezentéru jen metoda create z továrničky , ale to předpokládám udělám skript, který osahá všechny komponenty a udělá továrničky anebo využiju tu co jsi poslal.
Děkuji za trpělivost a nasměrování.
- zachrdlapetr
- Člen | 49
David Matějka napsal(a):
Vycházíš z předpokladu, že mám všechny modely naskládané jako inject v BasePresenter.
proc bys to tam musel mit? do presenteru predas akorat tovarnu na komponentu. ty sluzby, co pozaduje komponenta, tomu preda DI kontejner pres tu tovarnu
jo. teď mi to dává smysl
- zachrdlapetr
- Člen | 49
CZechBoY napsal(a):
zachrdlapetr napsal(a):
Myslet dopředu: to dělám a nechci udělat zbytečně komplikovanou aplikaci. ty přístupy, které se teď učí budou za 5 let zase jiné. rád bych přešel, ale zatím mi ty argumenty nezarezonovaly. Slyším na ztrátu a zisk :)to je zajímavý, zjistil jsem, že dependency injection „vzniklo“ až asi v roce 2004 – v rychlosti jsem nenašel nic staršího než zdroj 29 na wikipedii (Martin Fowler (2004–01–23). „Inversion of Control Containers and the Dependency Injection pattern – Forms of Dependency Injection“) https://en.wikipedia.org/…cy_injection#…
ale ty způsoby skladby vícevrstvé aplikace se měnily.
- zachrdlapetr
- Člen | 49
@DavidMatějka, @CZechBoY , @Šaman, @OndřejKubíček, @RobBob, @ali, @pavelmlejnek, @PavelKravčík
Děkuji všem za trpělivost a pomoc při odhalení nesouladu mezi mým způsobem uvažování nad aplikací, DI a továrničkami, které jsem považoval za komplikované z důvodů, že jsem koukal na nějaké projekty, kde sice měli interfaces, ale nepoužívali je jako továrničky, takže otrocky vše v prezentéru vkládali do komponent manuálně. Uzavírám.