Postřehy ohledně architektury JavaScriptu

Kit

Re:Postřehy ohledně architektury JavaScriptu
« Odpověď #270 kdy: 30. 08. 2016, 13:03:45 »
Co třeba něco praktického, místo akademických debat?
https://github.com/CRYTEK-CRYENGINE/CRYENGINE/blob/release/Code/CryEngine/CryEntitySystem/Entity.h
nějakých 50 getterů a setterů v jedné třídě... Fakt bych chtěl vidět, jak to zrefaktoruješ, aniž by to stálo výkon nebo přehlednost...

Já tam např. vidím spoustu metod, které berou jako parametr index slotu (nSlot). To by stálo za to schovat třeba pod metodu slots(..), vracející interface, kde by stejné metody již nemusely obsahovat tento index, protože by pracovaly již s konkrétním slotem.
Kód: [Vybrat]
entity->slots(1)->IsSlotValid() místo
Kód: [Vybrat]
entity->IsSlotValid(1)

Tohle je na trochu delší refaktorování. Nejprve bych volání
Kód: [Vybrat]
if (m_slot == -1) {
m_slot = 0;
while (GetEntity()->IsSlotValid(m_slot))
m_slot++;
}
převedl na jednodušší
Kód: [Vybrat]
m_slot = entity->getSlot();který mi dodá první validní slot.

Getter mi zůstal, takže pokračuji. Objekt entity bude obsahovat atribut slot třídy Slot. Třída Slot bude obsahovat metody pro vytvoření, změnu a případně i zánik slotu z nějakého poolu. Pool bude tyto sloty přidělovat.

Vše, co bude užívat metodu entity->getSlot() přesunu do třídy Slot. Takže například hromadu cyklů
Kód: [Vybrat]
for (int i = 0; i < pEnt->GetSlotCount(); ++i)
přemístím do třídy Slots a požadovanou operaci nad všemi sloty injektuji do nějakých metod dle potřeby.

Jak jsem již psal, je to na delší refaktorování, ale výsledkem by byl čistší, kratší, rychlejší, přehlednější a robustnější kód. Podstatné je, aby s atributem m_slot pracovala pouze třída Slot, o správu poolu slotů zase jen kolekce Slots.

... a to je vlastně jen refaktorování jednoho atributu.


Kit

Re:Postřehy ohledně architektury JavaScriptu
« Odpověď #271 kdy: 30. 08. 2016, 13:19:12 »
Posuzování, zda použiju konstruktor nebo setter podle toho, jak ten konsturktor bude dlouhej není programování, ale pohodlnost.

Nie pohodlnost, ale zdravy rozum. Vyplnit kilometrovy konstruktor, tam je trosku o hubu zistit poriadne, co kam ide.
Konstruktor sluzi predovsetkym na konfiguraciu objektu, to ze sa zhodou okolnosti pouziva aj na vytvorenie objeku je vedlajsia vec. Na vytvorenie objektu sa daju pouzit aj rozne factory metody/funkcie.

Jediny dovod konfigurovat vsetko v konstuktore je, ked je potrebny immutable objekt a vsetky fieldy su kvoli paranoji nastavene na filnal. (v jave)

Ja viem, ze som asi uchylny javista, ale bezny workflow je - Instancovat objekt, nakonfigurovat (nainjektovat), pustit init metodu objektu, ked je vsetko vo spravnom stave.  Ak to nerobi uz framework, tak to takto spravim rucne.

Menenie "stavu" objektu by sa nemalo robit cez setter (pokial sa tym mysli nieco viac nez konfiguracia). Ale prihodne nazvanou metodou typu changeKillingState(State.NOT_KILLING)

Co máš pořád s tím kilometrovým konstruktorem? Když má konstruktor obvykle 1-3 parametry, tak takový konstruktor má do kilometru hóódně daleko.

Atributy objektu mohou být finální a často je v této podobě používám. To abych si je náhodou nezměnil. Immutable objekty se hodí pro implementaci vzoru Messenger - nejsou pak potřebné gettery ani settery.

Metodu pro init objektu by měl volat už konstruktor. Neinicializovaný objekt zřejmě nebude validní a je tedy k ničemu.

