Diskuze ke článku: Inject a DIC továrničky

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Filip Procházka
Moderator | 4668
+
0
-

Prosil bych připomínky ke článku Inject a DIC továrničky.

Potřebujeme hlavně, aby to pochopilo co nejvíce lidí, takže upozorňujte na nejasnosti, nebo chybějící informace. Buďto mi napište sem, nebo to rovnou upravte. Máme chytrou wiki, takže se nebojte do toho sahat, kdyby se mi něco nelíbilo, tak to po vás opravím :)

Editoval HosipLan (22. 11. 2012 19:36)

Ot@s
Backer | 476
+
0
-

Sis naložil, co? :-) Za sebe bych úplně vyhodil kapitolu „jak to nedělat“.

vvoody
Člen | 910
+
0
-

Vynechal by som generované kusy kódu. Netreba tým zaťažovať začiatočníkov. Keep it simple

stekycz
Člen | 152
+
0
-

Osobně bych přidal k příkladu pro formuláře více vysvětlení práce s parametry pro factories. Když na to prvně kouknu, tak vidím, že přidávám %userId% pro klíč create a pak to musím znova specifikovat samostatným klíčem parameters. Chybí mi tam, proč to tak je a jak tyhle parametry fungují.

Plus bych k tomu přidal i nějaké varování (podobné jako pro rozhraní výše v článku), že tyhle parametry neslouží k předávání jiných závislostí. Vidím celkem reálně přístup toho, že udělám chybně něco takového:

factories:
    userForm:
        create: App\CreateOrEditUserForm(%database%, %userId%)
        implement: App\ICreateOrEditUserFormFactory
        parameters: [database, userId]

a pak to chybně použiju:

class UserPresenter extends BasePresenter
{

    /**
     * @persistent
     */
    public $userId = 0;

    /**
     * @var ICreateOrEditUserFormFactory
     */
    private $userFormFactory;

    /**
     * @var Nette\Database\Connection
     */
    private $database;

    /**
     * @param ICreateOrEditUserFormFactory $userFormFactory
     */
    public function injectUserFormFactory(ICreateOrEditUserFormFactory $userFormFactory)
    {
        $this->userFormFactory = $userFormFactory;
    }

    /**
     * @param Nette\Database\Connection $database
     */
    public function injectDatabase(Nette\Database\Connection $database)
    {
        $this->database = $database;
    }

    /**
     * @return CreateOrEditUserForm
     */
    protected function createComponentUserForm()
    {
        return $this->userFormFactory->create($this->database, $this->userId);
    }
}

Předpokládá to sice nepochopení předchozí části článku, ale IMHO bych se na snahu snížit počet vlastních vazeb na další služby znovu odkázal.

Filip Procházka
Moderator | 4668
+
0
-

@vvoody V dokumentaci jsou též ukázky vygenerovaného kódu – spíše o ořežu o omáčku.

@stekycz Zrovna parametry bych takticky ignoroval a po téhle úpravě bych upravil i článek, aby je vůbec neřešil.


Upraveno

Editoval HosipLan (22. 11. 2012 20:25)

Hafran
Člen | 121
+
0
-

Hezké, jen se mi nelíbí pořád ukazovat příklady na třídě „article“

<?php
factories:
    articles:
        create: ArticlesControl
        implement: IArticlesControlFactory
?>

tenhle příklad obsahuje 4 slova s dvojtečkou(tedy na první pohled důležitá), z nichž tři ale jsou klíčová a jedno ne – kdyby se to menovalo myOwnClass nebo nějaká taková blbost, možná to bude pro začátečníky jednodušší. Jelikož to articles by u někoho mohlo evokovat, že jde o klíčové slovo Nette. :/

Editoval Hafran (22. 11. 2012 21:19)

Felix
Nette Core | 1180
+
0
-

Me to prijde v pohode :)

Akorat u:

Kdybych nenapsal do create, že ArticlesControlFactory bude vytvářet ArticlesControl, tak se Nette Framework koukne na IArticlesControlFactory::create(), jestli nemá annotaci @return a kdyby ano, tak si z ní sám zjistí, jakou třídu bude vytvářet.

Nejmenovalo by se to ArticlesFactory??

factories:
    articles:
        create: ArticlesControl
        implement: IArticlesControlFactory
    # vs
    articlesControl:
        create: ArticlesControl
        implement: IArticlesControlFactory
vvoody
Člen | 910
+
0
-

