Pod článkem Dependency Injection versus Lazy loading se vyrojilo velké množství komentářů, dle mého však nešlo o přínosnou diskusi, ale spíš o nepochopení a špičkování se bez jakýchkoliv hmatatelných argumentů. Aby neubližovaly samotnému článku, přenesl jsem je pod tento spot.
Lazy loading je technika, která musí být (stejně jako jakákoliv jiná technika!) pochopitelně použita jen tam, kde je pro ni vhodné místo. Nebylo předmětem článku tohle řešit (vydalo by to možná na celý seriál). Reálným problémem, kterému programátor přecházející od singletonů a Service Locatorů k Dependency Injection čelí, je, jak vůbec lazy loading použít, pokud jej skutečně potřebuje. Service Locator ho totiž nabízí by design. Na což právě zmíněný článek dává odpověď.
Komentáře
Jan Tichý #1
Ahoj Davide, asi budu zase za kverulanta…
…takže prostě normální proxy?
Jinak lazy-loading při dependency injection osobně považuji za antipattern. Proč? Drtivá většina případů se dá navrhnout tak, aby lazy-loading potřeba nebyl. A aby se v každém daném okamžiku injectovalo vždy jen a pouze to, co opravdu potřebuji, nic víc, nic méně.
Pokud potřebuji lazy-loading pro injectování, je to v naprosté většině signál, že je něco špatně navržené. Typicky že daná servisa je příliš velká a komplexní, že je porušen single-responsibility principle apod.
Například v Tvém příkladu s článkem by se na první pohled hodilo Connection lazy-loadovat, protože ho ne vždy potřebuju a často chci s článkem pracovat zcela bez Connection. Ve skutečnosti je ale chyba v tom, že Connection dovnitř Article vůbec nepatří.
Další příklad – v presenterech můžete často narazit na to, že při instancování presenteru do něj injectuju ledacos, ale pak ve skutečnosti využiju jenom část z toho – některé injectované servisy jsou potřeba jen v některých actions apod. Takže by se na první pohled pro tyto servisy opět hodil lazy-loading. Ve skutečnosti jsou chybou ale příliš velké presentery obsluhující několik různých věcí, namísto hromady malých mikropresenterů, což je zrovna v Nette přístup výrazně čistší.
Jan Tichý #2
…a existují spíš výjimečné případy, kdy se lazy-loading opravdu hodí. V takovém případě je ale opravdu lepší sáhnout buď po klasické továrničce, anebo po opravdové nemagické proxy, která implementuje dané rozhraní a lazy inicializaci si dělá transparentně uvnitř sebe.
Jakub Tesárek #3
Opět zde musím zopakovat svůj názor, že je to jen obyčejná proxy, byť nedotažená.
Bohužel, rozdíl mezi továrnou a tímhle Accessorem není absolutně žádný. V obou případech volám cizí metodu a doufám, že mi vrátí to co potřebuju.
Nechci se tu pouštět do nějakých zběsilých diskusí. Fakticky uznávám, že může existovat legitimní důvod pro to, dělat něco podobného pro získání efektu lazy-loadingu (i když mě teď zrovna žádný nenapadá, DI tohle řeší tak nějak btw).
Každopádně, proč to proxy nedopsat? V podstatě to bude dělat úplně to samý, jen budeš mít jistotu co dostáváš, bude ti sedět hinting. Přestaneš magicky něco vytvářet uvnitř třídy, který už má service jen použít. A až se rozhodneš, že ten lazyloading vlastně nepotřebuješ, tak tam pošleš normální service, ne oproxyovanou a nemusíš nic předělávat.
David Grudl #4
#1 Jane Tichý, Proxy je objekt mající stejné API jako objekt, kterého obaluje. Nic takového v článku není.
Pokud považuješ lazy-loading za anti-pattern, budiž, nikdo ti ho nenutí. Pokud chceš ale polemizovat, zkus to bez demagogie, bez hastrošů (Imago), tj. že rozcupuješ příklady, které jsem neuváděl a sám sis je vymyslel (z jiného článku), a také bez Quousque, tj. třeba věta „pokud potřebuji lazy-loading pro injectování, je to v naprosté většině signál, že je něco špatně navržené.“ vytvářející falešný dojem, jako bych snad tvrdil opak. Naopak tím připouštíš, že v menšině případů je lazy-loading vhodný, což je v rozporu s tvým tvrzením, že jde o anti-pattern.
David Grudl #5
#2 Jane Tichý, a já tvrdím, že ne. Argumentoval jsem celým článek, proč nepoužít právě továrničku, ty přehlídkou Čapkových demagogických figur 😉
#3 Jakube Tesárku, není to nedotažená proxy, není to vůbec proxy. Nerozumím tomu, proč se snažíš vše naroubovat na vzory, které znáš. To je přece zcela proti duchu návrhových vzorů.
Jako důležitý rys tohoto řešení vidím to, že nevytváří nic magicky a plně „sedí hinting“, pokud to vidíš jinak, budu rád za vysvětlení. Mýlit se mohu. Ale určitě zkus předtím dvakrát číst a jednou komentovat 😉
Jan Tichý #6
#4 Davide Grudle, Takže je to jen nedotažená proxy ;), viz komentář Jakuba Tesárka výše. Proč tedy nepoužít místo takových divných a na první pohled ne zcela snadno pochopitelných obezliček, jako jsou zmiňované accessory, rovnou plnohodnotnou proxy, kde můžu typehintovat přímo na rozhraní dané konkrétní služby bez nutnosti přihazovat si k tomu nějaká další zbytečná pomocná rozhraní? Nebylo by to jasnější, čitelnější a průzačnější?
Příklady jsem uváděl ty nejčastější, kde IMHO budou lidé dělající v Nette v praxi nejčastěji po lazy-loadingu sahat. A je úplně jedno, jestli jsi je uváděl nebo ne, pokud se to stane běžnou praxí, jakože jsem přesvědčen, že stane, je zcela relevantní se o tom bavit.
Chceš-li ale, pojďme tu diskutovat o nějakém jiném konkrétním příkladu, kde dává lazy-loading smysl. Napadá Tě nějaký? Mě teď vůbec žádný (což může znamenat jak to, že mě zrovna opustila fantazie, tak i to, že to opravdu je antipattern ;)).
Jan Tichý #7
#5 Davide Grudle, Špatně je na tom to, že ten lazy-loading předjímáš:
Na jednu stranu injectuješ nějakou službu do presenteru. V tom okamžiku je ideální, když presenter nemusí vůbc nic vědět o tom, že chceš nebo nechceš něco lazy-loadovat. To totiž není problémem toho presenteru, ale je to problémem té služby jako takové.
Na druhou stranu mě ale nutíš už při psaní presenteru určit, co se (potenciálně) bude lazy-loadovat (musím to injectovat jako accessor a výzvedávat přes get()), a co se lazy-loadovat nikdy nebude (budu to injectovat rovnou).
V důsledku to pak povede buď k jednomu ze tří důsledků:
IMHO je tedy jediným dobrým řešením do presenterů injectovat cokoliv, co implementuje rozhraní původní služby, a o tom, jestli ji tam budu dávat samotnou, nebo lazy-loadovanou přes proxy, se rozhodovat venku mimo presenter. Prostě IoC :)
Jakub Tesárek #8
#5 Davide Grudle, Patterny jsou jen názvy pro obecně používané postupy které mají pomoci při komunikaci. Nejedná se o soubor konkrétních implementací. Navíc nevím, co myslíš tím „všechno naroubovat“, ale to je asi teď jedno.
Uznal jsem že to je „nedotažená proxy“, zajišťuje ti přístup k objektu o kterém zatím nevíš, jestli ho vůbec budeš potřebovat. Proxy (neboli „zástupce“) je to proto, že ho strkáš jako zástupný objekt do kontruktoru místo požadovaného objektu.
Uznávám, že neimplementuje jeho rozhranní. To je ale chyba. A pokud chybu opravím a pak smažu zbytečnou metodu get(), tak mám proxy jak z učebnice.
David Grudl #9
#6 Jane Tichý, figura třetí, Caput Canis, označíme řešení dehonestujícími slovy jako „divné a na první pohled ne zcela snadno pochopitelné obezličky“, protože jsme v argumentační nouzi.
Jestli zvládneš všech 12 figur, dostaneš speciální bagde „Diskusní troll“ 😉
David Grudl #10
#7 Jane Tichý, #8 Jakub Tesárek zcela zásadním momentem je, že presenter ví, že se lazy-loaduje a že je to právě presenter (uživatel služby), a nikoliv služba samotná, kdo to má vědět. Nesnažím se lazy-loading maskovat, naopak se k němu hrdě hlásím.
Jakub Tesárek #11
No, konečně se někam dostáváme.
A já si zase myslím, že vzhledem k principům IoC je uživateli houby do toho, kde se ten objekt veme, jak se persistuje, jestli se cachuje nebo lazy-loaduje. Presenter (uživatel služby obecně) dostane objekt který potřebuje. Ale jak to funguje uvnitř, tak do toho nemá co šťourat
Jan Tichý #12
#9 Davide Grudle, Nápodobně – figura osmá – ulixes.
#10 Davide Grudle, Aha, tak v tom se opravdu dost zásadně rozcházíme. Nevidím jediný smysluplný důvod, proč by to měl presenter vědět. Naopak to způsobuje WTF moment, kdy z pohledu potřeb presenteru stejné injectování se dělá dvěma různými způsoby.
David Grudl #13
#11 Jakube Tesárku, #12 Jan Tichý SignPresenter je přesně ten, který ví, že objekt bude potřebovat v jednom případě z tisíce. On, nikdo jiný. Proto právě on chce objekt získávat líně. A proto místo objektu získává jeho „továrničku“. (V uvozovkách, protože v článku vysvětluju, že právě továrnička není vhodná.)
Jan Tichý #14
#13 Davide Grudle, Díky za posunutí diskuze. Směrem, ve který jsem doufal.
Protože důvod „presenter bude potřebovat objekt v jednom případě z tisíce“ je IMHO právě ten špatný důvod pro lazy-loading, o kterém jsem mluvil výše, a to vždy a ve všech případech. Který je buď zbytečný (místo jednoho instancování objektu servisy instancuju objekt accessoru a pak ještě k tomu někdy objekt servisy, takže místo jedné instance vyrábím jednu až dvě instance) anebo se dá obejít lepším návrhem presenterů (místo jednoho velkého god presenteru udělám deset malých).
Pokud jsem výše psal o tom, že ve výjimečných případech se lazy-loading hodí, tak IMHO jediným relevantním důvodem pro to je případ, kdy je velice drahé nějakou servisu instancovat. Což je ovšem nezávislé na vůli presenteru, drahé je to vždy. Naopak presenter by o náročnosti dané konkrétní implementace servisy neměl vědět vůbec nic, natož aby to mělo dopad do toho, jak je ta servisa uvnitř něj volaná. A měl by si to rozhodovat kontejner, kde vím, jakou konkrétn implementaci servisy používám, jak moc drahá je a jestli bych ji tedy měl chtít schovat za lazy-loading proxy.
Jakub Tesárek #15
#13 Davide Grudle,
David Grudl #16
#14 Jane Tichý, určitě bude pro všechny nejpřínosnější, pokud příklad z tohoto článku přepíšeš tak, aby lazy loading nepotřeboval (a v ideálním případě to i vysvětlí, v čem je lazy-loading špatný).
#15 Jakube Tesárku, omlouvám se, skoro vůbec nerozumím. Tak jen k poslední větě: říci si pokaždé rovnou o accessor není návrat k service locatoru, protože na rozdíl od něj své závislosti explicitně a jednoznačně uvádíš.
Jan Tichý #17
#16 Davide Grudle, Přepsáno je to Tebou samotným na samém začátku Tvého článku :)
Vysvětlení, v čem je lazy-loading vynucující si změny v samotném presenteru špatný, viz několik mých předchozích komentářů.
Já #18
Upřímně, zlatej injectovanej container. Sice má svoje problémy, ale zrovna u controllerů, alespoň člověk nemusí vytvářet další zpomalující konstrukty jen aby byl nakonec papežtější než papež.
Jan Tichý #19
#18 Já, Injectovat kontejner do kontrolerů je špatně. Vymýšlet „další zpomalující konstrukty“ je taky špatně. Naštěstí obojí je jen produktem špatného návrhu a obojímu se dá tedy dobrým návrhem (malé presentery, důsledná DI typehintovaná na rozhraní servis) vyhnout, takže ve výsledku bude vše přehlednější a rychlejší.
Já #20
#19 Jane Tichý, Vidíš, já to používám a vůbec se mi z toho špatně nedělá. Špatně by se mi dělalo v případě, že bych crud rozděloval do několika kontrolerů jenom protože chci v jedný akci někdy poslat mail, v druhý možná translator a v třetí třeba šablony. Aneb jak z KISS udělat přearchitekturizovanou(yea, right) sračku. Asi jsem holt špatnej programátor, no co už…
David Grudl #21
#17 Jane Tichý, Honzo, už v té diskusi ohledně předávání závislostí presenteru na fóru mě překvapil dogmatismus, s jakým k tomu přistupuješ. Já hledal nejlepší ze 4 nedokonalých řešení a ty jsi viděl jedno dokonalé a zbývající zcela špatné. Jako nyní.
Jestli dobře chápu, říkáš, že lazy-loading jedině formou proxy, jiný způsob je anti-pattern. Nechápu ten černobílý pohled. U obou přístupů vnímám výhody i nevýhody.
V příkladu v tomto článku jednoznačně platí, že presenter ví, že získanou závislost použije jen občas. To je prostě fakt. Zcela nezávisle na tom, jestli je službu vytvořit náročné (ale s pragmatickým vědomím, že v bezstavovém PHP je vše náročné) může rozhodnout, že ji bude získávat lazy. Už to, že ji v konstruktoru uvádí jako povinný parametr, neodpovídá zcela realitě. Principiálně korektnější je předání jinou & čistou formou. Což je taky celkem důležitý moment.
Pochopitelně jsou situace, kdy měnit implementaci kvůli lazy-loadingu je nešťastné a proxy je pak výborné řešení, ale není náhodou, že jsem v článku použil takový příklad, jaký tam je.
I proxy má nevýhody oproti zdejšímu řešení:
Z toho důvodu se kvalifikovaně rozhodnu, které řešení v dané situaci použít, ale rozhodně nebudu zabejčenej, že jedno je naprosto dobře a druhé naprosto špatně.
Borek Bernard #22
Zajímavá diskuze. Jednoznačně se stavím na Honzovu stranu, ale s jednou důležitou podmínkou. PHP už si moc nepamatuju a Nette neznám prakticky vůbec, takže to moc nedokážu posoudit, ale pokud současně platí oba následující body:
tak potom patrně proxy nestačí. Tipnul bych si ale, že ve většině případů tyhle podmínky nejsou splněny (nebo aspoň ne obě dohromady) a proxy tak v pohodě stačí – je to ověřené řešení a kód je IMO o dost přehlednější.
Mimochodem, asi to mělo vypadat jako série o Dependency Injection, co? :)
Borek Bernard #23
Sakra, asi jsem měl komentář odeslat až po přečtení poslední Davidovy reakce :)
David Grudl #24
#22 Borku Bernarde, Když ti to převedu do řeči C#, Honza říká, že Lazy<T> je za všech okolností anti-pattern, já tvrdím, že nikoliv. Za koho se stavíš je mi fuk 😉
Borek Bernard #25
#24 Davide Grudle, Ani C# není úplně můj jazyk, ale dík :) Co v PHP udělat něco jako
Lazy<T>
místo „accessorů“? Plní stejnou roli, ale vypadat by to mohlo líp.David Grudl #26
#25 Borku Bernarde, V PHP nelze použít
<Abc>
, takže se musí udělat extra interface LazyAbc. Jenže označení LazyAbc se mi nelíbí, zní to jako forma implementace Abc, nikoliv jeho getter, takže mi připadlo rozumnější AbcAccessor.Borek Bernard #27
#26 Davide Grudle, Typ nejde předat parametrem nebo tak něco?
David Grudl #28
#27 Borku Bernarde, tady nejde o předání typu parametrem, ale korektní návrh z hlediska DI, kde u parametru uvedu výstižný typ. A jelikož
__construct(Lazy<Abc> $arg)
zapsat nejde, zapisuju__construct(AbcAccessor $arg)
.Borek Bernard #29
#28 Davide Grudle, Aha, zkusil jsem si napsat
__construct(Lazy(Abc) $arg)
a už to chápu :)Peter #30
Možná jsem omezený… ale určitě jsem zmatený.
Neměla by Authenticator dostat přímo metoda formSubmitted()? Tady to teda ještě tolik nepálí, vzhledem k tomu, že jediná injekce je právě Authenticator, takže je vidět, že jinudy se nepřihlásí, ale pokud bychom (např. v příkladu s ukládáním článku) používali vícero podobných úložišť, které by byly injektovány nepřímo (tj. $article->setDatabaseConnection(Connection) $article->setFileConnection(Connection), místo $article->save(Connection)) tak víme, že to někam uloží, ale už nevíme kam… (Asi by byl vhodnější příklad, který by opravdu potřeboval ukládat na disk i do databáze). Ale zpátky se na začátek: pokud by se v případu s formSubmitted() Authenticator inicializoval až při zavolání (byť si nedovedu představit, jak by to bylo implementovatelné, snad ona proxy), tak by se tím vyřešil i lazy-loading… Presenter by pak místo použití Accessoru až když potřebuje dostal rovnou Authenticator jen tam, kde potřebuje… jestli to ovšem jen neschová magii kamsi do taťky
Form
uláře.Jiří Knesl #31
Vzhledem k „Nechci ti do toho kecat Jiří, ale tak strašně dlouhé komentáře fakt nikdo nečte…“ jsem usoudil, že je má odpověď dost dlouhá na článek.
https://web.archive.org/…-vs-accessor
Jiří Knesl #32
Obecně ještě můžu dát obecný tip: v konstruktoru nedělejte žádnou práci, maximálně nastavování hodnot atributů. To je bezbolestné a lazy loading z důvodů rychlosti a náročnosti nebudete nikdy potřebovat (netvrdím, že se nenajdou situace, kde je z jiných důvodů lazy loading vhodný).
Honza Marek #33
Osobně mi ten lazy loading přijde trochu přeceňovanej. Vyrobit objekt accessor přece nemůže být o moc levnější než vyrobit objekt authenticator. Takovej authenticator si představuju jako jednoduchou třídu, která si v konstruktoru přiřadí nějaké připojovátko k databázi do privátní proměnné a nazdar. Tak kolik tohle může sežrat výkonu, i když se to použije v jednom případu z 1000?
NoxArt #34
Pokud se jedná o to jestli lazy-loading ano nebo ne … nejsem nějaký veterán, ale když jsem se pokoušel zrychlit svoji aplikaci, výrazně největších zrychlení jsem vedle cache dat dosáhl při použití lazy loadingu / lazy exekuce, takže mám jasno.
Je jasné, že PHP v rychlosti nebude konkurovat C, ale nějaká optimalizace není na škodu.
Accessor nebo ne … samozřejmě hezčí by bylo mít normálně proxy. Koukám že Davida #21 David Grudl napadly nevýhody, je fakt že ta údržba by mohla být nepříjemná, leda by to člověk generoval.
Problém vidím asi jen v tom nahrazování, co se týče pochopení, když bude někde „accessor“ a nepochopí to člověk hned, přečte si jeho phpdoc a ve všech dalších případech v aplikaci mu to už bude jasné.
#14 Jane Tichý, Jenže se předpokládá, že ty instance jsou každá jinak náročné na inicializaci. Na první pohled je lepší 100 × 0.2 + 1 × 2 než 101 × 2.
#32 Jiří Knesle, Hm, pravda … ale zase když první konstuktor má nějaké závislosti a ty závislosti mají další, tak to může narůst. V aplikaci jsem měl Doctrine2 a tam inicializace (min. bez APC) poměrně bolí.
Filip Procházka (@HosipLan) #35
Tak mě napadá, kdyby se presentery dělily podle HTTP metody (POST, PUT, GET) tak bych nějaký lazy-loading vůbec řešit nemusel, protože bych authenticator předal pouze do
SignInPostPresenter
u (to je ale blbé jméno).Čímž se dostáváme k tomu, že když je to pěkně navrženo, tak Lazy-loading ani není potřeba.
A lazy-loading (pro mě) není potřeba ještě z jednoho důvodu. Třídy píšu tak, aby náročné operace byly v metodách, nikoliv v konstruktoru. Tedy vytvoření a zahození objektu někdy proběhne a je to zbytečně, ale skoro nic mě to nestojí. Příkladem budiž geniální
lazy: true
pro připojování k databázi v dibi.Co se týče implementace accesorů, nelíbí se mi ta metoda ->get() tam. Je to sice čisté, ale smrdí to trochu těstovinama.
Ugo #36
každé řešení má svoje, nic dokonalého není. Rozhodně nemá smysl nějaké řešení odsuzovat, mimo to že je to podle vzoru jedna paní povídala existují i jiné věci – rychlost a jednoduchost tvorby, rychlost a náročnost běhu (jistě dnes není in dělat kvalitní aplikace, prostředky jsou tak proč neplýtvat). Mě se nejvíc osvědčil klasický kontejner a tam kde potřebuji jednu závislost, tak tam jí hodit parametrem. U toho přihlášení bych dával ale potřebný autenticator až do metody která jej potřebuje, přesneji u presenteru bych si ho vybral z contextu (u mě $this->authenticator), tam se pěkně vybere, případně vyrobí když neexistuje a já ušetřím tunu zbytečné práce. V controlleru obecně je potřeba často mnoho modulů, takže předávat je všechny ..
všechno je to jenom hledání mě vyhovujícího poměru mezi konvencí, minimalizací, znovupoužitelností a lehkým rozšířením. Každý má ale tu hranici priorit jinde.
Jan Tichý #37
#21 Davide Grudle, Davide, co může navenek vypadat jako dogmatismus, je ve skutečnosti moje snaha o maximální jednoduchost a čitelnost kódu. Snaha o to nezavádět do jazyka/frameworku/aplikace další a další nové konstrukce (které se každý další programátor musí naučit, k čemu jsou a jak se používají, aby vůbec rozuměl předhozenému kódu), když by se mohlo najít řešení, při kterém nejsou vůbec potřeba, dá se jim vyhnout a kýžená věc se dá udělat jednodušeji a elegantněji – s použitím jen standardních všeobecně známých konstrukcí, postupů a notací.
Je to dobré jak pro úplné začátečníky (nebudou zmateni a vyděšeni, okrajové věci, jako je lazy loading nebude odvádět jejich pozornost od důležitých věcí), tak i zejména pro firmy našeho typu, kde se praktikuje týmový vývoj, střídají se vývojáři v týmu i na jednotlivých projektech. Učit každého nového vývojáře zas a znova, k čemu slouží nějaká metoda setContext nebo co jsou accessory, by mi dávalo smysl, pokud by to nešlo jinak. Celé je to o tom, že ono to jinak jde, čistě a elegantně, s využitím standardních ne framework-specific postupů, bez nutnosti mít vůbec k dispozici nějaké setContext nebo accessory a rozumět tomu, proč tam vlastně jsou, co dělají a jak se používají.
Pokud můžu něco udělat hezky a čistě s využitím standardních postupů, anebo ne tak hezky s využitím framework-specific konstrukcí, hlasuju prostě vždy pro první variantu. Nesouhlasím s Tebou, že hledáme nejlepší ze 4 nedokonalých řešení, já tam opravdu vidím jedno „dokonalé“. Jasně, asi se dá vždy najít nějaký velice okrajový případ, pro který tohle jedno řešení jednou za sto let nesedne stoprocentně, ale to je pro mě přijatelná cena za to, že budu mít v repertoáru málo jasných a čitelných řešení formulovaných jednoduchými pravidly, než dalších několik různých „wtf“ nástrojů, které se musím učit navíc, znepřehledňují kód a ve kterých se utopím.
Má řešení tady i u presenter injection mají společné to, že využívají víceméně standardní postupy bez nutnosti učit se další dodatečné na první pohled nejasné a nečitelné framework-specific konstrukce. To, co může vypadat jako dogmatismus, jsou pouze jednoduchá snadno předatelná pravidla formulovaná jako logický důsledek celého návrhu. Jejich „dogmatické“ dodržování vede k čistému kódu, který je čitelný, ve kterém nejsou logické a systémové rozpory, nenarážíš na žádné paradoxy, nemusíš myslet na to, jestli někde zapomeneš volat konstruktor rodiče, nemusíš u presenteru přemýšlet nad tím, jestli lazy nebo nelazy a jak to sakra vlastně udělat apod.
Ano, je to snaha o černobílý pohled, jednoznačně. Ale jen v mezích toho, co mě nikde neomezuje, nezpůsobuje žádné problémy, zpomalení, nečitelnost, nejasnost, neefektivitu… Pokud lze za takových podmínek černobílého přístupu dosáhnout, je to pro mě ideál. A ono v mezích toho, o čem se tu bavíme, opravdu lze.
Jiří Landsman #38
#34 NoxArte, Jak přesně je proxy náročné na údržbu? Pokud se mi změní rozhraní třídy kterou by zastupovala tak stejně musím jít a měnit všechen kód který danou třídu používá. Myslím, že změnit pak jeden soubor navic aby proxy reflektovala rozhraní které implementuje je minimum toho co můžeme udělat.
Proti tomu je myslim mnohem horsi případ s accesorem kdy se rozhodneme, že už ho nepotřebujeme a budeme muset jit a odstranovat ho.
Navíc si myslím, že presenter má úplně jiné starosti jako rozhodnout se jestli zavolat uložení článku nebo uživatele přesměrovat a jeho data tím odmítnout než jestli lazyloadovat nebo ne
Jan Tichý #39
#21 Davide Grudle, Pojďme se ale opravdu bavit zcela konkrétně nad zcela konkrétními případy.
Vezmu hned první, a to je ta autentizace z příkladu. Pokud injectuju autentizátor tisíckrát a z toho ho použiju jen jednou, tak pro mě není signál, že bych měl použít lazy loading, ale signál, že ho injectuju někam, kde nemá co dělat.
Čistý postup je tedy mít něco jako LoginPresenter pro vykreslování login formuláře a věcí s ním souvisejících. A pak vedle něj něco jako LoginSubmittedPresenter pro zpracování a přihlášení se. Do prvního samozřejmě žádný autentizátor neinjectuju, do druhého ano.
Což teda je hodně dobrý nápad takhle rozdělovat aplikaci na malinkaté presentery i bez ohledu na DI, například z důvodů, jak fungují v Nette signály, ale to je úplně jiné téma na úplně jiný článek. Takže to, že se nám takové rozdělení hodí i tady pro DI, je spíš příjemný vedlejší efekt něčeho, co je dobré dělat tak jako tak.
Tharos #40
#35 Filipe Procházko (@HosipLan), Já poměrně často rozepisuji CRUD do čtyř presenterů… V podstatě to, co je u jiných nějaký ArticlePresenter, je u mě rovnou ArticleModule. :) Presentery jsou poté ReadArticlePresenter, CreateArticlePresenter a tak podobně.
(IMHO) elegantně řeší řadu zde probíraných problémů. Dalším bonusem je, že skoro všechny třídy se pak na větším monitoru vejdou celé na obrazovku ;). Prostě takové SRP v praxi.
Na druhou stranu je to ale hrozná pruda v tom, že sebemenší aplikace má pak 50+ tříd a střední aplikace jde hravě do stovek. S jejich zakládáním ještě jakž takž pomáhají IDE, ale následovné časté přepínání mezi nimi je pak skutečný porod.
Mně známá (mainstreamová) IDE na to IMHO nejsou moc dobře připravená. Hrozně mě štvalo, když jsem se kvůli každému přepnutí do jiné odpovědnosti musel přehrabávat ve stromu projektu kdo ví kam…
Prostě IDE, která mi prošla pod rukou, nebyla moc dobře připravená na to, že budu chtít za jedno dopoledne zasáhnout celkem do 30 tříd… Všechna byla spíše připravená na kód, kde typická třídá má několik set řádků :) (navigátory v kódu a tak podobně).
Pokud bych ale osobně měl někomu demonstrovat, jak hezky v „MVC“ napsat třeba blog za pár minut, rozhodně bych CRUD rozdělil do čtyřech presenterů (zastřešených jedním modulem).
Filip Procházka (@HosipLan) #41
#38 Jiří Landsmane, Nette má perfektně implementovanou invalidaci Cache. Takže se dá jednoduše udělat to, že když se změní soubor, invaliduje se cache a proxy se ti sama vygeneruje znovu. A protože proxy musí mít vždy úplně stejné rozhraní, jako třída kterou obaluje, nemusíš měnit nic 2×, můžeš předstírat, že o žádné proxy vůbec nevíš. Skoro bez práce. (průser je, když máš vě třídě něco final)
Filip Procházka (@HosipLan) #42
#40 Tharosi, Tvůj přístup je správný a já ho také praktikuji. Ovšem moje IDE to zvládá celkem obstojně, má šikovnou zkratku na otevření třídy podle jména, aniž bych se někde proklikával.
Ale já se bavím o rozdělení podle HTTP metod
Tharos #43
#42 Filipe Procházko (@HosipLan), A kteréžto IDE se tedy takhle hezky osvědčilo? :)
Jan Tichý #44
#34 NoxArte, „Pokud se jedná o to jestli lazy-loading ano nebo ne … nejsem nějaký veterán, ale když jsem se pokoušel zrychlit svoji aplikaci, výrazně největších zrychlení jsem vedle cache dat dosáhl při použití lazy loadingu / lazy exekuce, takže mám jasno.“
A já jsem i bez toho, že bych to viděl, přesvědčený, že to je důsledek špatné architektury aplikace a že dobře postavená aplikace by takové výkonnostní problémy neměla ani bez lazy loadingu.
„Proxy – je fakt že ta údržba by mohla být nepříjemná, leda by to člověk generoval.“
Problém je v tom, že si tu možná interfacy představujete jako nějaké mega obrovské definice s desítkama metod, do kterých se pořád něco přidává. A obdobně pak i proxy třídy jako něco obrovského.
Přitom v mém ideálním černobílém světě existuje spíš hodně malých interfaces a i když výsledná servisa implementuje zpravidla více různých rozhraní, pro daný účel vždy potřebuju jen jedno z nich. Takže i příslušná proxy pak snadno a jednoduše implementuje jen právě to jedno z nich, krátké a malinkaté, bez nutnosti opisování tun kódu, duplikované implementace desítek metod, nutnosti nějaké šílené správu v budoucnu.
„Jenže se předpokládá, že ty instance jsou každá jinak náročné na inicializaci. Na první pohled je lepší 100×0.2 + 1×2 než 101×2.“
Ale ty jsou pak náročné na inicializaci vždy, nikoliv jen v kontextu daného presenteru. Takže kdybych chtěl jó lazy-loadovat, budu to pro danou servisu dělat napříč celou aplikací – tedy už v kontejneru přes proxy, nikoliv až v presenteru.
Podstata je ovšem v tom, že většinou si umím presentery navrhnout tak, že do nich budu injectovat jen to, co v nich opravdu potřebuju a využiju, ne to, co by se mohlo někdy hodit – takže ty drahé servisy většinou stejně potřebuju instancovat. A v těch okrajových případech, kdy tomu tak být nemusí, viz předchozí odstavec.
„ale zase když první konstuktor má nějaké závislosti a ty závislosti mají další, tak to může narůst.“
Opět jen důvod pro to, že pokud někde rozhodování o lazy-loadingu dává smysl, tak na úrovni kontejneru, ne na úrovni presenteru.
Daniel Milde #45
+1 pro normální Proxy místo Accessoru. Proč? Protože Demeterův zákon („don't talk to strangers“).
Jinak celý lazy-loading závislostí v presenterech také chápu jako anti-pattern, kdy se zodpovědnost přenáší na někoho jiného, než kde by se měla opravdu řešit. Lazy-loading připojení k databázi by měla řešit nějáka DB/ORM vrstva, rozhodně ne presenter. Presenter má mít zodpovědnost sestavit odpověď, něco udělat s daty od uživatele apod. Nelíbí se mi, že by presenter měl být nějaký god object, který bude znát vnitřní implementaci všech servis, se kterými pracuje.
Jiří Landsman #46
#41 Filipe Procházko (@HosipLan), Moc nechápu. v Nette je nějaké generování tříd? ale to s tématem nesouvisí :)
Patrik Votoček #47
#33 Honzo Marku, Nejsem si jistý jestli jsem tvůj komentář pochopil dobře ale…
Jde právě o to jestli si do authenticatoru nám spojení s DB (nebo jiným úložištěm), nebo nějaké připojovátko. Právě ono připojovátko už je lazy-loading.
Pokud tam budu cpát spojení musí být vytovřené (vytvoření spojení s DB je drahá operace na to abych ho pak nevyužil).
Co se týká připojovátka tak jednou z možností je cpát tam factory. Zde ale nastává problém který David popisuje v tomhle článku (pokud bude připojení využívat více částí (služeb) budu jich mít zbytečně inicializovano více. Proto onen accessor. Další z možností je proxy u té je ale problém s final metodama původního objektu.
Jan Tichý #48
#47 Patriku Votočku, „Další z možností je proxy u té je ale problém s final metodama původního objektu.“
<dogma>
Final je zlo. Vždy a všude.</dogma>
Nicméně – jak konkrétně Ti u proxy třídy, která je implementací stejného interface, jako ta původní třída, vadí final u té původní třídy?
Filip Procházka (@HosipLan) #49
#46 Jiří Landsmane, Skro ano, Nette\Utils\PhpGenerator
#43 Tharosi, PhpStorm, ale to je diskuze na jiné téma, nechceš se stavit na jabber MUC nette@conf.netlab.cz ?
#47 Patriku Votočku, A další možností je rozdrobit presentery, viz #35 Filip Procházka (@HosipLan) a #42 Filip Procházka (@HosipLan)
Jakub Vrána #50
Za slabinu považuji, že implementace AuthenticatorAccessor nijak nepřiměji, aby fakt vracely Authenticator. Totéž ale platí i o AuthenticatorFactory.
Patrik Votoček #51
#48 Jane Tichý, o tom zda je final zlo nebo ne se nepřu (souhlasím že zlo je) nicméně to jestli je to zlo nebo ne nic nemění na tom že je to problém.
Jako programátor jsem prošel určitýmy stádii vývoje (bastlíř – je mě to jedno, akademická čistota, kompromis). Aktuálně se nacházím v etapě „kompromis“ kdy nehledím vždy a 100% na „akademickou čistotu“ ale jdu cestou kompromisu vycházející z praktického využití.
Tím chci říc že né na vše mám a né vše co dělám má interface. Tj. blbě by se roubovala proxy.
#49 Filipe Procházko (@HosipLan), pokud si můžu zvolit cestu lazy-loadingu a vs. 4 (BaseFooPresenter, HeadFooPresenter, PostFooPresenter, GetFooPresenter) /5 (BaseFooPresenter, CreateFooPresenter, ReadFooPresenter, UpdateFooPresenter, DeleteFooPresenter) tříd. Tak jednoznačně volím cestu lazy-loadingu.
Čas je drahý a upsat k smrti se fakt nehodlám. Ano část psaní kódu se dá nahradit generátory a snippetama kódu (taky to z větší části dělám) ale pořád je to více psaní.
Honza Marek #52
#47 Patriku Votočku, připojovátko k databázi obvykle bývá beztak vytvořené vždy a všude, takže u authenticatoru to cenu nezvýší
Patrik Votoček #53
Jen dodám že se nekloním ani na stranu Proxy ani na stranu Accessoru, protože sám jsem v tomhle v rozepři. Jen se snažím koukat z obou stran.
A „přílišná“ dekompozice mě subjektivně (aktuálně) připadá jako nejhorší varianta.
#50 Jakube Vráno, Dobrý postřeh na to jsem zapoměl!
#51 Patriku Votočku, O tom já se ale nepřu jen říkám že to připojovátko samo o sobě je vpodstatě lazy-loading (jen se z presenteru přesunul jinam). To samé platí i u #45 Daniel Milde.
Daniel Milde #54
#53 Patriku Votočku, Ano, připojovátko k databázi (Dibi, Doctrine, NotOrm) by mělo řešit lazy-loading. Je to jeho zodpovědnost.
Michal Illich #55
Souhlasím s Honzou. Presenter nemá co řešit nějaké Accessory. Ten má dostat pomocí DI přímo to co implementuje potřebné rozhraní.
A pokud existuje (např. výkonový) důvod pro lazy-loading, má být řešený jinde – např. pomocí proxy. Na úrovni konfigurace kontejneru pak řeknu, co se má do toho nebohého Presenteru posílat.
Honza Marek #56
A vůbec nechápu, proč se tady všude řeší nějaká proxy. Pokud bych výjimečně (jednou za aplikaci) potřeboval lazy loading, tak bych si třeba udělal jednoúčelový accessor a pojmenoval ho factory (taková factory s cachovanou instancí).
Psát proxy kvůli lazy inicializaci je podle mě dost práce a s leckdy pochybným výsledkem. Takže proxy bych případně vytvářel z úplně jiných důvodů. Např. pokud nějaká metadata na vývojářském stroji přímo parsuju z anotací tříd a na production bude nějaká cache. Ve třídách, kde metadata používám, nechci vědět s kterou variantou pracuju. Cachovaná varianta bude sdílet stejný interface a bude obsahovat instanci původního načítátka metadat.
#50 Jakube Vráno, Souhlasím, to mě taky hned zarazilo. U AuthenticatorFactory je možné alespoň napsat dokumentační komentář, který pak vychovaní programátoři respektují (když to neumí zařídit jazyk).
Hrach #57
Pořád se tu baví o nějakém ideálním případě. Pánové, Tichý & spol., čekám, že tu utopii naprogramujete a odprezentujete, v lepším případě uděláte open source jako nette. Nebo forkněte a pošlete pull. V opačném případě přesťaňte plkat. Psát rádoby chytré komentáře umí každý.
Takže, shrnuto: čekám na blogpost, který publikuje rozhraní presenteru, který by neměl tolik závislosti, šlo by v něm dělat to stejné jako ve výše uvedeném příkladu, a přitom by nebylo třeba lazy loadingu a authenticator by se neinstancoval každý request.
David Grudl #58
Líbí se mi, jak vymýšlíte nejneuvěřitelnější řešení (rozřezání presenterů na tolik duplicit, kolik akcí mají jeho komponenty, POST presentery, psaní interface na úplně vše, aby to šlo proxovat), jen aby se proboha nepoužil lazy-loading s „továrničkou“, protože přece nebudeme nováčky učit složitosti.
Vraťte se na zem 🙂
#56 Honzo Marku, #57 Hrach Díky, konečně rozumná řeč.
#50 Jakube Vráno, beru to tak, že je to otázka příští verze PHP. Na návratovou hodnotu se proto běžně spoléhá a řeší se anotací (jako v případě accessorů). Nicméně obejít se dá i typehint, utlumením E_RECOVERABLE_ERROR.
David Grudl #59
#55 Michale Illichu, Michale a co když presenter chce accessor? A dokážeš napsat proxy nad PDO?
David Grudl #60
#37 Jane Tichý, dogmatismus není snaha o maximální jednoduchost a čitelnost kódu – tím je spíš pragmatismus. Jako třeba #56 Honza Marek: lazy loading je potřeba velmi výjimečně, tak si na něj udělám jednoúčelový accessor/factory. Dogmatismus je čtvrcení presenterů.
Vrátím se zapadlé myšlence: skutečně by měl presenter, který autentikátor využije v jednom případě z tisíce, jej uvádět v konstruktoru jako povinný parameter, nebo by realitě víc odpovídala jiná forma?
Daniel Milde #61
#57 Hrachu, Honzo, asi Tě to překvapí, ale my tu utopii (=dobrý návrh) každý den používáme a snažíme se ji průběžně prezentovat (na školení, na zdrojáku, v diskuzích) a prosazovat i do Nette.
Otázku refactoringu presenterů bych sem nezatahoval. Na tohle téma už padlo myslím dostatek názorů a dokud se to nepřepíše, nemá smysl o tom mluvit.
David Grudl #62
#61 Danieli Milde, Dane, nechci být jízlivý, ale je to pár týdnů, kdy jsi mi ukazoval na Facebooku čisté DI řešení lazy-loadingu autentikátoru. A bylo konstruováno tak, že Honza teď stojí proti tobě na úplně opačné straně.
Tharos #63
#58 Davide Grudle,
„rozřezání presenterů na tolik duplicit, kolik akcí mají jeho komponenty“
Jestli je to reakce na tu dekompozici, nemyslíš, že třeba tomuhle by neslušelo rozdělení na DashboardModule, který by obsahoval ReadPresenter (nebo DefaultPresenter, to není podstatné), CreatePresenter, UpdatePresenter a DeletePresenter? A třeba zároveň přesunout i formuláře do vlastních tříd?
Jakmile složitost trochu naroste (více vstupních polí, možnost nahrávat i obrázky…), vepsáno v jednom presenteru to bude mít 800 řádků a třeba pro mě osobně to asi bude i dost nepřehledné. Ale možná je to věc vkusu…
Každopádně kde je ta duplicita? Jestli tedy ta poznámka byla mířena na tu dekompozici.
David Grudl #64
#63 Tharosi, O tom není a nebyla řeč. Bavíme se pod článkem, kde je presenter s jedním view a jedním přihlašovacím formulářem. A držme se prosím tématu.
Tomáš Fejfar #65
#43 Tharosi, Eclipse to má taky.
Ctrl + Shift + T
→ napsatZFEMC
→ najdeZend_Form_Element_MultiCheckbox
. A neboCtrl + Shift + R
→ napsat*/art*/in
→ najde/application/views/scripts/articles/index.phtml
Jirka Helmich #66
#6 Jane Tichý, Ty problémy, které tu řešíte (a celé jsem to teda nezvládl dočíst), by asi vyřešily traity. Udělám si malé DI kontejnery a budu je hojně reusovat.
Daniel Milde #67
#62 Davide Grudle, Honza Hrach? Asi vůbec nechápu, co jsi tím chtěl říct.
Davide, Tvoje články a diskuze pod nimi mají velmi často jeden zásadní problém. V článku nastíníš jeden problém, pořádně ho přeženeš, nastavíš hranice problematiky tak, aby Tvoje myšlenka dávala smysl a pak za ní bojuješ.
Teď jsi například vykonstruoval jeden drobný problém s autentikátorem a ve výsledku má čtenář z článku dojem, že by měl všechny závislosti do presenteru předávat pomocí nějakého accessoru. Osobně jsem tenhle problém nikdy neřešil a řešit ho ani nebudu. V aplikaci jsou zpravidla daleko větší bottlenecky než vytváření jedné konexe navíc.
Osobně je mi to celkem šumák, accessory v Nette používat nebudu, ale vadí mi, že Tvoje články čte spousta lidí, kteří tak jasno nemají a teď začne polovina z nich používat accessory, protože je to přece hrozně kůl. A proč je to špatně? Protože si zvyknou předávat něco jiného než přímé závislosti a začnou brát presentery jako něco spešl.
Jakub Tesárek #68
#67 Danieli Milde, Před hodinou jsem dopsal jeden email s prakticky stejným obsahem 🙂
Jakub Tesárek #69
#66 Jirko Helmichu, Traity nebrat.
Jirka Helmich #70
#69 Jakube Tesárku, Dogma? :) Ty PHPkové moc neznám, jsem poslední dobou zkažený Javou a Scalou, takže se nechám poučit.
David Grudl #71
#67 Danieli Milde, článek nafoukla především zcela nepochopitelná dogmatická diskuse pod ním. Honza Tichý už měl vymyšlený první komentář po přečtení titulku. Za obsahem článku si jednoznačně stojím. Jako protiargumenty tu zaznívají jen prázdné teoretické nerealizovatelné konstrukce. A pokud si z něj někdo odnese něco, co v něm nebylo, není to můj problém. Vskutku by mě zajímalo, co bys na článku napsal jinak, které formulace něco nafukují.
Jiří Landsman #72
Tak co třeba tahle? https://pastebin.com/iET8S1uq nebo tam mam něco špatně?
Hrach #73
#61 Danieli Milde, Zřejmě to nejde, jinak by tu nepadali pořád věty typu „Presenter má moc povinností“. A že jich tu je. Pokud to jde, čekám na článek – nemusí to být hned pull request. To, že se tomu v mediu tak z 50 % blížíte je možný hezky, ale prakticky na____.
Honza Marek #74
#71 Davide Grudle, V článku mi dost chybí nějaké upozornění pro začátečníky, že accessor by měl být použit jen v případě, kdy instanciace objektu služby je nadprůměrně náročná. Působí to dojmem, že každé vyrobení služby je drahé a že accessor je univerzální řešení.
David Grudl #75
#72 Jiří Landsmane, tomuto řešení se říká proxy. Ve srovnání s „továrničkou“ má některé výhody a některé nevýhody, viz #21 David Grudl. Podstatnou výhodou je, že ji lze nasadit zcela transparentně, praktickou nevýhodou je, že proxy lze zkonstruovat pouze při použití rozhraní.
Rozumný člověk se rozhodne, které řešení zvolí s přihlédnutím k okolnostem, dogmatik má jasno hned a volí podle momentálního vyznání 😉
Jiří Landsman #76
Já vím, že to je proxy. Hodil jsem to sem jen proto aby tady nezaznivaly jen prázdné teoretické nerealizovatelné konstrukce. Nutnost údržby moc neberu. Pokud se mění rozhraní tak stejně musím jít a měnit kód tak změním kod v jednom souboru navic no. Hlavní je, že si nepřidávám do presenteru komplexitu která tam nepatří. Pro třídu která neimplementuje rozhraní by se určitě taky našlo nějaké řešení například v podobě adapteru.
Jan Tichý #77
#60 Davide Grudle, Rozcházíme se v axiomech. Mně hodně malých presenterů vychází z mnoha důvodů (minimální množství kódu prováděného při každém requestu; instancování jen těch služeb, které opravdu potřebuji, bez nutnosti krkolomných berliček; žádné křížení nesouvisejících actions/renders a signálů; přímočarost a srozumitelnost; single responsibility a tak dále) jako velice rozumné praktické řešení. Pro Tebe to jsou prázdné teoretické nerealizovatelné konstrukce a dogmatismus, které tak šmahem zahazuješ. Proti rozdílným axiomům neumím argumentovat.
Michal Illich #78
#59 Davide Grudle, „Michale a co když presenter chce accessor?“
A proč by ho měl chtít? On může imho nanejvýš chtít informaci o přihlášeném uživateli a tu dostane z té injectované třídy. A může mu být jedno, jestli je to jednoduchá třída nebo proxy. Může mu být i jedno, jak ta třída vznikla – jestli přes prosté new nebo zavoláním factory (a v ní new), zda ručně nebo z DIC, atd.
„A dokážeš napsat proxy nad PDO?“
Osobně mě pro lazy loading PDO neuráží řešení a la https://web.archive.org/…-in-php.html – striktně řečeno to není proxy, ale nevidím důvod, proč bych ty třídy nemohl nastrukturovat tak, aby to proxy skutečně bylo.
To že důvod nevidím může samozřejmě znamenat, že tomu nerozumím – já vyvíjím v C a do PHP jen kibicuju :) Naštěstí ve Wikidi je hodně lidí, kteří návrhu webových aplikací rozumí víc než já, tak moje kibicování neškodí :)
David Grudl #79
#77 Jane Tichý, ještě jednou opakuju, v článku se píše o presenteru s jedním view a jedním formulářem. Ty mi neustále podsouváš něco jiného a přestávám mít pocit, že to neustálé uhýbání od tématu je jen nedorozumění.
Michal Illich #80
#59 Davide Grudle, „A dokážeš napsat proxy nad PDO?“ – A mimochodem, to proxy nad PDO je vyřešené už od roku 1650!! http://www.clim-past.net/…-1-2010.html ptáš se jako kdybys neuměl googlovat, vždyť to bylo hned na prvním místě na dotaz proxy pdo :))
Jan Tichý #81
#79 Davide Grudle, Ježiš, ale vždyť to je podstata celé věci! Celé je to od začátku o tom, že „jeden presenter s jedním view a jedním formulářem“ je chybná premisa, která vede k nutnosti vymýšlet berličky typu lazy loadingu.
Ty sis stanovil nějakou premisu a snažíš se na ni vymyslet řešení. Já říkám, že ta premisa sama o sobě není dobře, a tudíž ani žádná řešení nad ní postavená nemohou být dobře. Jedna nesystémovost plodí vždy jen další nesystémovosti. A že správným řešením je podle mého názoru změnit počáteční premisu.
Daniel Milde #82
#71 Davide Grudle, Já osobně bych tenhle článek radši vůbec nenapsal :) Prostě proto, že si moc dobře uvědomuji, že takovéhle speciálnosti lidem jen zamotají hlavu. Nette komunita potřebuje naučit se čisté DI, lazy-loading bych radši vůbec nevytahoval.
Co se týče nafukování, tak bych trochu zapochyboval o tom, že si někdo 1000 krát zobrazí přihlašovací presenter a až 1001. request bude přihlášení :)
Docela by mě zajímalo, co vidíš pod termínem „prázdné teoretické nerealizovatelné konstrukce“. Pokud vím, tak většina lidí, kteří tady prosazují čistotu kódu, takový kód v praxi opravdu píší.
#73 Hrachu, To ale trochu mícháme jabka s hruškama. Ten refactoring (na který se chystá Vašek) se týká Nette\UI\Presenter, o tom tu dnes nepadlo ani slovo. Tady se bavíme obecně o presenterech a tom, že pokud uděláš dostatečně malý presenter s jasnou zodpovědností, nepotřebuješ lazy-loading.
Václav Novotný #83
#79 Davide Grudle, V tom případě jsi si Davide IMHO vybral dost nešikovný příklad (což se bohužel stalo i v https://phpfashion.com/…cy-injection), který některé programátory nadzvedl, protože v něm vidí rizika a který začínající programátory dost možná postrčí špatným směrem (samozřejmě to může být subjektivní), protože ta rizika zatím ještě nevidí.
Napsal to tu už Dan: „Davide, Tvoje články a diskuze pod nimi mají velmi často jeden zásadní problém. V článku nastíníš jeden problém, pořádně ho přeženeš, nastavíš hranice problematiky tak, aby Tvoje myšlenka dávala smysl a pak za ní bojuješ.“
Je to škoda, protože máš dlouhodobě velký vliv na české PHP a tvé články jsou přínosné. Tohle mi ale přijde pod tvůj standard.
David Grudl #84
#78 Michale Illichu, Proč by ho měl chtít? Protože všechny závislosti nejsou rovnocenné. Pokud se shodneme na tom, že existují závislosti povinné a závislosti volitelné, pokračujme (pokud ne, nepokračujme ;)
Povinné a volitelné se odlišují formou předání (konstruktor vs. jiná inicializační metoda), nebo tím, že mají v hlavičce funkce uvedeno
= null
. Podstatné je, že tyto rozdíly jsou zapsány přímo v API třídy, tedy o nich ví.Problém volitelných závislostí je v tom, že je můžeme předat zbytečně, nebo naopak nepředat, když jsou potřeba. Někdy ani dopředu nelze zjistit, jestli závislost bude potřeba (například proto, že objekt si nějakou informaci možná drží v cache apod.)
Věc se pak řeší dvěma možnými způsoby: buď se použije callback, tedy mechanismus, kdy si objekt o závislost řekne sám (princip Hollywood), nebo se mu předá proxy. Obojí má své pro a proti.
Chci říci jediné: je-li korektní, že třída rozlišuje mezi povinnými a nepovinnými závislostmi, pak je korektní, že si nepovinnou závislost umí vyžádat callbackem.
Opačné tvrzení, že třída nemůže chtít accessor, protože to nepatří do její implementace, je pak ekvivalentem tvrzení, že třída nemůže vyjádřit nepovinnou závislost, a mají se místo toho předávat nějaké Null objekty (tj. opět forma proxy).
(což je sice taky zajímavé téma k diskusi, ale asi by ses divil, kdybych vám poplival kód, protože v něm používáte nepovinné proměnné).
David Grudl #85
#81 Jane Tichý,
vs o čtvrt hodiny později:
Už to nehul 🙂
David Grudl #86
#82 Danieli Milde, prosím tě, můžeš zveřejnit kolik máte měsíčně page views na https://www.medio.cz/ a kolik máte odeslání toho formuláře vespod? Nebo ať nevytahujeme absolutní čísla, stačí mi poměr. Pak si budeme dál vykládat o nafukování.
#83 Václave Novotný, nadzvedlo to pouze dogmatiky, kteří za celou dobu nedokáží odargumentovat své postoje, tudíž jsem v klidu.
Jan Tichý #87
#85 Davide Grudle, Ale no tak, fakt to nechápeš, nebo to záměrně zahazuješ do kouta?
Mezi těma dvěma citacema není žádný rozpor. Presenter tak, jak ho máš Ty, je moc „velký“, protože příprava vykreslení toho formuláře je něco úplně jiného než zpracování formuláře.
Takže to zkusím napsat ještě jednou a srozumitelně:
Chybná premisa celého Tvého článku je, že pracuješ s jedním SignPresenter. Tak se do sebe míchají dvě naprosto různé odpovědnosti a dvě naprosto různé potřeby závislostí. Z toho pak jako důsledek vyplývají všechny ty potřeby krkolomných lazy loadingů apod.
Správné řešení je mít SignPresenter pro vykreslování login formuláře a věcí s ním souvisejících. A pak vedle něj něco jako SignSubmittedPresenter pro zpracování odeslaných credentials. Do prvního samozřejmě žádný autentizátor neinjectuju nikdy, do druhého naopak vždy.
Ale to už se jen opakuji, to už jsem psal dávno výše, viz #39 Jan Tichý…
David Grudl #88
#87 Jane Tichý, ano, rozřezání presenterů na tolik duplicit, kolik akcí mají jeho komponenty v součtu, viz #58 David Grudl.
Určitě ti nebude vadit vystavit večer na Github ukázku z vašeho kódu realizující tento scénář. Je potřeba začátečníky vzdělávat na správných příkladech. Obzvlášť, když se na ně sypou takové zpátečnické názory na tomto blogu 🙂
Ugo #89
#87 Jane Tichý, Správné řešení je
tiše se zájmem čtu postupně celé vlákno, ale i jako noob mezi vámi si dovolím napsat, že tímto jsi to zabil
btw. sem rád že Jakub s Davidem zas píší, konečně je co číst, jen tak dál.
Jan Tichý #90
#88 Davide Grudle, Davide, můžeš prosím upřesnit, co konkrétně myslíš tím slovem „duplicity“? Co se tam kde zbytečně opakuje?
#89 Ugo, Výše jsem ve stejném kontextu psal „správným řešením je podle mého názoru“, tak jsem tak nějak myslel, že to nemusím znovu explicitně dlouze opakovat a že je to tak nějak jasné.
Adam Štipák #91
Nechcem sa do toho velmi montovat 🙂.
Ale dávam za pravdu #89 Ugo. Ono je dobré asi myslet teoreticky ale zas to az tak neprehanat. Pride mi to nieco ako „Ja pouzivam Ford“ a ty mi budes tvrdit „Mal by si pouzivat BMW, oni to robia spravne!“. To potom zahodme vsetku literaturu o navrhovych vzoroch a pouzivajme DI vsade lebo je to nove je to cool a neviem co este.
A som bohovo rad, ze nemusim (som lenivy a nechce sa mi) pisat X tried pre moj formular s X tlacitkami a neviem cim inym.
Boh nas chran aby sme touto cestou nedosli k Zendu z buducnosti 😉.
David Grudl #92
#90 Jane Tichý, vystav kód vaší homepage a dodejte k tomu s #82 Daniel Milde poměr PV/form-submit. Pro programátora je pohled na správné řešení lepší, než tisíce zbytečných slov.
Borek Bernard #93
#88 Davide Grudle, Příklad by se hodil, je tu příliš teoretizování. Mně připadá, že to, co říká Honza, dává perfektní smysl, ale Nette Presentery neznám a ty třeba zmiňuješ jakési duplicity, tak by bylo dobré vidět, jestli tam skutečně budou nebo ne. Taky by bylo dobré vidět celou aplikaci včetně toho, jak vypadá DI kontejner – na tom docela záleží. Třeba Unity pro .NET to řeší takhle: #stary-odkaz-#stary-odkaz-http://stackoverflow.com/questions/6177347/asp-net-mvc-unity-2–0-lazy-loading-dependency-properties
Daniel Milde #94
#84 Davide Grudle, Nepovinná závislost? Co to je? :) Není to tak trochu protimluv? Viděl jsem to jedinkrát v životě a to u nějakého zblastleného formuláře.
Daniel Milde #95
#92 Davide Grudle, To ale přece není SignPresenter, ale něco jako HomePresenter. To je, co se týče poměru odeslání formuláře ku zobrazení, docela rozdíl ;)
David Grudl #96
#94 Danieli Milde, https://zdrojak.cz/…-zavislosti/?…
#95 Danieli Milde, chápu, došly argumenty. Toliko k nafukování.
Daniel Milde #97
#96 Davide Grudle, Sorry, ale za Honzu mluvit nemůžu.
U LoginPresenteru máme tipuju 95% přihlášení na počet zobrazení. U HomePresenteru je to samozřejmě něco jako 0.1% odeslání kontaktního formuláře na počet zobrazení.
Takže opravdu nechápu, k čemu by Ti kód našeho HomePresenteru byl. Navíc vzhledem k tomu, že se tam nikde nepracuje s nějakým authenticatorem nebo databází.
Patrik Votoček #98
#97 Danieli Milde, tak si představ že místo toho kontaktního formuáře je právě ten SingIn form (spousta webů zobrazuje přihlašovací form na každé stránce). A ukaž řešení (kód).
Michal Illich #99
#84 Davide Grudle, Povinné vs nepovinné – souhlasím, smím tedy pokračovat :)
Rozumím, co chceš říct i věřím, že existují případy, kdy se callback/accessor hodí a je nejlepším řešením.
Jen si akorát myslím, že takový případ je velmi vzácný.
Vykonstruoval jsi ho tím, že máš presenter, který tepvr při runtime zjistí, jestli vlastně nějaký autentifikátor potřebuje. Kdybys měl ty presentery dva jak navrhuje Honza (jeden vykresluje formulář, druhý ho zpracovává), tak se do té situace nedostaneš.
Neboli když svůj teoretický případ přepíšeš čistěji (ve smyslu důslednější aplikace single responsibility), tak ti zmizne větší část důvodu použít accessor a ukáže se, že prosté DI (s volitenou proxy nebo lazy loadingem schovaným uvnitř třídy) je vhodnější.
David Grudl #100
#97 Danieli Milde, tak si představ, že to je HomePresenter s přihlašovacím formulářem. A ukaž kód HomePresenteru, všichni jsou zvědaví na to, jak se tam zpracování formuláře řeší.
David Grudl #101
#99 Michale Illichu, Michale, přepsat formulář do dvou presenterů je taky možné řešení. Z těch možných ale zdaleka nejkomplikovanější. Navíc, když jde o vzácný případ (souhlas). Pomalu jako přestěhovat se do jiného bytu proto, že se mi v zámku zalomil klíč.
Rozuměj, na jedné straně píšeš, že použití AuthenticatorAccessor je neomluvitelným zásahem do kódu presenteru, na druhou stranu nabízíš řešení, které ho rozbije na prvočinitele. Ale budiž.
Mohl bys prosím rozvést to „s voliteným lazy loadingem schovaným uvnitř třídy je vhodnější“? Zajímal by mě ten lazy loading. Jak přesně to myslíš?
Honza Marek #102
#100 Davide Grudle, Jak asi. Předá se tam celý authenticator, protože je to stejně drahé jako tam předat nějaký accessor :)
Valerián Kadrnos #103
Gratuluji autorovi článku ke stému diskusnímu příspěvku.
Daniel Milde #104
#100 Davide Grudle, Ve Front\HomePresenteru přece uživatele autentizovat nechci, tak proč bych tam něco cpal. Bude tam jen ten formulář. Authenticator bude třeba v něčem jako Admin\BasePresenter a ověření v Admin\LoginPresenter.
Pokusím se sepsat nějaký ucelený příklad.
Jan Kodera #105
#104 Danieli Milde, Jak zajišťujete dodržovaní naming konvencí těch souborů? Ve vašem případě jich musíte psát docela dost, takže všichni v týmu by měli dodržovat stejnou konveci, ne?
Daniel Milde #106
#105 Jane Kodero, Naming konvenci souborů máme, ale nijak automatizovaně ji nekontrolujeme.
Michal Illich #107
#101 Davide Grudle, „Zajímal by mě ten lazy loading. Jak přesně to myslíš?“ – myslel jsem tenhle už výše citovaný článek: https://web.archive.org/…-in-php.html – tedy pozdržení založení konekce až na dobu, kdy je skutečně potřeba (na příkladu PDO).
V tomhle článku se tomu říká lazy loading, ale když nad tím víc přemýšlím, tak mi ten název přijde matoucí – nejde o lazy loading, ale spíš takový lazy connecting. Obecně mi přijde ta myšlenka aplikovatelná na problém, který řešíš: bojíš se, že něco (v tvém případě autentifikátor) může být výkonově náročné. Přitom víš, že ve většině případů to není potřeba. Tohle je jedním z možných řešení (netvrdím, že nejsprávnější): třídu předáš, ale v konstruktoru se skoro nic neděje, skutečná práce nastane až tehdy, kdy je skutečně potřeba.
David Grudl #108
#107 Michale Illichu, tento přístup používá třeba dibi, je to šikovné. A využitelné ve chvíli, kdy existující kód už přímo pracuje s tímto chytrým objektem namísto PDO. Jak ale řešit situaci, kdy existující kód (například třetí strany) pracuje přímo s PDO, které lazy connecting neumí?
Borek Bernard #109
#107 Michale Illichu, Řeší se tady něco, co se jmenuje Lazy Initialization. Nadpis článku je matoucí.
jasir #110
Jen z rozjetého vlaku – myslím si, že Davidovo řešení je velice zajímavé, a to zejména v okamžiku, pokud mi Nette\DI container bude sám (podle hintů nebo anotací) generovat accessory. Kdyby bylo možné opravdu bezproblémově (PDO, final, …) a (beze stráty výkonu dané service, ala _call přístup) generovat proxy objekty obalující lazy-chování, bylo by to zřejmě lepší, ale v současné chvíli (bez změny v jazyce) je to asi neiplementovatelné a pak je toto velice pěkný způsob možnosti lazy předávání závislostí.
Je to vlastně takový service locator pro jednu service 🙂, kombinující výhody service locatoru a DI.
Výhrady typu „programátor se to chudák musí učit“, tak ať radši píše tunu kódu" při použití frameworku neberu, stejně tak se musí učit zbytek a tohle se zdá dostatečně průhledné.
David Grudl #111
#109 Borku Bernarde, obávám se, že nikdo neví, co se tady řeší. Mám to za zlé Honzovi, který místo přečtení článku žhavě vystartoval s oponenturou proti něčemu, co jsem neřekl (že lazy-loading je částo známkou špatného návrhu, s čímž rozhodně souhlasím, ale je OT) a ačkoliv druhým komentářem to zmírnil, dokázal, že článek nečetl a celou diskusi *** :-/
Honza Marek #112
#111 Davide Grudle,
<provokace>
to zní jako přiznání, že jsi vyrobil udělátko usnadňující výrobu špatně navržených aplikací :D</provokace>
David Grudl #113
#112 Honzo Marku, ano, to jsem udělal už milionkrát. Třeba takové statické
dibi::
. Ty určitě podobné případy najdeš u sebe taky.Borek Bernard #114
#111 Davide Grudle, Mně ta diskuze připadá zajímavá. Kód, který v článku vznikl, se mi, stejně jako Honzovi, Danovi a dalším, taky moc nelíbí, ačkoliv přesně řeší problém, který byl zadáním. Jelikož Nette neznám, tak se těším, až někdo z kluků vystaví kód nepoužívající accessor, a bylo by škoda o tohle finále přijít :)
David Grudl #115
#114 Borku Bernarde, jenže tahle diskuse buď zpochybňuje zadání (můj SignPresenter se tolikrát nezobrazí, my tomu říkáme HomePresenter, moje babička je starší než tvoje, …), nebo řeší něco jiného, nebo jen tak plácá (žádného kódu bez accessoru se nedočkáš, jen silný slova).
Místo diskuse na téma článku, proč je pro řešení jasně zadaného problému vhodnější accessor než továrnička, a jsem přesvědčen, že jsem to podpořil dobrou argumentací, se tady řeší to, že někdo lazy-loading moc nepotřebuje a že existují situace, kde se nehodí. No jasně! Já ho taky potřebuji výjimečně. Ale kolik lidí tu prokázalo průměrnou inteligenci a psalo k tématu?
Borek Bernard #116
#115 Davide Grudle, Je pochvalou pro tebe, že jsi tak dobře vyargumentoval továrničku vs. accessor, že o tom nikdo diskutovat nepotřeboval :) Daleko víc evidentně zaujalo téma, jestli by v Nette měl být takový kód vůbec kdy potřeba, a zas tak velký OT to není.
David Grudl #117
#116 Borku Bernarde, jenže diskuse nic nikam neposunula, protože jediným argumentem proti lazy loadingu bylo prohlášení, že je to antipattern.
Jakub Tesárek #118
#115 Davide Grudle, „Ale kolik lidí tu prokázalo průměrnou inteligenci a psalo k tématu?“
Když se podíváš, tak když jsem argumentoval k tématu, tedy že existují lepší způsoby jak tento problém vyřešit a že Accessor není vhodný, tak jsi začal s osobními urážkami. Toliko k tvé otázce.
Borek Bernard #119
Jé, ona ta diskuze ještě existuje! Díky za zachování, třeba kluci z Media pošlou jejich řešení.
Augi #120
Díky za původní článek a zajímavou diskuzi.
IMHO David v článku velmi dobře popsal „jak“, zatímco většina lidí v diskuzi má argumenty proti „proč“, což ten článek ale vůbec neřešil.
Na původním článku bych vyzdvihl především to, že David řešil rozdíl mezi „factory“ a „accessor“. Někomu to může připadat jako slovíčkaření, ale existuje několik návrhových vzorů, které mají velmi podobnou (nebo i stejnou) strukturu/implementaci a ten správný název v konkrétní situaci pak určuje účel, proč danou věc děláme, takže pojmenovat věci správně je hodně důležité (a těžké).
Tomáš Holcman #121
v reakci na „tweet“:„https://twitter.com/#!/geekovo/status/179941232330555392“
Accessor = ServiceLocator nebo se pletu?
Nejvíc se mi nelíbí, že by presenter(uživatel služby) měl vědět něco o tom, že nemá přímo službu, že o tu si musí ještě požádat.
Přílišná decompozice je taky hloupost. Vytváření services by mělo být VELICE levnou záležitostí (cca jako Accessor jen přiřadit závislosti do atributů). Pak by nevadilo, že je service potřeba při jednom z XYZ requestů. Pokud nemůžeme zabránit náročným operacím při vytváření services (knihovny třetí strany), tak by se to mělo ošetřit pokud možno co „nejblíže“ problému a ne si ten problém tahat přes několik objektů až do presenteru. Nejlepší je podle mě proxy nad nevhodně udělanou třídou třetí strany.
David Grudl #122
#121 Tomáši Holcmane, accessor není service locator. Že uživatel služby ví, že nemá přímo službu, ale něco, co mu ji teprve vrátí, je předmětem zadání a presenteru se to tak líbí a chtěl to tak. Kdyby o tom vědět neměl, použila by se třeba proxy.
paranoiq #123
#121 Tomáši Holcmane, pleteš. zatímco ServiceLocator je černá skříňka, ve které může a nemusí být ledascos, Accessor je způsob jak přistoupit jedné (nebo více) konkrétně definované službě. (jediné co chybí Accessoru v PHP k dokonalosti je jen return type hinting. to zmiňoval nahoře Jakub Vrána. a toho se snad dočkáme v PHP 5.5 :)
debata o Accesoru je v podstatě o dvou výrocích:
proto vyzývám teoretiky, aby zrakapitulovali důkazy pro výrok 1) a následně dokázali, že tyto platí i pro Accessor
já jsem toho názoru, že u Accessoru, jelikož jeho jedinnou zodpovědností je právě získání určité přesně definované služby, nedochází ke skrytí závislosti, ale pouze k jejímu odsunutí (v čase i v kódu), což je ovšem přesně ten důvod, proč Accessor chceme použít! win-win!
pokud se vám zdá, že přesunutím závilosti na Accessor, jehož (záměrně se opakuji) jedinnou zodpovědností je dodat tuto závislost, se závislost „skrývá“, shledávám vaší logiku trochu pokroucenou
to co platí u Accesoru platí stejně tak i u Factory. jediným rozdílem je, že Accessor má závislot prostě sehnat (není řečeno jak), kdežto Factory vyrobit. je snad injektování jakékoliv Factory do objektu v rozporu s principy DI?
Jan Tichý #124
#57 Hrachu, #88 David Grudl #92 David Grudl #114 Borek Bernard „Určitě ti nebude vadit vystavit večer na Github ukázku z vašeho kódu realizující tento scénář.“
Ahoj všem, nejlepší bude konkrétní kód doprovozený i celým článkem. A článek i s konkrétním kódem se pokusím stihnout někdy během příštího týdne. OK?
Daniel Milde #125
#123 paranoiqu, Ad 1: To myslím není potřeba opakovat. Informací je dost a dost.
Ad 2: Použití Factory musí mít nějaké opodstatnění, protože z pohledu DI to opravdu není úplně čisté.
David Grudl #126
#125 Danieli Milde, použití factory není z pohledu DI úplně čisté?
Daniel Milde #127
#126 Davide Grudle, Není, protože pokud bys do třídy předával factory místo závislosti (servisy), tak očividně nepředáváš přímou závislost :) Porušuješ tím Demetera. Proto je třeba mít k použití factory nějaký smyslupný důvod. Mě teď napadají dva:
paranoiq #128
#127 Dan má pravdu v tom, že je porušen Demeterův zákon. jenže aby porušen nebyl, musela by být každá Factory vykázána až na úroveň BožskéhoObjektu, který na počátku čte konfiguraci a skládá z ní aplikaci. a tomu samozřejmě brání někdy technické důvody (ty uvádí) a někdy důvody ryze praktické (přehlednost a udržovatelnost kódu – nerozbíjet presentery na atomátní součásti, optimalizace – nevytvářet služby, které nebudou použity)
Augiho řešení je zajímavé. problém je, že PDO/NetteDatabase žádné rozhraní pro Presenter či komponenty definované nemá a generovat proxy na celou třídu se mi nevím proč nezdá :/
asi by bylo v konkrétním případě NetteDatabaseConnection lepší udělat refaktoring a namísto dědění od PDO použít kompozici (kolikrát už jsem tohle slyšel jinde…). to by umožnilo používat NetteDatabase líně a celý problém by zmizel
David Grudl #129
#127 Danieli Milde, možná už se v tom začínám ztrácet, říkáš, že (zcela obecně) je použití factory nečisté, krom toho, kdy k tomu máš důvod?
To je přece nesmyslná hra slovíček. Nahraď si v té větě „factory“ za cokoliv jiného (třeba dědičnost) a bude to pravda. Ber tedy jako default, že k tomu ten důvod mám. A bavme se o důvodu.
#128 paranoiqu, generovat proxy pro celou třídu se nezdá nejen tobě. Nehledě na to, že v případě PDO to nejde. Řekl bych, že v praxi by to stejně nikdo nedělal a hledal by si zdůvodnění, proč vlastně ta či ona třída může vědět, že nějaký zdroj je cenný, viz komentáře Reného Steina u Augiho.
bene #130
Prvně na odlehčení: Než jsem dočetl k poslednímu komentáři, uběhlo cca 1,5h 😁
Předpokládám, že z jeho pohledu je Presenter ten, kdo vyvolává akce (tam začína požadavek uživatele) a tudíž on se rozhoduje, co potřebuje.
Jestli je to tak správně nebo ne a jestli to lze navrhnout jinak/lépe je akademická otázka a klonil bych se k menším třídám. Nakonec ten kód být někde musí. Ale jak už někdo zminil výše, je to otázkou kompromisu. Ať už jsou důvody finanční/časové nebo je to u daného projektu zbytečné.
Mám ale pocit že zrovna v Nette se rozdělení formuláře na dva Presentery dělá dost nešikovně (kvůli signálům). A nejspíš by se to muselo řešit obezličkou jako ErrorPresenter $form->setAction($this->link(„SignInSubmittedPresenter:“, array(„do“ ⇒ „form-submit“)));
Nicméně se můžu mílit.
A proto bych chtěl poprost Honzu Tichého, aby svůj článek a příklad ukázal právě nad Nette. Díky.
David Grudl #131
#130 bene, jo, to je přesně accessor. Hledáš logiku v komentářích od #55 Michal Illich „Souhlasím s Honzou. Presenter nemá co řešit nějaké Accessor“ a následně #78 Michal Illich „Osobně mě pro lazy loading PDO neuráží řešení a accessor“? 😉
bene #132
#131 Davide Grudle, jj presně tak 🙂
Jinak jsem pochopil, že pro tebe presenter, který se stará o zobrazení formuláře, taktéž zodpovídá za jeho zpracování? Proto jej nechceš dělit na dva (což má logiku). A tudíž je vlastně presenter komponenta, která má na starosti nějaké spolu-související požadavky. Pokud se mýlím, prosím oprav mě.
Ale pro zajímavost, umí Nette to rozdělení nějak šikovně vyřešit? I kdybych nemusel řešit problém se signálem, stejně musím řešit validaci, která se odehrává po odeslání formuláře. Tudíž na jiném presenteru po chybné validaci bych musel redirectovat na původní a nějak v parametrech poslat hodnoty, které uživatel již vyplnil. Navíc při validaci ještě nepotřebuji IAuthentizator. Celé se to celkem komplikuje a proto sloučení v jednom presenteru je na tomto místě asi nejlepší řešení.
Co se týče lazy loadingu, tak poměrně pěkná a přínosná diskuze je na augiho webu https://augi.cz/…azy-loading/ kde se dle mě vyřešil základní problém, ve kterém by „tvůj“ accessor postrádal smysl. Lépeřečeno ten accessor je nezbytný pouze v případě, kdy jsou splněny následující dvě podmínky:
David Grudl #133
#132 bene, presenter v Nette se stará o inicializaci formuláře a říká, jak má být zpracován. Běžně tak obsahuje právě dvě metody: createComponentForm() vytvářející instanci formuláře a formSubmitted() zpracovávající formulářem získaná data.
Zobrazení má na starosti šablona.
Neumím si proto představit, jak bych presenter rozdělil do dvou, jelikož ten druhý by musel stejně mít obě tyto metody. Dle mého v rozdělení logiku nevidí ani ti, co ho v diskusi navrhli a jsem přesvědčen o tom, že ve svých kódech nic takového nedělají.
V diskusi u Augiho padl velmi trefný komentář od Reného Steina. Ačkoliv se ve zdejších komentářích nestále dokola omílá bod 1., tj. že komponenta je drahá a zda to má presenter vědět, článek řeší bod 2. (viz #13 David Grudl), tj. že presenter tento zdroj používá jen někdy. Což pochopitelně ví a adekvátní řešení je předat si factory/accessor, naopak ne zcela vhodné je sestavovat proxy.
Jan Tichý #134
Ahoj, text se mi natáhl do nutností více dílů a přinejmenším tenhle týden to kvůli hromadě jiné práce nestíhám dokončit, takže bude později. Omlouvám se, opravdu nestíhám.
#130 bene, #133 David Grudl „A proto bych chtěl poprost Honzu Tichého, aby svůj článek a příklad ukázal právě nad Nette. Díky.“
Obávám se, že právě nad Nette to určitě neukážu, protože nad současným čistým Nette to dneska nejde.
Od začátku jsem se snažil tomuhle vyhnout, protože místo „pojďme si nejdřív vyjasnit, proč jsou rozdělené presentery obecně lepší, a pak se hned pojďme někde jinde pobavit o tom, co v Nette změnit, aby je takhle rozdělovat šlo i v praxi“ by se to hned obratem zvrtlo v „rozdělené presentery jsou nesmysl a nereálný teoretický konstrukt, protože v Nette nejdou udělat, takže se o nich přece ani nebudeme seriózně bavit“.
Myslete si o mně, že jsem teoretik (ona je to ostatně pravda, dva roky jsem nenaprogramoval ani řádku, to se snad všeobecně ví), ale jsem opravdu přesvědčený o tom, že postup „nejdřív si to teoreticky vyjasněme a pak to uveďme do života“ je výrazně lepší než „něco nabušíme a ono to nějak bude fungovat a lidi se to holt nějak naučí používat“.
Nicméně ono se to tu zvrhlo právě v „ukaž kód, protože teoretické kecy jsou na nic“, což je sice podle mě z výše uvedených důvodů naprosto chybný postup vedoucí ke kácení ve špatném lese, ale bez toho se odsud nevyhrabeme. Což je taky důvod, proč se mi to možná natáhne i do více článků, protože je opravdu nejdřív nutné si v nich vymezit důvody, a pak navrhnout způsob řešení třeba právě v Nette.
OK?
David Grudl #135
#134 Jane Tichý, V tom je jádro celé diskuse: řešení reálné situace vs. upravení okolních podmínek tak, aby byly ideální. Přičemž i tento pohled je důležitý, může přinést zajímavou a užitečnou diskusi, která však neměla být pod tímto článkem jako jeho oponentura.
Na řešení se každopádně těším, zajímá mě, jak se ti to podaří celé udělat bez jediné továrničky.
Parik Votoček #136
#134 Jane Tichý, Má smysl stále jednou týdně kontrolovat tuhle diskusi jestli už náhodou někde není ta reakce?
Jan Tichý #137
https://www.youtube.com/watch?…
Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.