Místo nevhodného
Kód: [Vybrat]
state->changeKillingState(State.NOT_KILLING)bych raději zvolil mnohem jednodušší
Kód: [Vybrat]
state->noKill()nebo něco podobného.

gamer

Re:Postřehy ohledně architektury JavaScriptu
« Odpověď #272 kdy: 30. 08. 2016, 13:29:57 »
Tohle je na trochu delší refaktorování. Nejprve bych volání

Ty jsi nepochopil, k čemu ty sloty jsou, že? Primárně pro LUA skriptery, kteří si do nich strkají svoje věci. Vyhodit funkcionalitu ohledně slotů do zvlášní třídy na první pohled dává smysl, jenže skripteři to tak používat nechtějí. Oni chtěljí jednoduchý interface s číslem slotu na entitě. Jasně, můžeš tam mít dva různé interface, jeden pro skript a jiný pro C++ engine a mapovat to mezi sebou, ale nic to nepřinese, kód bude delší, složitější a pomalejší. Mimochodem po tom tvém "refaktoringu" by to nebylo ani rychlejší, ani jednodušší.

Kit

Re:Postřehy ohledně architektury JavaScriptu
« Odpověď #273 kdy: 30. 08. 2016, 13:37:27 »
Tohle je na trochu delší refaktorování. Nejprve bych volání

Ty jsi nepochopil, k čemu ty sloty jsou, že? Primárně pro LUA skriptery, kteří si do nich strkají svoje věci. Vyhodit funkcionalitu ohledně slotů do zvlášní třídy na první pohled dává smysl, jenže skripteři to tak používat nechtějí. Oni chtěljí jednoduchý interface s číslem slotu na entitě. Jasně, můžeš tam mít dva různé interface, jeden pro skript a jiný pro C++ engine a mapovat to mezi sebou, ale nic to nepřinese, kód bude delší, složitější a pomalejší. Mimochodem po tom tvém "refaktoringu" by to nebylo ani rychlejší, ani jednodušší.

Proč se vlastně ve vláknu o Javascriptu zabývat jazyky C++ nebo Lua? Víš dobře, že v těch jazycích nedělám a přesto se mě ptáš, jak bych to v nich refaktoroval. Tak jsem ti napsal svůj názor. Ber nebo nechej být, klidně si to dál dělej jak chceš, ale příště sem dej raději příklad na Javascript.

BoneFlute

  • *****
  • 1 988
    • Zobrazit profil
Re:Postřehy ohledně architektury JavaScriptu
« Odpověď #274 kdy: 30. 08. 2016, 13:37:47 »
Gettery a settery su hlavne na to, aby konstruktor objektu nemusel mat kilometer.
To je zase zaměnění příčiny a následku.

Posuzování, zda použiju konstruktor nebo setter podle toho, jak ten konsturktor bude dlouhej není programování, ale pohodlnost.

Konstruktor slouží k tomu, aby se vytvořil objekt.

Setter k tomu, aby se změnil stav objektu z jednoho validního stavu na jiný validní.

To, že v případě rozsáhlejch struktur jsou často většina hodnot volitelná je shoda okolností vedoucí k mylné představě, že settery jsou jen jinej způsob jak plnit objekt daty.

Druhej extrém je Kitova představa, že settery jsou nějakým specielním způsobem vždy špatné.


Posuzování, zda použiju konstruktor nebo setter podle toho, jak ten konsturktor bude dlouhej není programování, ale pohodlnost.

Nie pohodlnost, ale zdravy rozum. Vyplnit kilometrovy konstruktor, tam je trosku o hubu zistit poriadne, co kam ide.
Konstruktor sluzi predovsetkym na konfiguraciu objektu, to ze sa zhodou okolnosti pouziva aj na vytvorenie objeku je vedlajsia vec. Na vytvorenie objektu sa daju pouzit aj rozne factory metody/funkcie.

Jediny dovod konfigurovat vsetko v konstuktore je, ked je potrebny immutable objekt a vsetky fieldy su kvoli paranoji nastavene na filnal. (v jave)