@HosipLan myslím si že to ani tam nepatrí, ešte si pamätám ako som sám z toho bol zmätený, nevedel som či pre mňa ten kód niečo znamená kedže je generovaný, ale na druhú stranu je napísaný v dokumentácií, takže jej autor si zrejme myslí že ho programátor potrebuje vidieť… s čím (imho) momentálne, keď už som v obraze, nesúhlasím. Aspoň u začiatočníkov si myslím, že to narobí menej „škody“, respektíve rýchlejšie pochopia danú problematiku, keď bude predstavená čo najmenším množstvom kódu. Snažím sa na to pozerať ako by to čítal človek, čo Nette pozná tak z 5–10%, nie ako taký čo ho pozná z 50–90%.

stekycz
Člen | 152
+
0
-

@HosipLan Pokud tam ta úprava bude, tak bych je pak vypustil také. A kdo se tím bude více zabývat, tak si najde (snad :-)) správný způsob.

kubajz
Člen | 47
+
0
-

Já osobně mám trochu problém s tím, proč se pro takovou funkčnost mám psát interface, v jehož definici je přímo uveden návratový typ. Připadá mi to jako zneužívání rozhraní pro jiné účely, než pro jaké má sloužit, nebo mi něco zásadního uniká?

Naopak se zastanu toho, aby vygenerovaný kód v článku zůstal.

David Grudl
Nette Core | 8074
+
0
-

Díky za tento post! Je vážně skvělé, když se člověk zajímá, jestli to, co napsal, je srozumitelné!

Takže stručně: není :-)

A podrobněji: vysvětluješ lidem, kteří mají výborné znalosti současného DI, v čem jsou lepší továrničky. (A věřím, že nás pět ten článek pochopilo.) Ale zřejmě jsi chtěl vysvětlit běžnému programátorovi, k čemu je tahle feature dobrá. V tom případě je ale potřeba se odstínit od všech předpokládaných znalostí. Žádné jak to nedělat, o trošku lépe atd, ale naopak jak to dělat a jak to používat. Trvalo mi roky, než jsem to na školeních pochopil.

Tedy ideálně ukázat příklad, jak potřebujeme v presenteru vytvářet nějaký objekt → takže potřebujeme do něj dostat továrnu → ukázat výhodu, že ji framework vygeneruje sám. A teprve nakonec se dostat k složitějšímu tématu, jako jsou komponenty.

A opět zjednodušeně: nikdy nepoužívej „Jak jistě všichni víme“ a „občas nám může vadit“. Všichni neví a featury nikdy nevadí ;)

Filip Procházka
Moderator | 4668
+
0
-

Jsem to tedy vzal od podlahy … :) Líp už to ale asi nedám, takže pokud to nestačí, bude to muset napsat někdo jiný ;)


Koho zajímá „history of factories, how it was and how it is“, tak v historii to samozřejmě zůstalo ;)

Editoval HosipLan (23. 11. 2012 0:38)

Cifro
Člen | 245
+
0
-

Davam lajk na Davidov post. Dobre to zhrnul. I keď mám rank že „Nette guru“ ale s Nette som už dlho nerobil, a ani vývoj veľmi nesledujem (iba Latte) a tak članok mi prišiel taký že, „wtf? zase sa s tým DI inak pracuje v tom Nette ako pred paru mesiacami?“

Lepšie je napisať od akej verzie (commitu) je daná fičura možná. A ako sa to robilo predtým (stručne) a ako sa to robí teraz (podrobnejšie). Nie všetci sú vždy v obraze. You know there is other life out there outside of Nette…

Cifro
Člen | 245
+
0
-

HosipLan napsal(a):

Jsem to tedy vzal od podlahy … :) Líp už to ale asi nedám, takže pokud to nestačí, bude to muset napsat někdo jiný ;)

Tak teraz je to ooooveľa lepšie. Nice :)

Eda
Backer | 220
+
0
-

Díky za článek. Takovéto osvěty obzvlášť u nových věci není nikdy dost.

První verze byla podle mě taky fajn, ale asi jsem ovlivněn tím, že se zabývala přesně tím, co jsem taky řešil a prošel jsem si stejnými fázemi přístupu, které byly postupně čtenáři předkládány.

Poznámky k aktuální verzi článku:

  • doplnit na začátek upozornění o tom, že návod je určen pro verzi 2.1-dev
  • explicitně bych zdůraznil: „…zaregistrujeme do DIC jako bezejmennou službu:“ Ať aspoň lidi ví, co hledat, protože o bezejmenných službách zatím v dokumentaci nic není a dokud jsem to nečetl tady na fóru, netušil jsem, že bezejmenné služby existují
