Komentáře k článku

Dependency Injection: motivace

Dependency Injection se stalo horkým tématem programátorských diskusí i na českých fórech. Někteří jej horlivě obhajují a jeho použitím vysvětlují různé konstrukce a doporučení, jiní jej považují třeba za „overkill“ – většinou z nepochopení. Vašek Purchart seznámí s DI všechny, co zatím tápou.

Zpět na článek

94 komentářů k článku Dependency Injection: motivace:

  1. Radek Miček

    Proč nepoužít staticky typovaný jazyk

    Jaká je výhoda, když se místo staticky typovaného jazyka použije dynamicky typovaný jazyk a typy se píší do komentářů?

        1. manik.cze

          Re: Proč nepoužít staticky typovaný jazyk

          Nikde nic takového netvrdím, sám mám staticky typované jazyky radši, ale podle ankety je mezi čtenáři Zdrojáku nejpoužívanější PHP, tak jsem prostě použil tento zápis (ostatně je to v článku uvedeno).

          Návrhový vzor jako takový s tím nemá nic společného, takže tímto bych rád tuto debatu ukončil.

          1. Radek Miček

            Re: Proč nepoužít staticky typovaný jazyk

            Díky za odpověď.

            Návrhový vzor jako takový s tím nemá nic společného

            Podle mě má – ve staticky typovaných jazycích se injector typicky řídí typem parametru, což v dynamicky typovaném jazyce nepůjde. Například ve staticky typovaném jazyce mohu mít generické rozhraní INeco<T>, kde se injector může řídit i podle typu T. Zatímco v dynamicky typovaném jazyce budu mít pouze INeco (parametrizovat typem to asi nepůjde), takže zmíněný scénář budu muset realizovat jinak.

      1. Radek Miček

        Re: Proč nepoužít staticky typovaný jazyk

        1) Souvisí to s DI: Těžko můžete něco injectovat, aniž byste věděl typ potřebné instance. Což mě vede k závěru, že potřebujete typovou informaci, tudíž se ptám, proč nepoužít staticky typovaný jazyk?

        2) Souvisí to i s kódem v článku, proč psát

        /** @var ICache */
        private $cache;

        když mohu mít jen

        private ICache cache;

        Mj. statické typování přináší mnoho dalších výhod.

        1. Landy

          Re: Proč nepoužít staticky typovaný jazyk

          Asi proto, že DI neni něco co by vyžadovalo staticky typovaný jazyk. Jak jsem již psal je to hlavně o uvolnění závislostí a né o syntaxi jazyka. PHP se prostě vyjadřuje tak jak je uvedeno v článku a tím to končí. jediný rozdíl je v tom že já sám si v PHP musím hlídat jestli tam fakt mám instanci implementace daného rozhraní a nekontroluje to za mě kompilátor nebo to nevyvolá runtime error když se tam pokusím zapsat instanci jiného objektu

          1. manik.cze

            Re: Proč nepoužít staticky typovaný jazyk

            Ono to PHP dokonce i kontroluje – pomocí typové kontroly při předávání parametru do metody. Nicméně uvnitř objektu to v property samozřejmě už nefunguje. Vzhledem k tomu, že DI je o předávání závislostí do třídy, tak to by nás už ani nemělo zajímat.

            1. Aleš Roubíček

              Re: Proč nepoužít staticky typovaný jazyk

              Až na to, že DI není o předávání závislostí do třídy.

              1. Třída je pouze předpisem pro vytváření *objektů*.
              2. DI stejně skvěle funguje i u metod nebo funkcí (u neobjektových jazyků). Je to obecný princip.

              1. manik.cze

                Re: Proč nepoužít staticky typovaný jazyk

                Ano Aleši, máš samozřejmě v obou bodech úplnou pravdu, kaji se.

    1. Opravdový odborník :-)

      Re: Proč nepoužít staticky typovaný jazyk

      Žádná, ale když chce někdo PHP, tak mu nic moc jiného nezbývá.

  2. Opravdový odborník :-)

    chro chro

    Koukám, že bastlíři v PHP začínají pomalu objevovat to, co je v Javě už roky a na kvalitativně vyšší úrovni :-)

    Tak jen přidám pár rad:

    1) Volat nejdřív exists() a až když vrátí true volat read() je hloupost, protože musím provést hledání podle daného klíče dvakrát (ať už prohledávám hash tabulku nebo třeba ten souborový systém). Lepší je, když read() vrátí v případě neexistence null. Pokud by operace čtení neexistujícího byla výrazně dražší než zjištění existence bez čtení, mělo by se zjištění existence provést uvnitř implementace mezipaměti — ne v klientském kódu.

    2) Vnitřek metody doSomethingUseful() je potřeba refaktorovat resp. přesunout do implementace mezipaměti, protože tenhle blok kódu (logika obsažená v tom if/else, zjišťování existence, vytažení hodnoty, uložení…) by se nám jinak opakoval všude, kde budeme cache používat. Ono se sice zdá, že je to jen pár řádků a že to nevadí… ale vadí.

    3) Dávat do názvu rozhraní písmeno „I“ zavání tatarskou notací. Že jde o rozhraní je dané klíčovým slovem „interface“, není potřeba tuhle informaci duplikovat do názvu. Když už to chcete mermomocí odlišit, tak je lepší konvence mít rozhraní bez předpony/přípony a k implementacím doplnit na konec „Impl“ (i když to je taky nadbytečné, protože FileCache je prostě souborová implementace Cache).

    4) Hlavní kouzlo DI je v tom, že se o něj může postarat kontejner a jeho konfigurace není potřeba psát něco natvrdo do kódu a předávat pomocí parametrů konstruktoru. Má PHP něco takového?

    5) Nezapomínat na bezpečnost — chtělo by to kontrolovat, co se předává jako $index. Souborová mezipaměť by si měla hlídat, že poskytuje jen soubory z daného adresáře a žádné jiné — aby nešlo vytáhnout libovolný soubor z disku.

    1. fos4

      Re: chro chro

      To, že vyjde o DI článek v PHP nyní neznamená ještě, že v PHP to nebylo už dříve, některé frameworky to už mají dlouho :-)

      Jinak bych do detailu neřešil kód ono tam těch chyb je více (např. file_get_conten­ts(unserialize(TEM­P_DIR . ‚/cache/‘ . $index)); ), ale pro názornost a úvod do DI to bohatě stačí.

      Jinak tady jsou celkem pěkné další články o DI:
      Seriál od Fabiena:
      http://fabien.potencier.org/article/11/what-is-dependency-injection
      Martin Fowler:
      http://www.martinfowler.com/articles/injection.html

    2. manik.cze

      Re: chro chro

      ad 1,2,5) Cituji z článku: „Všechny příklady zde uváděné budou zapsány v PHP, ale návrhový vzor jako takový se samozřejmě na žádný konkrétní jazyk neváže. Uvedený kód berte pouze jako ilustrativní, důležité nejsou konkrétní implementace, pouze to, jak objekty skládáme dohromady a jak spolupracují.“

      ad 3) Odlišené pouze pro přehlednost v rámci článku

      ad 4) Toto je úvodní díl s názvem motivace, pokročilejším záležitostem jako jsou kontejnery se budu věnovat v některém s dalších dílů. Seriál je rozdělen protože všechny související věci by se do jednoho článku nevešly, kromě toho když DI ještě někdo nepoužil, tak není dobré na něj hned jít s kontejnerem – samotné DI nic takového nevyžaduje.

      Děkuji za názor opravdového odborníka ;)

    3. HosipLan

      Re: chro chro

      Přijde mi, že jste se sem přišel pouze vyzvracet, byť s Vašimi připomínkami lze pouze souhlasit (až na to I, to je věc zvyku a konvence).

      Takže: Jak tohle všechno souvisí s úvodem do Dependency Injection? Proč by měl úvod řešit věci, které s ním vůbec nesouvisí?

      1. mark8468464

        Re: chro chro
        Zřejmě by se v takovém případě spíš měla vyhodit výjimka než návratová hodnota null …

    4. Tharos

      Re: chro chro

      3) Když už to někdo chce mermomocí rozlišit, v čem je přidávání „Impl“ k názvu implementací lepší? Mně to přijde jako notace ještě tatarštější :). Přestože to doporučuje například Robert „Uncle Bob“ Martin ve své knize Čistý kód /kterou mi přijde – bez urážky – že jste právě dočetl a vydal jsem se rychle do vod internetu rozsévat právě načerpaná moudra :)/, nevidím žádnou výhodu v tom mít namísto jednoho rozhraní zapleveleného písmenkem „I“ zaplevelených rovnou několik tříd mnohem delším přídavkem „Impl“.

      Ptám se úplně vážně, v čem je to lepší? Očekávám nějaký velký přínos, když už jste to měl potřebu napsat jako offtopic komentář do článku o něčem úplně jiném. Peace. :)

      1. kruppi

        Re: chro chro

        Já se přiznám :) já jí právě dočet ale teda ničeho podobnýho sem se tam nedočet. Možná proto, že jsem nedával ani tak pozor na konvence jazyka jako na rady jak psát čistější kód :)

      2. Opravdový odborník :-)

        Konvence Impl vs. I

        Díky za otázku.

        Knihu Čistý kód jsem nečetl. Je dobrá? Četl jsem např. Dokonalý kód, ta se mi docela líbila. Ale človek se toho stejně nejvíc naučí procvičováním v praxi a od zkušenějších kolegů, skutečných mistrů.

        Dělám třicet let bankovní aplikace v Javě, tak snad můj příspěvek nikoho neurazil. Myslím to s vámi dobře. Je přeci hezké povídat si o programování, i když to přímo nesouvisí s tématem článku, ne?

        Co se týče té konvence: ono je to jen zdánlivé, že rozhraní je jedno a implementací je hodně a tudíž to „Impl“ zapleveluje více než jedno „I“. Jenže ve skutečnosti je to tak, že když už rozrhaní definujeme, pracujeme pak v klientském kódu (témeř výhradně) s ním a proměnné typu XXXImpl se nám téměř nikde nevyskytují. Na to si člověk musí přijít sám léty praxe, nebo mu to někdo zkušenější poradí — tady to máte na Internetu zadarmo, tak berte dokud dávám :-)

        A druhým důvodem pro tuto konvenci je tento: kromě běžných tříd a rozhraní máme i abstraktní třídy, což je jakýsi mezistupeň (vulgárně řečeno) a my můžeme v průběhu vývoje zjistit, že místo rozhraní nám bude více vyhovovat abstraktní třída (nebo naopak z abstraktní třídy budeme chtít udělat rozhraní). A pak bychom museli všechny výskyty přejmenovat (odstranit nebo přidat „I“), co by bylo dost práce, ale třeba i peněz, protože na tom našem rozhraní mohl už začít stavět někdo jiný a najednou by i on musel přejmenovávat. Takže když už si nějak ty třídy a rozhraní potřebujete poznačovat, používejte „Impl“ místo „I“, ušetří vám to náklady a váš vývoj bude radostnější.

        Děláme to tak my Javisté — zatímco třeba patlalové v C# používají to „I“ (oni vůbec dělají hodně věcí natruc obráceně, aby se odlišili, ale většinou to zmatlají a jejich programy stojí za starou bačkoru).

        1. Opravdový odborník :-)

          Re: Konvence Impl vs. I

          P.S. oprava:

          sed s/“A druhým důvodem“/“A druhý důvod“/g

          8ecd0389dc24441­1e8993d582bd0a­e77

        2. HosipLan

          Re: Konvence Impl vs. I

          V čem ušetřím, pokud budu mít rozhraní, které musím implementovat třídě, přepisovat na abstraktní třídu, ze které musím dědit? A nebo i klidně naopak. Myslím si, že jedno písmenko mě nezachrání :)

          1. Opravdový odborník :-)

            Re: Konvence Impl vs. I

            Máme:
            — jedno rozhraní
            — několik jeho implementací (řádově jednotky)
            — spousty použití tohoto rozhraní (klidně stovky nebo i tisíce výskytů) v klientském kódu (a ten mohl psát i někdo jiný)

            Takže jestliže změníme rozhraní na abstrantní třídu nebo obráceně, nebude potřeba měnit ten klientský kód, kterého je nejvíc, ale změníme jen těch pár výskytů (jednotky kusů).

        3. Michal Illich

          Re: Konvence Impl vs. I

          30 let programujete v jazyku, který byl vydán před 16 lety? To jste ho asi vymyslel, že?

          1. Jan Kodera

            Re: Konvence Impl vs. I

            billy joy se asi naučil česky a rozhodl se realizovat se skrze komentaře na zdrojáku :)

            1. mark8468464

              Re: Konvence Impl vs. I
              Hele zase to nepřehánějte, a zvolněte trochu s těmi osobními útoky … jeho komentář se mi zdá dost smysluplný, kašlete na to že se chlubí praxí a vnímejte víc podstatu toho co píše, ano? Děkuji.

        4. Radek Miček

          Re: Konvence Impl vs. I

          …zatímco třeba patlalové v C# používají to „I“…

          Je to pouze moje spekulace, ale myslím si, že tuhle konvenci Microsoft převzal z technologie COM, kterou .NET do jisté míry nahradil.

            1. Opravdový odborník :-)

              Re: Konvence Impl vs. I

              jj, jsou to dozvuky tohoto nesmyslu — proto jsem taky výše psal, že je nejlepší je nijak neoznačovat — jsou totiž označené klíčovým slovem „class“ nebo „interface“ stejně jako typy proměnných jsou dané slovy „int“, „String“ atd., není potřeba tuto informaci duplikovat do názvu proměnné nebo třídy/rozhraní. Ale když už si to někdo označovat musí, tak je lepší konvence „Impl“ než „I“ a snad se mi i podařilo vysvětlit proč :-)

              1. Tharos

                Re: Konvence Impl vs. I

                Nepodařilo. :) Navrhuji konec siláckých řečích o odprogramovaných dekádách a přejděme k činnu – ukažte kód, který ty Vaše výhody demonstruje (třeba „Impl“ vs „I“, ale klidně i jiné).

                Ten kód nemusí být zrovna úplně výstavní, PHP programátoři jistě budou shovívaví. Klidně vytáhněte ze šuplíku i starší Java kousek, třeba nějaký vyzrálý dvacetiletý ;).

                8488307681665­f3dc017ebcab0c4cd7b17­33e102 HOUK :)

                1. Opravdový odborník :-)

                  Re: Konvence Impl vs. I

                  „Impl“ samo o sobě žádnou výhodu nepředstavuje — je to pouze menší zlo ve srovnání s „I“. Jak už jsem tu psal, nejlepší je nepoužívat ani jedno, protože všechna potřebná informace je obsažena v tom klíčovém slovu „interface“ resp. „class“ a je nadbytečné (ba škodlivé) ji ještě duplikovat do názvu třídy/rozhraní. Více k tomuto tématu už nemám co říct (a víc prostoru si ani jedna hloupá konvence nezaslouží). Pokud si chcete ještě povídat, zkuste nadhodit jiné zajímavější téma :-)

                  1. anonym

                    Re: Konvence Impl vs. I

                    Mne by přesto zajímala jedna věc: pokud pro rozhraní a třídy používáte pojmenování bez prefixu a suffixu, často vám jistě vznikají stejné názvy. Obzvláště právě u DI a obecně programování přes rozhraní.

                    Jak toto řešíte? Oddělujete rozhraní a třídy do jiného jmenného prostoru?

                    1. Opravdový odborník :-)

                      Re: Konvence Impl vs. I

                      Rozhraní používáme v případě, že připadá v úvahu více implementací (ne třeba hned v první verzi, ale výhledově počítáme s tím, že jich bude více). Mít právě jednu implementaci k jednomu rozhraní nedává valný smysl.

                      Máme tedy více implementací a ty se od sebe nějak liší – tudíž se i jinak jmenují. Když zůstaneme u příkladu z článku: budeme mít jednou souborovou Cache jednou paměťovou a jednou databázovou – každá se bude jmenovat jinak a rozhraní se bude jmenovat třeba jen Cache. Tudíž k žádným konfliktům jmen docházet nebude. Není tedy nutné používat ani jiné jmenné prostory.

                      1. www.google.com

                        Re: Konvence Impl vs. I

                        Díky za odpověď. Právě jsem nad tím dumal a vzpomněl si, že jsem se pár měsíců zpět na to někoho (vás) ptal :)

        5. Ondřej Mirtes

          Re: Konvence Impl vs. I

          Kvalitu programu jmenné konvence rozhodně nedělají :)

          Ačkoli mám Javu rád, prefixovat rozhraní s I je mi bližší. Nerozlišovat jeho název od tříd postačuje do té doby, pokud je přijímám jako parametry metod – pak mě nezajímá, zdali se jedná o rozhraní nebo jeho implementaci.

          Často se mi ale stává, že si někde všimnu používaného názvu, chci ho instanciovat a IDE mi udělá obrovskou nudli kódu s anonymní třídou – protože jsem mu řekl, že chci instanciovat rozhraní.

          Nejmarkantnější je to u Stack (třída) a Queue (rozhraní). Přitom podle názvosloví jsou na stejné úrovni.

        6. Zaboj Campula

          Re: Konvence Impl vs. I

          Obávám se, že tvrzení „Dělám třicet let bankovní aplikace v Javě“ se dá jen stěží věřit. Nejsem opravdový odborník takže nedokážu posoudit zda je vhodnější mít interface s předponou I nebo implementaci s příponou _impl, nicméně vaše tvrzení, o kterém lze s úspěchem pochybovat snižuje důvěryhodnost ostatních informací, které nám s velkou laskovostí předkládáte.

        7. dusanmsk

          Re: Konvence Impl vs. I

          Teda precital som si Tvoj komentar este raz a musim povedat, ze nevychadzam z udivu. Clovece, ty si mag. „30 rokov bankove aplikacie v Jave“, padam pod stol a zacinam rotovat.

          Odhliadnuc od toho, ze pisanie bankovych aplikacii nie je nic, cim sa da chvalit ( bohuzial mam tu cest, uz chapem tie kecy kolegov z minulych firiem o cvicenych opiciach v bankach, sam som sa jednou takou opicou stal a radsej sa sposobom obzivy moc nechvalim ), tak pisat ich v jazyku, ktory v tej dobe este neexistoval, je uctyhodne. Java je na takyto druh aplikacii pouzitelna ( a skutocne je to tak? ) par rokov, nech nezerem, maximalne 6.

          C# zas tak odlisny nie je, nech platformu microsoftu neznasam ako chcem, v jazyku a jeho moznostiach ako takom nie su zasadne rozdiely. Najvacsi rozdiel je akurat tak vendor/platform lock-in.

          Inak pozdrav pani ucitelku v skolke. A ked budes v Jave programovat 80 rokov, tak sa sem vrat, ok?

          1. arnold

            Re: Konvence Impl vs. I
            Vy ste asi ešte nevidel lambda metódy a v C# 5.0 async programovanie. To je ten najväčší rozdiel. Takže najprv si naštudujte niečo o jazykoch a až potom píšte veľkohubé vyhlásenia.

  3. harvejs

    dik za super clanok

    ako sa uz pise v rozbiehajucej sa diskusii, ide cisto a nastrel problematiky, ale velka vdaka za to ze sa zacinaju riesit veci ako navrhove vzory atd. drzim palce a tesim sa na dalsie diely!

    PS: neda mi este k odbornikovmu bodu c. 1 :) ak uz ideme do takychto puntickarskych detailov (co samozrejme vobec nebolo cielom tohto clanku), ak ocakavam od funkcie objekt nemozem vratit null, ale hodit exception. to len tak na okraj :)

    1. Radek Miček

      Re: dik za super clanok

      Tohle ale není detail. Mezi testem a čtením může hodnota z cache vypadnout a máte z toho bug.

      Pokud do cache záměrně neukládám null, pak s tímto řešením není žádný problém. Pokud ano, mohu vrácený objekt zabalit do typu Some/ Maybe známého z jiných jazyků.

        1. zomp

          Re: dik za super clanok

          Samozřejmě že ne, je na to ale dobré upozornit – když se návrhové vzory implementují špatně, pěkně to dokáže situaci zhoršit (regrese ve výkonu, nesrozumitelný kód, menší znovupoužitel­nost…).

        2. Andrew

          Re: dik za super clanok

          To ale přece vůbec nevadí. Když člověk nemá nic k tématu, nabízí se oblíbené fráze „tohle máme v brainfucku už roky“, „v PHP programují jenom lamy“, případně se najde nějaká drobnost (bonusové body jsou za to, když nesouvisí s tématem článku) a na ní se dokáže, že autor je patlínek, který vlastně vůbec neumí programovat. Jo, zavděčit se je těžké :)

          P.S.: Těším se na další díl ;)

        3. v6ak

          Re: dik za super clanok

          To je na jednu stranu pravda, ale na druhou stranu, nejsem pro utvrzování nováčků v některých chybách. Je to podobné jako <?php echo $_GET[‚name‘]; ?> v nejedné učebnici PHP – sice je asi cílem ukázat něco jiného, ale mnoho nováčků se toho může chytit a používat to, protože kniha je pro ně určitou autoritou. V tomto případě je to relativně zřejmé, ale u některých útoků (třeba CSRF a hrátky se sessions) až tak ne.

      1. František Kučera

        Výjimky vs. návratové hodnoty

        Přesně tak. Ono je sice nevhodné zneužívat návratové hodnoty pro řešení výjimečných stavů (např. vracet -1, -2, -3 atd. a podle toho pak luštit, co se vlastně stalo a v nevýjimečných případech vracet kladná čísla – skutečné hodnoty), v takovém případě je správné vyhodit výjimku.

        Jenže vracení null bych za takové zneužití nepovažoval – jednak null dobře vystihuje, co se stalo (chybějící* hodnota je null hodnota) a jednak je to běžná konvence. Navíc tohle chování musí být popsané v dokumentaci metody, takže každý ví, co od ní má čekat (např. tady by bylo napsané: „vrací hodnotu z cache nebo null, pokud hodnota ještě nebyla načtena“). Navíc to, že hodnota chybí není nijak výjimečný stav – naopak je to často stav normální (např. po startu programu nebo u položek, ke kterým se nepřistupuje příliš často), takže vyhazovat výjimku není úplně vhodné.

        Nicméně pokud by někdo potřeboval rozlišovat, zda je hodnota skutečně null nebo pouze nebyla zatím do cache načtena, tak je možné to přepsat s použitím těch výjimek (ale není to preferovaná varianta). Každopádně má pravdu Odborník – je potřeba, aby to byla atomická operace, ne exists() a read() zvlášť – jednak kvůli výkonu a jednak kvůli tomu, že se hodnota může vypršet a při read() dojde k chybě, ačkoli jsme podle exists() očekávali, že dostaneme hodnotu.

        *) Trochu složitější je to při vracení kolekcí – některé týmy mají pravidlo, že místo kolekcí se nesmí vracet null a místo toho se musí vrátit prázdná kolekce. Jinde se naopak null místo kolekce vracet může a má to nějak definovaný význam. Tady záleží na konvenci a pravidlech daného týmu/projektu. Ale to už zabíháme do zbytečných detailů.

    1. František Kučera

      Re: Hrůza

      Chvíli mi to trvalo, ale pak jsem si vzpomněl :-) On je to takový interní humor, podle hodnocení tvého komentáře to vypadá, že ho většina lidí nepochopila. Takže pro ostatní: STFW :-)

  4. Aleš Roubíček

    Nevhodný příklad

    Injektování cache do service je v první řadě smell. Tohle je ideální místo na užití vzoru dekorátor.

    1. manik.cze

      Re: Nevhodný příklad

      Když jsem vymýšlel příklad, tak jsem tak mě bohužel nenapadlo nic moc, kde by se nemuselo vlastně vysvětlovat o co jde a ostatní by to pochopili. Toho, co říkáš jsem si byl vědom, ale rozhodl jsem se to risknout i přesto, že mi to tu může někdo omlátit o hlavu. Proto jsem se snažil do třídy FooService napsat pouze minimum informací, v zásadě ona může být tou „vnější“ cachovací vrstvou, která teprve v metodě process volá původní třídu. Je pravdou, že decorator by byl pro implementaci cache vhodnější.

      Díky za oba přínosné komentáře.

    2. Jan Tichý

      Re: Nevhodný příklad

      Aleši, díky za připomínku k věci! Než Vašek poslal svůj první díl do redakce, tak jsme spolu přesně tohle řešili, rozhodnutí ukazovat to zrovna na cache bylo nakonec motivováno hlavně průhledností a snadnou pochopitelností tohohle příkladu pro lidi, kteří ještě nikdy o DI nezavadili…

  5. Fanoušek A. Denta

    Re: Dependency Injection: motivace

    Franto Kučero, omlouvám se, ale netuším, o čem píšete :-) Jen jsem chtěl adentovi udělat radost, když si na to na twitteru stěžoval :-) Popravdě netuším ani, co je to v programování rošáda :D

  6. Leoš

    statické typování

    DI ve staticky typovaných jazycích prostě funguje lépe, právě proto že DI framework může pracovat s těmi statickými typy a podle nich se rozhodovat co kde „injectne“. Projděte si například základy Google Guice a pochopíte.

    1. Tharos

      Re: statické typování

      Žeby další Javista s praxí kolem 30 let ;)?

      Chápeme a nemusíme si nic procházet. Proč ten konfrontační tón? Zde někdo tvrdí, že DI funguje lépe v dynamicky typovaných jazycích?

      Tady jde o to, že při rozhodování, jaký jazyk na daný projekt použiji, je typovost relativně dost nepodstatná. A mám-li spadeno na PHP, které má množství výhod (viz i jeho popularita), mám jej zavrhnout proto, že je dynamicky typované a v Javě by DI fungovalo o trochu lépe? Nebo jaké myšlenkové pochody se nám tu snažíte vštípit?

      Na podobné komentáře jsem asi krátký… :) Nechápu pohnutky, jaké autory vedou k jejich napsání.

      1. Jirka V.

        Re: statické typování

        Myslím si, že podobné jako mají Svědkové Jehovovi k nedělnímu obcházení domácností. Musí nás – pobloudilé to ovce obrátit na správnou (svou) víru a za to přijdou do nebe.

        1. asdasd

          Re: statické typování

          Taky mi to tak někdy připadá. Diskuze na téma „staticky typované jazyky jsou lepší než dynamicky typované“, „Java je lepší než C#“, „Ruby je lepší než PHP“, „levá ruka je při honění lepší než pravá“, jsou většinou o hovně.

          1. stydim se

            Re: statické typování

            Ja honim pravou ! Lorem Ipsum is simply dummy text of the printing and typesetting industry. Levou honej jen bastliri a patlaci kodu.

              1. asdasd

                Re: statické typování

                Tak to 30 let honíš v (sperma)bance a je ti 16, ne? Snad můj příspěvek nikoho neurazil. Myslím to s vámi dobře. Je přeci hezké povídat si o honění, i když to přímo nesouvisí s tématem článku, ne? :-D

    2. David Grudl

      Re: statické typování

      Tak to teď přijde velké překvapení: žádné černobílé dělení na statické a dynamické jazyky neexistuje. Kam zařadit PHP, které má statické typování tříd předávaných metodou (šok, že?), kam zařadit C# 4 s jeho dynamickým typováním? A jak to souvisí s DI se raději ani neptám ;-)

      1. Radek Miček

        Re: statické typování

        má statické typování tříd předávaných metodou (šok, že?)

        Řekl bych, že nemá, neboť se typy kontrolují až za běhu programu.

        kam zařadit C# 4 s jeho dynamickým typováním?

        C# je staticky typovaný – v době kompilace rozlišuje více než 1 typ.

        A jak to souvisí s DI se raději ani neptám

        Mé poznámky se vztahovaly ke staticky typovaným jazykům s bohatším typovým systémem (osobně nemám rád dělení na staticky a dynamicky typované, protože to druhé je první případ toho prvního).

        Konkrétně mi tedy řekněte, jak provedete DI pro funkci s hlavičkou f(a, b).

            1. David Grudl

              Re: statické typování

              Pošlu tam objekt, který tam chci mít. Přece typ neurčuje, jaký objekt tam mám dát. Pokud mám funkci copy(File $from, File $to), tak sice vím typ, ale nic to neřeší, setsakramentsky záleží na tom, abych objekty uvedl v zamýšleném pořadí. Pokud jsi v tomhle viděl výhodu typovosti, tak pro samé kontejnery nevidíš DI. Podstata je skutečně někde jinde.

              Nehledě na to, že v PHP lze taky zapsat copy(File $from, File $to) a funguje to dle očekávání včetně reflexe.

              1. Radek Miček

                Re: statické typování

                Nehledě na to, že v PHP lze taky zapsat copy(File $from, File $to) a funguje to dle očekávání včetně reflexe.

                Nemáte tam parametrizovaný typ, např. pro INeco<T> to už fungovat nebude (například pro kolekci prvků typu T).

                Netvrdím, že nemůžete DI dělat v PHP, Pythonu apod., ale jsem přesvědčen, že to půjde lépe v jazycích s bohatším typovým systémem – třeba kvůli zmíněnému kontejneru, který má v těchto jazycích mnohem více informací a tím pádem mnohem větší potenciál pro automatizaci.

                OT: ostatně, co dnes nejde lépe v jazycích s bohatším typovým systémem.

                1. Opravdový odborník :-)

                  Spring?

                  Nějak mezi řádky vašich příspěvků cítím, že máte na mysli Spring. Je tomu tak? Pokud ano, tak jen drobné varování:

                  Spring je lákavý a za určitých okolností užitečný, ale… místy se z toho stává šamanismus. Je tam příliš mnoho automatizace a snahy přemýšlet místo programátora (resp. programátor toho napíše méně a stroj si má domyslet ten zbytek). Spring zdaleka není dokonalý software (jemně řečeno). Někdy bohužel injektuje něco jiného než programátor chce (nebo odmítá injektovat úplně) a přesvědčit ho je takřka nemožné. 8ecd0389dc24441­1e8993d582bd0a­e77 Třeba to časem opraví, ale zatím to není úplně ono. Proto dávám přednost raději standardnějším prostředkům Javy EE, kde má člověk věci víc pod kontrolou a ani tam není moc psaní navíc (spíš naopak).

                  On je to problém s příliš volnou vazbou (bohužel velký problém dneska v SW inženýrství), vyhodnocování až za běhu a nejistým nepředvídatelým výsledkem. Tak vznikají křehké a snadno se rozpadající se systémy (ačkoli záměr byl přesně opačný — volnější vazby měly dodat systému pružnost).

                  Je to velmi podobné tomu sporu mezi staticky a dynamicky typovanými jazyky (resp. silně a slabě, pozor, není to totéž). Věci, které fungují tak nějak samy od sebe jsou někdy příjemné, ale často nespolehlivé — v opravdových programech je lepší se jim vyhnout (to může být i to injektování na základě typu, kde si stroj domýšlí, co by měl injektovat a ne vždy je to jednoznačné). Když se vrátíme k tématu článku: důležité je, že některé věci nejsou zadrátované uvnitř, ale jsou předávány zvenku — ale jestli to předávání bude nějak automatizované a kouzelnické, nebo řízené ručně, precizně je už druhá věc.

                  Jinak s vámi ale souhlasím ohledně těch dynamických/sta­tických jazyků, např. statické typování ušetří část testu, protože řadu věcí není potřeba testovat: roli některých testů přebírá kompilátor, který má dvě výhody — pracuje zadarmo (nemusíme ho psát, narozdíl od testů, použijeme hotový) a nemůžeme na něj zapomenout nebo se na něj zapomenout (zkompilovat program před spuštěním prostě musíme).

                  1. Radek Miček

                    Re: Spring?

                    Když programuji v C#, používám Ninject, dříve jsem používal Autofac. Spring nepoužívám.

                  2. Sid

                    Re: Spring?

                    kde Spring injektuje nieco co programatoror nechce? nejaky priklad by sa nasiel – alebo je to typu jedna pani povedala?

              2. Radek Miček

                Re: statické typování a testování

                Stejně tak Vám budu tvrdit, že se v jazycích s bohatším typovými systémem lépe testuje:

                1) některé vlastnosti testovat nemusím, protože je garantuje typový systém

                2) mohu využít automatického generování testovacích dat podle typu

                A Vy mi můžete opáčit, že pro samé generování dat nevidím testování. Ale já vidím DI i testování.

                  1. Jan Tichý

                    Re: statické typování a testování

                    Radku, prozraďte mi, o co Vám jde? Kam míříte, co se nám v kontextu článku snažíte říct? Že ve staticky typovaných jazycích se injektování implementuje o drobet lépe, než v dynamických jazycích? OK, tohle sdělení už jsme od Vás asi všichni dávno pochopili. Co dál? Že nemá cenu snažit se o DI v dynamických jazycích? To asi ne, že jo. Tak o co vám tady v té Vaší onanii jde?

                    1. Radek Miček

                      Re: statické typování a testování

                      Reagoval jsem na komentář pana Grudla. Konkrétně na větu

                      A jak to souvisí s DI se raději ani neptám

                      Vadí Vám to?

                      1. kruppi

                        Re: statické typování a testování

                        v DI jde o to že pokud někdo nebo něco potřebuje nějaký jiný prostředek k tomu aby provedl svou funkci, tak si ten prostředek nevytvoří ale dostane ho. Nevím co s tím má společného typovost jazyka.

                        1. Radek Miček

                          Re: statické typování a testování

                          Nevím co s tím má společného typovost jazyka.

                          Už to tu padlo asi třikrát.

                          1. asdasd

                            Re: statické typování a testování

                            No a je to opravdu tak zásadní a nepřekonatelný rozdíl? Pro mě teda ne.

                          2. martin

                            Re: statické typování a testování

                            trochu sa zasekavate na implementacnych detailoch tam, kde ini riesia princip

              3. v6ak

                Re: statické typování

                Tento příklad ukazuje, že to v některých případech nelze vyřešit jen na základě typu. (Ještě viditelnější by to bylo u Stringu.) Ale neříká, že je to vždy blbost. Mám-li vycházet z předchozího případu, bude to trošku umělé, ale ještě to půjde (jazyk: Scala):
                copy(from: File, to: File, implicit copyingStrategy: CopyingStrategy)
                Parametr copyingStrategy je možné neuvést, pak se kompilátor pokusí vyhledat v aktuálním scope (tedy i v proměnných/funkcích viditelných jen díky importu) nějakou vyhovující proměnnou nebo funkci, která je označena slovem implicit.

                Lepší příklad by mohl být s databázovým připojením a konfiguracemi. Ale v zásadě jde o to stejné, jen to není tak umělé.

                Že by to šlo i v dynamicky typovaném jazyce? Určitě ano, ale:
                * Ještě jsem to neviděl.
                * Mohl by to být takový slowdown, že by se tomu programátoři radši vyhýbali. Ve staticky typovaných jazycích je tato režie jen u kompilátoru, za běhu není rozpoznatelné, zda to programátor chtěl mít pohodlnější.
                * Optimalizovat by to zcela určitě šlo, ale nejspíš by to stálo spoustu úsilí a výkon by pak byl trochu magií – nevinná úprava by mohla nečekaně srazit výkon.

      2. v6ak

        Re: statické typování

        U PHP je to spíše cukr pro dynamickou kontrolu, který je navíc viditelná přes Reflection apod. Pak mi totiž PHP nebrání, abych tomu přiřadil něco jiného a vše je kontrolováno až za běhu. Mezi následujícími ukázkami kódu není v PHP až takový rozdíl:

        http://ideone.com/MgjEk

        http://ideone.com/VM9ks

        Ve staticky typovaných jazycích (C#, Java, Scala, …) by tam byl podstatný rozdíl.

        C# je už lepší příklad. Podobně by se dala uvést Java/Scala a Reflection API, ačkoli to je spíše vlastnost standardní knihovny. Ale pořád tu vidím jeden podstatný rozdíl: Javu, Scalu, C# etc. lze použít jako staticky typovaný jazyk. PHP bez nějaké nadstavby ne. Lze v něm psát, jako by bylo typované staticky (to je velmi časté), ale standardně (bez úpravy jazyka) budou všechny kontroly probíhat dynamicky, aspoň z pohledu programátora (optimalizátor je může provést dříve).

        Ale souhlasím, že je problém udělat dvě škatulky jazyků a do jedné dát staticky typované a do druhé dynamicky typované. Takový Prolog by se škatulkoval už hůře, protože na dynamicky typovaný jazyk je (z mého podledu) příliš staticky, ale na staticky typovaný jazyk příliš dynamický.

  7. Pavel Šimerda (pavlix)

    zvláštní...

    Už když jsem viděl na začátku článku to o „nepochopení“, tak jsem si říkal, že bude mít autor dost, co dělat, aby mě přesvědčil, že právě on je ten, který chápe.

    Odhlédnu-li od toho, že mě nepřesvědčil… DI tak jak je popsané v tomto článku mi přijde jako pojmenování pro něco, co alespoň trochu slušní programátoři považujou za samozřejmost. Nehledě na to, že v tom nevidím žádnou injekci.

    Jestli to správně chápu, tak autor článku napsal, že DI spočívá v tom, že konstruktor Cache má jako parametr, kde ta cache bude, a konstruktor nějaké jiné třídy má jako parametr objekt cache. Prostě triviální pospojování objektů.

    1. v6ak

      Re: zvláštní...

      „DI tak jak je popsané v tomto článku mi přijde jako pojmenování pro něco, co alespoň trochu slušní programátoři považujou za samozřejmost.“

      Celkem souhlasím. Já taky k tomu přišel „přirozenou cestou“ – říkal jsem si, že ony závislosti se mi tam berou nějak „magicky“ a že používání (de facto globálních) cfg souborů není ideální (např. není možné použít tu třídu pro dvě různé DB), tak jsem k tomu taky přišel.

      Ale na druhou stranu, návrhové vzory bývají obvykle jednoduché. Když si vezmu třeba Factory, Strategy nebo i onen nadužívaný Singleton, jejich implementace bývá obvykle na pár řádků.

      Dokonce bych řekl, že Design Patterns tu možná nejsou k tomu, abychom se podle nich učili. Ty tu jsou od toho, abychom mohli snadno popsat opakované vzory – abychom to nemuseli pokaždé znovu popisovat. Jinými slovy, DRY v dokumantaci a komunikaci.

      „v tom nevidím žádnou injekci.“
      DI je „vložení závslostí“ – ty vkládám například v konstruktoru. Taky jsem měl zpočátku problém pochopit ten název. Ale spíš se mi nelíbí pojem IoC (Inversion of Control), protože zde nevidím inverzi. Spíš bych za inverzi považoval nepoužití IoC.

      „Prostě triviální pospojování objektů.“
      Jak jsem již psal, návrhové vzory nemají za účel být něčím složitým. Komplikovaný návrhový vzor něčím smrdí a v lepším případě vy si zasloužil rozdělení na více malých.

      1. Aleš Roubíček

        Re: zvláštní...

        inverze řízení znamená, že objekt si vytváření závislostí neřídí sám, ale nechává to na někom jiném. Zde je ta inverze. Bezparametrický konstruktor, který vytváří závislosti se otočí a pouze je nadeklaruje jako parametry.

Napsat komentář

Tato diskuse je již příliš stará, pravděpodobně již vám nikdo neodpoví. Pokud se chcete na něco zeptat, použijte diskusní server Devel.cz

Zdroj: https://www.zdrojak.cz/?p=3504