Ja viem, ze som asi uchylny javista, ale bezny workflow je - Instancovat objekt, nakonfigurovat (nainjektovat), pustit init metodu objektu, ked je vsetko vo spravnom stave.  Ak to nerobi uz framework, tak to takto spravim rucne.

Menenie "stavu" objektu by sa nemalo robit cez setter (pokial sa tym mysli nieco viac nez konfiguracia). Ale prihodne nazvanou metodou typu changeKillingState(State.NOT_KILLING)

OK. Nesouhlasím. Zásadně. S ničím.

Můžem se přesunout dál.


balki

Re:Postřehy ohledně architektury JavaScriptu
« Odpověď #275 kdy: 30. 08. 2016, 13:38:57 »
Posuzování, zda použiju konstruktor nebo setter podle toho, jak ten konsturktor bude dlouhej není programování, ale pohodlnost.

Nie pohodlnost, ale zdravy rozum. Vyplnit kilometrovy konstruktor, tam je trosku o hubu zistit poriadne, co kam ide.
Konstruktor sluzi predovsetkym na konfiguraciu objektu, to ze sa zhodou okolnosti pouziva aj na vytvorenie objeku je vedlajsia vec. Na vytvorenie objektu sa daju pouzit aj rozne factory metody/funkcie.

Jediny dovod konfigurovat vsetko v konstuktore je, ked je potrebny immutable objekt a vsetky fieldy su kvoli paranoji nastavene na filnal. (v jave)

Ja viem, ze som asi uchylny javista, ale bezny workflow je - Instancovat objekt, nakonfigurovat (nainjektovat), pustit init metodu objektu, ked je vsetko vo spravnom stave.  Ak to nerobi uz framework, tak to takto spravim rucne.

Menenie "stavu" objektu by sa nemalo robit cez setter (pokial sa tym mysli nieco viac nez konfiguracia). Ale prihodne nazvanou metodou typu changeKillingState(State.NOT_KILLING)

Co máš pořád s tím kilometrovým konstruktorem? Když má konstruktor obvykle 1-3 parametry, tak takový konstruktor má do kilometru hóódně daleko.

Atributy objektu mohou být finální a často je v této podobě používám. To abych si je náhodou nezměnil. Immutable objekty se hodí pro implementaci vzoru Messenger - nejsou pak potřebné gettery ani settery.

Metodu pro init objektu by měl volat už konstruktor. Neinicializovaný objekt zřejmě nebude validní a je tedy k ničemu.

Místo nevhodného
Kód: [Vybrat]
state->changeKillingState(State.NOT_KILLING)bych raději zvolil mnohem jednodušší
Kód: [Vybrat]
state->noKill()nebo něco podobného.


Kód: [Vybrat]
robot.changeKillingState(State.NOT_KILLING)Neviem, co je na tom nevhodne. Je to pekna hodnota z ciselniku, velavravna, explicitna. Netreba mat na kazdy stav metodu.

Kód: [Vybrat]
Metodu pro init objektu by měl volat už konstruktor. Neinicializovaný objekt zřejmě nebude validní a je tedy k ničemu.

Objekt ktory nie je inicializovany (tj nevalidny) by sa nemal pouzivat. Spajat instanciaciu s inicializaciou je zarabanie si na problemy.

BoneFlute

  • *****
  • 1 988
    • Zobrazit profil
Re:Postřehy ohledně architektury JavaScriptu
« Odpověď #276 kdy: 30. 08. 2016, 13:43:51 »
Objekt ktory nie je inicializovany (tj nevalidny) by sa nemal pouzivat. Spajat instanciaciu s inicializaciou je zarabanie si na problemy.
Objekt který je nevalidní by neměl v prvé řadě vůbec existovat.

Naopak. Možnost něčeho takového, tedy oddělovat vytvoření a inicializace objektu je zadělávání si na problémy.

Kit

Re:Postřehy ohledně architektury JavaScriptu
« Odpověď #277 kdy: 30. 08. 2016, 13:51:47 »
Kód: [Vybrat]
robot.changeKillingState(State.NOT_KILLING)Neviem, co je na tom nevhodne. Je to pekna hodnota z ciselniku, velavravna, explicitna. Netreba mat na kazdy stav metodu.