gawan
Člen | 110
+
0
-

mne sa viac páčila tá prvá verzia, dole by si mohol pridať link „nebo jinak DIF továrničky pro nás pět“ ;-)

David Grudl
Nette Core | 8074
+
0
-

Wow, to je pokrok o světelný rok!

enumag
Člen | 2118
+
0
-

Asi patřím mezi těch pět nebo co, ale pro mne byla lepší původní verze. :-D Zejména protože jsem chtěl vědět jak to použít s komponentami. :-)

Poznatky k nové verzi:

  1. Nejdříve mi přišla trochu wtf ta vlastní služba mailer, když Nette přece vytváří vlastní službu nette.mailer. Až když jsem se podíval do debugBaru tak jsem zjistil, že to je jiný mailer (Nette vytváří SendMailMailer, v článku je SmtpMailer). Ale pořád s tím mám problém, že na to nepotřebuji vlastní službu. Článek ve mne zkrátka vyvolal dojem „toto je jediný správný způsob jak odesílat e-maily“, což dle mého názoru není.
  2. Očekával bych, že factory pro vytvoření věcí jako \Nette\Mail\Message nebo \Nette\Latte\Engine bude také poskytovat přímo framework jako služby nette.latteFactory a nette.messageFactory a že třeba \Nette\Mail\Message bude už přímo v sobě mít metodu injectMailer. Chystá se něco takového?

Editoval enumag (23. 11. 2012 6:59)

Filip Procházka
Moderator | 4668
+
0
-

enumag napsal(a):

Nejdříve mi přišla trochu wtf ta vlastní služba mailer…

To je schválně, abych to nekomplikoval nějakým nette., nebo tím, jak nakonfigurovat mailer, všimni si také, že jsem nikde nepoužil autowire, aby na mě DIC neřval.

Nějaké to "tohle není best practice, ale demonstrace tovarnice doplnime.

cabadaj
Člen | 8
+
0
-

Jak Nette pozná, že má implementovat metodu create()? Nikde v configu není použito slovo create. Co kdyby interface obsahoval více funkcí? Nebo je create nějaké magické klíčové slovo?

Osobně se mě taky moc nezdá, ze interface určuje přímo třídu, kterou vrací. To by měla podle mě být záležitost konkrétní implementace interface. Mělo by tam být spíš Nette\Mail\IMessage.

Filip Procházka
Moderator | 4668
+
0
-

@enumag přidal jsem poznámku, že to není best-practise.

@cabadaj doplnil jsem poznámku o create() metodě.

Osobně se mě taky moc nezdá, ze interface určuje přímo třídu, kterou vrací. To by měla podle mě být záležitost konkrétní implementace interface. Mělo by tam být spíš Nette\Mail\IMessage.

Tak jsem si to přečetl 3× a už tě chápu. Problém je v tom, že nikdo ti nebude psát interface kvůli tomu, aby ho implementoval jedné třídě ;)

Má to další důvody. Například z toho Nette pozná, že bude vytvářet Nette\Mail\Message, ikdyž mu to nenapíšu do configu.


Úkol pro všechny: vymyslete lepší téma, kolem kterého půjde článek napsat – emaily se zdají být dost kontroverzní. Ideálně něco, co vůbec není ve frameworku.

Editoval HosipLan (23. 11. 2012 9:10)

enumag
Člen | 2118
+
0
-

HosipLan napsal(a):
@enumag přidal jsem poznámku, že to není best-practise.

OK, to už vypůadá lépe. :-)

Úkol pro všechny: vymyslete lepší téma, kolem kterého půjde článek napsat – emaily se zdají být dost kontroverzní. Ideálně něco, co vůbec není ve frameworku.

Přesně to mne taky napadlo. Že bych to přepsal na něco jiného než maily a komponenty. A stejně jako ty jsem se zasekl, protože mne nenapadá vhodné téma. :-D

Co ta druhá část ohledně injectMailer() v \Nette\Mail\Meassage?

EDIT: Trochu jsem nad tím přemýšlel.

Jaký example vlastně hledáme?

  1. Něco co se použije vícekrát (jinak je to služba),
  2. ale současně něco co není vykreslitelné (jinak je to komponenta),
  3. a současně to musí mít nějaké závislosti (jinak stačí new).

