21 komentářů k článku Defenzivní JavaScript? Rozhodně ano!:

  1. HonzaMarek

    hm
    Simulovat privátní proměnný ve „třídách“ a kvůli tomu nepoužívat prototype pro metody není z výkonnostního hlediska úplně dobrý nápad.

    Příklad s časama je zajímavej. Autor si pochvaluje jak se mu nemění reference na proměnnou, ale vesele mění samotnou hodnotu té proměnné. Přitom z toho, že věci jako čas nejsou immutable, taky vzniká hodně chyb.

    Nepoužíval bych jedno klíčové slovo var pro více proměnných. Pak se dá snadno zapomenout čárka na konci a neštěstí je na světě. I když lint to pak zachrání.

    Nepodoporu klíčového slova const řeší babel.

    Odstranění else často naopak kód zjednoduší. Místo if (a) { return 1; } else if (b) { return 2; } else { return 3; } můžu napsat if (a) { return 1; } if (b) { return 2; } return 3;

    1. Ondřej Novák

      Re: hm
      Jaké výkonostní problémy tam vidíte? Že se musí pokaždé v konstruktoru znova a znova inicializovat member promenne a funkce? Takže místo toho, aby je pak při volání JS hledal v prototypech je může vytáhnout rovnou z objektu.

      1. HonzaMarek

        Re: hm
        Určitě je zbytečný ty metody při každém new vytvářet. Mohly by být definovány předem jako funkce a v konstruktoru by pak bylo jen přiřazení. Tím by se ušetřil čas i paměť.

        Víc mi ale vadí, že to není „normální“ javascript, ale ohnuté řešení. Běžně se pro třídy používá prototyp s tím, že v JS nic jako privátní proměnné neexistuje a musí se s tím počítat. Jakékoliv neobvyklé řešení podle mě přináší jen problémy, když třeba má přijít nový programátor a podobně.

        1. Ondřej Novák

          Re: hm
          Tak sorry, já myslel, že chytrý JS parser ty metody má už dávno vytvořený během parsování kódu, že tedy si je někam uloží do nějakých skrytých proměnných. Asi jsem moc napřed.

          Jinak mi na prototypovém programování vadí roztříštěnost kódu, Je přehlednější, když věci spolu související jsou u sebe.

          Navíc častokrát deklaruju i „privátní“ funkce a to i uvnitř jiných funkcí, třeba pokud nějaký callback potřebuju použít víckrát a přitom má smysl, aby byl vidět jen uvnitř té funkce a ne nikde vně.

          Podle mě zakmnout se jen v nějakém patternu, který omezuje možnosti JS na minimum aby tomu rozuměli, …třeba javisté…, není dobrý. Schopný JS programátor by se měl vyznat i v čistě funkcionálním použíti JS… a samozřejmě v closure.

          1. Ondřej Žára

            Re: hm
            Chytrý parser je — a bude — pořád jenom parserem. Těžko bude nějaký kód vykonávat, jako například cokoliv, co najde v konstruktoru. Co kdyby tam bylo nějaké volání? Co kdyby se tam dělo něco podmíněně? Co kdyby se tam ty metody — z nichž každá zabírá novou paměť, pro každou vytvořenou instanci! — vytvářely parametrizovaně, v závislosti na výsledku volání něčeho jiného v tom konstruktoru?

            Navíc tedy, mějme kód

            var F = function() {
              this.m = function() {}
            }
            var f1 = new F();
            var f2 = new F();
            

            V tomto případě je f1.m != f2.m, jsou to zcela odlišné funkce (mají akorát shodný zdrojový kód). Těžko by chytrý parser dopředu odvodil, kolik jich má vytvořit, že…

            Zatímco u F.protoype.m budou obě ty samé, sdílené, vytvořené ještě před instancializací. Samosebou je výhoda tohoto řešení znát jen pokud vytvoříme >1 instanci :-)

            1. Ondřej Novák

              Re: hm
              No z mého pohledu this.m je pořád tatáž funkce, jen při jejím spuštění se nasetuje jiný kontext. Nepsal bych to bezúčelně, nějaký jazyk s podobnou syntaxi a logikou programování jako je Javascript jsem sám napsal (aktuálně je SF mrtvý, zdrojáky tam budou, až se SF zmátoří). Nemůže se samozřejmě rovnat s možností JS, ale to taky nebyl účel. No a právě něco takového jsem tam řešil. Kompilátor vidí function tak přeloží její obsah do exekučního stromu a jeho root strčí jako konstantu. Inicializace objektu pak už není nic jiného, než pouhé nastavení proměnné na konstantu.

              Funkce v JS mají navíc svůj kontext (closure) kde vznikly. Ale nemyslím si vůbec, že by každá funkce byla originál. Jestli to tak běžně parsery dělají… myslím že nedělají, minimálně V8 každou funkci přeloží JITem do strojového kódu v době parsování kódu, nepouští už JIT při každé instanci funkce. Maximálně bych připustil, že by nějak z té instanciace dokázal vytěžit a přeložit to lépe při znalosti kontextu, ale to mi přijde jako spíš z říše snů.

              Samozřejmě mi na JS prototypování vadí, že funkce v objektech neví čí jsou. To pak vede k nutnosti neustále hlídat, zda sebou tahám kontext objektu (this) nebo ne. Funkce v closure naopak vědí čí jsou, je to víc OOP.

              1. Ondřej Žára

                Re: hm
                Je docela jedno, jestli tvůj pohled považuje f1.m a f2.m za stejné funkce či nikoliv. Podstatné je, že pro interpret JS jsou zcela rozdílné, například i proto, že můžu napsat:

                f1.m.neco = "ahoj";
                f2.m.neco = 42;
                

                A k žádné kolizi či přepsání nedojde. Jistě se tedy shodneme, že jsou identické sémanticky (dělají tu samou věc), ale tím to tak končí.

                Jinak JIT je zkratka z „Just In Time“, což přesně vyvrací hypotézu, že by k překladu do strojového kódu došlo již během parsování. JIT stojí na tom, že se kompilje až „hot“ kód, tj. ten, který se ukázal jako často vykonávaný (a typově stabilní). Jen pro něj se pak za běhu – „just in time“ pustí ta (složitá, drahá) kompilace.

                U parseru se ovšem může objevit AOT, „Ahead Of Time“ kompilace. Ta provádí překlad už při parsování, bez vykonání kódu. Jestli se něco takového děje u funkcí definovaných v konstruktoru, to upřímně nevím.

                1. Ondřej Novák

                  Re: hm
                  pohybujes se porad v js dogmatu. Funkce je porad jeste js objekt, ktery ale interne bude mit skrytou konstantu a to vlastni kod, ktery ty tam nevidis. f1.m.neco tedy nic nedokazuje, neco je promenna, ktera nijak nemeni kod vlastni funkce, ani se nijak nepromitne do kontextu, dokud na nej pres this neukazes. O te skryte kostante celou dobu mluvim a to ze se nejakym zpusobem vytvori jen jednou pri parsovani kodu. Hloupa js implementace by tam mela cisty text tela te funkce, ktery by pri kazdem volani znova parsovala. Tohle snad delaji jen jednoduche skriptovace, u js bych to cekal chytrejsi… BTW v8 kompiluje pri parsovani, alespon to co jsem videl ve webkitu, nestalo se mi, ze bych mohl interpretaci js prochazet nativne pres engine, vzdy to byl strojak.

                  1. Ondřej Žára

                    Re: hm
                    O problematice JIT a AOT ve V8 dobře píšou na http://programmers.stackexchange.com/questions/246094/understanding-the-differences-traditional-interpreter-jit-compiler-jit-interp (poslední odstavec odpovědi). Je otázka, jestli lze považovat nějaký naivně hloupý a pomalý nativní kód za srovnatelný s tím, co následně — právě po zajištění typové stability a dalších podmínkách — vygeneruje JIT.

                    Ohledně sdílení kódu funkcí definovaných v konstruktoru — asi nebude obtížné pro tuto věc vyrobit malý benchmark, který vyrobí milion instancí jedním či druhým způsobem a profiler prozradí něco o zabrané paměti, což?

                2. Ondřej Novák

                  Re: hm
                  jsem ochotnej pripustit ze casove naklady na vytvoreni jednoduchych malych objektu funkci neco skutecne casoove stoji a ze pri prototypovani tento cas usetrim. Otazkou je, zda to ma tu cenu a nevytvori to problemy jinde, treba v tom, ze se musim rozloucit se zapozdrenim (mohu to obchazet podtriztky coz neresi problem kdy potomek pouzije privatni promenne se stejnym jmenem jako predek)

  2. caracho

    if / else
    Koncept if/esle s defaultni vychozi hodnotou, je narozdil od doporucovaneho z hlediska defenzivnoho programovani ten spravny. Kod to zjednodusuje, takze poznamaka o cistlenosti je dost sporna ale hlavne vam pak nehrozi ze pustite dale do vypoctu neinicializovanou promnenou s nepredvidatelnymi nasledky (na coz clanek naopak spravne poukazuje o par odstavcu jinde v pripade retezeni retezcu).

  3. Honza

    Práce v týmu
    Defenzivní programování je pro roboty, ale ne pro lidi. Programování je obvykle týmová práce. Pokud ale chybí vzájemná důvěra mezi členy týmu, a je potřeba defenzivní přístup, mají lidé a firma velký problém.

    1. NoxArt

      Re: Práce v týmu
      To je stejná logika jako že unit testy jsou pouze pro vývojáře, co nepíší dokonalý a zcela bezchybný kód. Firma co testuje má velký problém, deklaruje tím, že vývojáři jsou neschopní…

      1. Honza

        Re: Práce v týmu
        Žádný vývojář nepíše dokonalý a zcela bezchybný kód. Unit testy jsou pro všechny vývojáře. Firma, kde vývojáři píší unit testy má mnohem méně problémů.

        Nicméně pokřivená firemní kultura vývoje, kde se netestuje (případně testy nepíší přímo vývojáři, ale testeři), jde obvykle ruku v ruce s defenzivním programováním.

        1. NoxArt

          Re: Práce v týmu
          „Žádný vývojář nepíše dokonalý a zcela bezchybný kód“ – přesně tak, děkuji :)
          Důvěra je naprosto nesmyslná metrika pro uvažování jestli programovat defensivně nebo ne. Lidé jsou omylní, i ten člověk (ať už je to kdokoli) co napíše test je omylný, takže není důvod zavrhovat přístup který se snaží chyby ještě více minimalizovat.

  4. vm

    ESLint
    Místo JSLint bych doporučil ESLint (http://eslint.org), který se poučil s JSLintu, nabízí pokročilejší analýzu a hlavně skvělou rozšiřitelnost (podpora Babelu, JSX atp). Samozřejmě také nabízí integrace do všech běžných editorů. Jinak neexistuje rozumný důvod, proč ES6 nepoužívat s Babelem už dnes.

  5. Aleš Hájek

    A není nic horšího než udělat toto
    tiskni(text, true); místo tiskni(text, zarovnat); když změníte logiku funkce, a chyba v ní bude v reakci na druhý parametr, tak pokud to bude konstanta, máte ztíženou šanci ji najít. Pokud je to proměnná, která v názvu nese význam, je nalezení chyby a výskytu volání funkce mnohem jednodušší.

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=15306