Kód: [Vybrat]
Metodu pro init objektu by měl volat už konstruktor. Neinicializovaný objekt zřejmě nebude validní a je tedy k ničemu.

Objekt ktory nie je inicializovany (tj nevalidny) by sa nemal pouzivat. Spajat instanciaciu s inicializaciou je zarabanie si na problemy.

Metoda pro každý stav je docela výhodná. Umožňuje totiž měnit implementaci, aniž by se o tom okolní svět dozvěděl. Refaktorování takové třídy je mnohem snazší.

V každém konstruktoru mám inicializaci objektu. Konstruktor je krátký, problémy s tím nejsou žádné.

gamer

Re:Postřehy ohledně architektury JavaScriptu
« Odpověď #278 kdy: 30. 08. 2016, 13:53:57 »
Proč se vlastně ve vláknu o Javascriptu zabývat jazyky C++ nebo Lua? Víš dobře, že v těch jazycích nedělám a přesto se mě ptáš, jak bych to v nich refaktoroval. Tak jsem ti napsal svůj názor. Ber nebo nechej být, klidně si to dál dělej jak chceš, ale příště sem dej raději příklad na Javascript.

To není věc jazyka, je úplně jedno, v čem to napíšeš. Vedeš tady svatou válku proti getterům a setterům, ale ony se v praxi používají, protože nikdo zatím nic lepšího nevymyslel. Schválně sem dávám kód velkého projektu, který dělají docela schopní programátořii. A světe div se, getterů a setterů tam mají fakt hodně... Kdybys dělal herní engine, měl bys je tam taky, protože to prostě funguje nejlíp. Bez getterů a setterů by to šlo udělat, ale bude to horší. Jak z hlediska výkonu, tak z hlediska udržovatelnosti kódu. Vzájemných závislostí mezi daty jednotlivých objektů je ve hře prostě přiliš moc, nenajdeš nějaký rozumný průnik. Mimochodem Unreal engine to stejné, taky spousta getterů a setterů:
https://docs.unrealengine.com/latest/INT/API/Runtime/Engine/GameFramework/AActor/index.html

balki

Re:Postřehy ohledně architektury JavaScriptu
« Odpověď #279 kdy: 30. 08. 2016, 13:56:11 »
Objekt ktory nie je inicializovany (tj nevalidny) by sa nemal pouzivat. Spajat instanciaciu s inicializaciou je zarabanie si na problemy.
Objekt který je nevalidní by neměl v prvé řadě vůbec existovat.

Naopak. Možnost něčeho takového, tedy oddělovat vytvoření a inicializace objektu je zadělávání si na problémy.

Objekty v nevalidnych stavoch existuju uplne bezne aj po inicializacii v konstruktore. (Nieco sa nepodari tak ako ma, kvoli vonkajsim vplyvom) Taky objekt je mozne zahodit a spustit znova drahy proces instanciacie, alebo je mozne ho znova nakonfigurovat a pustit init metodu.  Od smalltalku to tak funguje ze je oddelena instanciacia a inicializacia.

Zavrhov

Kit

Re:Postřehy ohledně architektury JavaScriptu
« Odpověď #280 kdy: 30. 08. 2016, 13:58:42 »
Proč se vlastně ve vláknu o Javascriptu zabývat jazyky C++ nebo Lua? Víš dobře, že v těch jazycích nedělám a přesto se mě ptáš, jak bych to v nich refaktoroval. Tak jsem ti napsal svůj názor. Ber nebo nechej být, klidně si to dál dělej jak chceš, ale příště sem dej raději příklad na Javascript.

To není věc jazyka, je úplně jedno, v čem to napíšeš. Vedeš tady svatou válku proti getterům a setterům, ale ony se v praxi používají, protože nikdo zatím nic lepšího nevymyslel. Schválně sem dávám kód velkého projektu, který dělají docela schopní programátořii. A světe div se, getterů a setterů tam mají fakt hodně... Kdybys dělal herní engine, měl bys je tam taky, protože to prostě funguje nejlíp. Bez getterů a setterů by to šlo udělat, ale bude to horší. Jak z hlediska výkonu, tak z hlediska udržovatelnosti kódu. Vzájemných závislostí mezi daty jednotlivých objektů je ve hře prostě přiliš moc, nenajdeš nějaký rozumný průnik. Mimochodem Unreal engine to stejné, taky spousta getterů a setterů:
https://docs.unrealengine.com/latest/INT/API/Runtime/Engine/GameFramework/AActor/index.html