To už myslím docela výrazně omezuje možnosti. Kromě toho, jaký byl důvod proč @HosipLan tuhle feature vůbec vymýšlel? Pokud vím tak to bylo kvůli komponentám (@Hosiplan: oprav mne pokud se mýlím).

Z téhle úvahy mi vychází, že komponenty budou jako příklad přeci jen nejlepší, co myslíte?

Editoval enumag (23. 11. 2012 10:30)

Filip Procházka
Moderator | 4668
+
0
-

To téma (emaily) jsem vymýšlel déle, než jsem psal článek. Pochlapte se někdo ;)

Editoval HosipLan (23. 11. 2012 10:26)

enumag
Člen | 2118
+
0
-

@HosipLan: Upravil jsem svůj příspěvek výše. ;-)

Off topic: Stejně mám pocit, že ta třída Nette\Mail\Message by ten mailer vůbec neměla potřebovat a tedy by neměla mít ani metodu send. Myslím, že by bylo lepší odesílat přes $mailer->send($message);.

Filip Procházka
Moderator | 4668
+
0
-

Dle mého jsou komponenty téže nejlepším příkladem. Můžu přidat na konec ještě jednu kapitolu s komponentam, což?

Off topic: Stejně mám pocit, že ta třída Nette\Mail\Message by ten mailer vůbec neměla potřebovat a tedy by neměla mít ani metodu send. Myslím, že by bylo lepší odesílat přes $mailer->send($message);.

To je hodně offtopic, takže jen krátce: s první větou důrazně nesouhlasím, s druhou souhlasím. Proč? Convention over configuration ;)


No a samozřejmě bych opět ocenil inspirující komentář od Davídka :) Úplně nejlepší by bylo, tě napadlo geniální téma pro demonstraci :)

Editoval HosipLan (23. 11. 2012 11:01)

romiix.org
Člen | 343
+
0
-

Je to neporovnateľne pochopiteľnejšie ako prvá verzia;)
Jediná poznámka.. Pre nováčika by mohlo byť trošku mätúce kde sa vzalo ‚$this->database‘.

Možno by to ešte mohlo pokračovať tým, že formulár so spracovaním by šiel zvlášť do továrničky a tá by bola tiež nastavená tým istým spôsobom aj s nastavením ‚database‘ a ‚mailingFactory‘ cez inject.

Editoval romiix.org (23. 11. 2012 12:01)

duskohu
Člen | 778
+
0
-

neviem ci to nieje Off topic ale ako zaciaticnik by som uvital nieco taketo, kedze stracam nejako prehlad:
https://forum.nette.org/…tre-a-modely

Honza Marek
Člen | 1664
+
0
-

Podle mě je to dost těžko pochopitelná a dost magická feature a jako takovou bych ji vůbec do frameworku nezařazoval.

  • Je to takové programování v konfiguraci. Pokud přesně vím mechanizmus jakým to funguje, můžu některé třířádkové třídy napsat v neonu místo PHP.
  • Není zřejmé na čem funguje konfigurace setup. Jestli na továrničce nebo na vytvářeném objektu.
  • Nějaký kód stejně psát musím (ten interface).

<offtopic> Ostatně soudím, že sekce factories by měla být zničena. Neexistuje žádný rozdíl mezi továrničkou a službou, která má metodu na továrničkování. </offtopic>

jasir
Člen | 746
+
0
-

Hele super, ale klidně bych tam vrátil jak vlastně ta vygenerovaná třída vypadá.

Filip Procházka
Moderator | 4668
+
0
-

To je řečeno tím, že nejprve ukážu, jak bych si ji napsal já a dále je řečeno, že stejnou třídu za mně vygeneruje Nette, ne?

Patrik Votoček
Člen | 2221
+
0
-

Honza Marek napsal(a):

  • Je to takové programování v konfiguraci.

Ano Nette se stává o něco více deklarativní a zbavujeme se dalšího boilerplate (a toho se vždy rád zbavím). Imho nikdo a nic tě nenutí to používat (jenom pokud to používat budeš usnadníš si práci).

<offtopic> Ostatně soudím, že sekce factories by měla být zničena. Neexistuje žádný rozdíl mezi továrničkou a službou, která má metodu na továrničkování. </offtopic>

Ten rozdíl je právě v tom generování třídy (resp. tak to vidím já).

Michalek
Člen | 209
+
0
-

Já do toho asi nemám co moc mluvit, ale když ten příklad (kompletní, na konci) ze stránky zkopíruju do aktuálně staženého sandboxu z 2.1-dev, tak to skončí chybou Service 'nette.mail': Multiple services of type Nette\Mail\IMailer found: nette.mailer, mailer

Což buď jsem blbej já (zkoušel jsem to pro jistotu dvakrát), nebo je to záměr? :)

A za další, už týden se snažím správně pochopit factories a services, v čemž by asi i tenhle článek mohl pomoct, jenže slova Tuhle továrničku si zaregistrujeme do DIC uvozují příklad, kdy se přidává do sekce services a to je teda hodně moc matoucí :) Proč se továrnička (i když to má v názvu) registruje do služeb a ne do továrniček…

enumag
Člen | 2118
+
0
-

A už je to tady. :-(

@Michalek: Ten příklad je špatný. Snažíme se vymyslet něco lepšího, ale to bude chvíli trvat. Faktem je, že pro mailer nemáš vytvářet vlastní službu jelikož takovou už poskytuje samo Nette.

EDIT:

A ta druhá část se ti nezdá také oprávněně. Tohle je v podstatě ukázka toho jak bys to musel udělat dříve. Tj. továrnu si naprogramovat sám (to je ta třída MailingMessageFactory) a pak si ji zaregistrovat jako službu. Ten nový (preferovaný) způsob je potom níže, kde už to dáš přímo do sekce factories – to znamená že tu factory ty sám nepíšeš jako nějakou třídu, ale necháš Nette aby ji vyrobilo. To šlo používat i dříve, akorát takové továrny doteď nebyly injectovatelné, protože je Nette nevyrábělo jako třídu, ale pouze jako metodu DI containeru.

Myslím, že tohle stačí jako názorný příklad, že jakékoli „jakto bylo dříve“ nebo cokoli podobného začátečníky jen zbytečně mate a bude pro ně nejlepší ten nový správný způsob uvést hned na začátku a cokoli dalšího neuvádět buď vůbec nebo pod velkým červeným nápisem „takhle ne, tohle je jen ukázka pro detailnější pochopení“.

EDIT2:

@HosipLan: Lepší téma zřejmě nikoho nenapadá, takže asi čekáme než @dg povolí komponenty jako príklad, je to tak? Ty e-maily bych tam nechal jen opravdu nerad, připadá mi to hodně matoucí.

Editoval enumag (23. 11. 2012 19:00)

Filip Procházka
Moderator | 4668
+
0
-

Michalek napsal(a):

Což buď jsem blbej já (zkoušel jsem to pro jistotu dvakrát), nebo je to záměr? :)

Nejsi, opravil jsem to.

Jenže slova Tuhle továrničku si zaregistrujeme do DIC uvozují příklad, kdy se přidává do sekce services a to je teda hodně moc matoucí :) Proč se továrnička (i když to má v názvu) registruje do služeb a ne do továrniček…

Továrnička samotná je službou – je tam od toho, aby vytvářela opakovaně nové instance nečeho (emailu). Pokud ale chceš, aby to ale za tebe řešilo Nette, tak použiješ factories.

enumag napsal(a):

@HosipLan: Lepší téma zřejmě nikoho nenapadá, takže asi čekáme než @dg povolí komponenty jako príklad, je to tak? Ty e-maily bych tam nechal jen opravdu nerad, připadá mi to hodně matoucí.

Komponenty tam přidám na konec (až bude chvilka).


Začínám si myslet, že tohle téma prostě není pro začátečníky. Nenapadá mě totiž jednoduchý způsob jak jim to vysvětlit, ani na co by to oni mohli použít. Je dost těžké takovému člověku ospravednit „psaní takové spousty kódu“, když by prostě mohl napsat new Message.

Budu tam asi muset sepsat nějaký disclaimer, že je to „power-user feature“ a k její potřebě dojde člověk až po delší době používání Nette/psaní aplikací.

Editoval HosipLan (23. 11. 2012 22:08)

mkoubik
Člen | 728
+
0
-

IMHO je to názvosloví dost matoucí (obecně v nette, ne v tom článku). Vzhledem k tomu, že továrničky ve smyslu $container->createFoo() jsou neperspektivní by stálo za to se zamyslet jak to znormálnět (pokud možno bez BC breaku).

Editoval mkoubik (23. 11. 2012 22:08)

Filip Procházka
Moderator | 4668
+
0
-

@mkoubik: od toho jsou tyhle generované továrničky přeci ;)