Příště si raději vyber příklad, který je napsán objektově.

gamer

Re:Postřehy ohledně architektury JavaScriptu
« Odpověď #281 kdy: 30. 08. 2016, 14:04:40 »
Příště si raději vyber příklad, který je napsán objektově.

Aha, takže odtud vítr vane... Oni vlasně autoři herních enginů nepíšou objektově. Chybí jim Kit, který jim to správné "objektové" programování vysvětlí...

Kit

Re:Postřehy ohledně architektury JavaScriptu
« Odpověď #282 kdy: 30. 08. 2016, 14:13:11 »
Příště si raději vyber příklad, který je napsán objektově.

Aha, takže odtud vítr vane... Oni vlasně autoři herních enginů nepíšou objektově. Chybí jim Kit, který jim to správné "objektové" programování vysvětlí...

Píší imperativně, protože mají představu, že jim to zvedne výkon toho enginu. Tak jim to necháme, ne?

balki

Re:Postřehy ohledně architektury JavaScriptu
« Odpověď #283 kdy: 30. 08. 2016, 14:16:08 »
Příště si raději vyber příklad, který je napsán objektově.

Aha, takže odtud vítr vane... Oni vlasně autoři herních enginů nepíšou objektově. Chybí jim Kit, který jim to správné "objektové" programování vysvětlí...

Autory hernych enginov nepisu objektovo, lebo je to pomale. Preto sa uz nejake to destrocie razi multiparadigmovy vyvoj ako "zlata stredna cesta".  Tym sa zaoberal Jim Coplien https://www.amazon.com/Multi-Paradigm-Design-C-James-Coplien/dp/0201824671 (teraz robi scrum.)

BoneFlute

  • *****
  • 1 988
    • Zobrazit profil
Re:Postřehy ohledně architektury JavaScriptu
« Odpověď #284 kdy: 30. 08. 2016, 14:16:31 »
Objekt ktory nie je inicializovany (tj nevalidny) by sa nemal pouzivat. Spajat instanciaciu s inicializaciou je zarabanie si na problemy.
Objekt který je nevalidní by neměl v prvé řadě vůbec existovat.

Naopak. Možnost něčeho takového, tedy oddělovat vytvoření a inicializace objektu je zadělávání si na problémy.

Objekty v nevalidnych stavoch existuju uplne bezne aj po inicializacii v konstruktore. (Nieco sa nepodari tak ako ma, kvoli vonkajsim vplyvom) Taky objekt je mozne zahodit a spustit znova drahy proces instanciacie, alebo je mozne ho znova nakonfigurovat a pustit init metodu.  Od smalltalku to tak funguje ze je oddelena instanciacia a inicializacia.

Zavrhov

Požádal bych o lepší argument.

Nekvalitní kód se také objevuje zcela běžně. A důvodem není to, že by to nešlo napsal lépe, ale pouze takové přízemní věci, jako nezkušenost, legaci, good-enought. Domníval jsem se, že se tu bavíme o tom, co je správně, ne o tom, jak se to dá zbastlit.

Pokud se konstruktoru nepodaří vytvořit validní objekt, tak chcípne. Volající má na starost sehnat všechno co konstruktor potřebuje/deklaruje (vnější vliv) aby byl spokojený.

Jestli budeš vytvářet drahý konstruktor, nebo drahou inicializaci, to máš fuk. Toto je obyčejný cargocult. Pokud narážíš na C++, nebo Javu a na alokaci paměti, když se nepovede inicializace, tak máš úplně jiné starosti, než honit bajtíky.

Pohledem do historie můžeme pozorovat, že konstruktor byl vymyšlen právě proto, aby se část alokace (malloc) sloučila s částí inicializací. Nevím, proč bych v moderních jazycích měl psát hůř než v plainC.