M.Lempera: Proč pro mě Angular není správná volba rubrika: Programování: JavaScript

7 mjonas4356
položil/-a 23.11. 13:27
 
upravil/-a 23.11. 13:58

Ahoj,

na blogu Milana Lempery mně zaujal tento článek https://blog.lempera.cz/2019/11/proc-pro-me-angular-neni-spravna-volba.html

Angularu se věnuji od verze 1.5, jedna aplikace mi běží na Angular.JS 1.7, druhá jede na Angularu 8. Počáteční nadšení z přechodu z Angular.JS na Angular už vyprchalo a v hlavě mi zůstává spousta otazníků. V článku jsou popsány velmi přesně problémy, se kterými se také potýkám.

Ať už to je RxJS - nikde není srozumitelně popsáno jak správně číst data pomocí HttpClienta a ošetřovat chybové stavy. Na internetu je spousta tutoriálů a v každém je to řešeno úplně jinak. Nakonec jsem skončil u async/await :-(

Change detection - používám Cordovu pro mobilní aplikace, kde používám pluginy v Javě, dost často se mi stávalo, že po dokončení kódu pluginu se nepřekreslil stav komponent, nakonec jsem začal používat this.applicationRef.tick(); což mi připomnělo staré časy s Delphi a Application.ProcessMessages()

Reaktivní formuláře - na první pohled to vypadá úžasně, mám jeden FormGroup, ve kterém je vnořeno 15 FormGroup a 3 FormArray, je tam CustomValidation. Vše funguje perfektně. Bohužel u reaktivních formulářů nelze použít atribut disable přímo v HTML šabloně, ale v kódu dát this.mujForm.get('mojePolozka').disable(); Napsání vlastní direktivy na disabled bohužel neřeší případy, kdy máte komponenty od třetích stran a ty pak nefungují jak by měly (např. PrimeNg)

Velikost aplikace - produkční aplikace má vendor.js o velikosti 2,5MB (AgGrid + PrimeNg) + aplikace má 1,8MB. Je tam zapnuté AOT, kompilace pouze pro es2015. To už mi přijde poměrně hodně.

Nyní připravuji napsání nové aplikace a jsem před rozhodnutím jestli na frontend použiji Angular 8 nebo něco jiného (React, Vue).

Co je pro Vás ta správná volba?

odkaz
10 vit.herman
odpověděl/-a 25.11. 1:58

Je na čase skoncovat s falešnou relativizací a takovým tím alibistickým "každému vyhovuje něco jiného". To je v tomto případě jen báchorka pro nerozhodné a nezkušené, když je nechci rozčílit, a dobrá ledatak do debat o tom, zda je hezčí modrá nebo červená barva. Teď musí jít pokora stranou, sorry.

Z populárních technologií je dnes jednoznačně nejlepší základem TypeScript + React (dokonce v tomto pořadí důležitosti). Starý AngularJS je beznadějně naprosto zastaralý a návrhově zcela špatný (svého času to bylo maximum možného). K novějšímu Angularu se vyjadřovat nebudu, protože jsem v něm nic nenapsal. Ale mám pocit, že jeho popularita je založena na falešném slibu, že mít jeden komplexní framework je super. Tisíckrát není. Je to ohromný vendor a technology lock. Jsem ochotný se lockovat k TypeScriptu, protože dává smysl prakticky přesně všude tam kde plain JS. I v tom Reactu mám jen relativně tenkou (byť tvoří vysoký objem) view vrstvu, kterou ale řeší bezezbytku excelentně, tj. efektivně, jednoduše a skrz TSX šablony plně typovaně. Maximum logiky aplikace mám v plain TS modulech, zcela vyčleněno mimo React komponenty a obvykle zcela nezávisle na jakémkoli frameworku. Takový přístup zaručuje dlouhou životnost a hlavně srozumitelnost kódu po dlouhá léta.

Komentáře

  • mjonas4356 : To použití TypeScriptu a Reactu mně zajímá - z Angularu 8 jsem zvykl na TSLint a poměrně přísné sledování pravidel v kódu. Prakticky nikde nemám typ any. Otázka je jestli použitím React + Redux + Typescript si do budoucna opět nepřidělám problémy. 25.11. 9:06
  • vit.herman : mjonas4356: Troufám si tvrdit, že si touto kombinací problémy nepřiděláš. Naopak ještě více podpoříš typovost právě tím, že s Reactem nepoužíváš žádný jiný paralelní a potenciálně netypový jazyk pro šablony (direktivy zapsané jako atributy HTML). Mlhavě jsem četl, že Angular obsahuje něco jako typové šablony. Možná ano, ale moc o tom nevím. Ale třeba použití direktiv - pokud vím - typovat moc nelze, protože se používají jako stringy. A takovýchto slabých míst má React podstatně méně, protože je postaven jen na JavaSscriptu, funkcích a třídách. Místo aby přidával paralelní jazykové konstrukce, využívá JavaScriptu (TypeScriptu). TSX je jen syntaktický cukr nad TypeScriptem, tedy i pro šablony stačí ekosystém TypeScriptu včetně TSLintu. Toto je právě čistě pragmaticky obrovský benefit. A to nemluvím o strmější učící křivce, protože jde v podstatě jen o library řešící pouze UI vrstvu. Různé další aspekty jako celková struktura aplikace zůstává na Tobě a je celá řada voleb. Neobsahuje třeba httpClienta, nevnucuje DI architekturu, atd. Naopak si pro každý účel můžeš technologii volit a tím postupně vylepšovat své postupy. Angular je navržen s opačnou filozofií vše v jednom. Což se může zdát pěkné jen z toho důvodu, že chci návod od A po Z pro všechno za cenu výrazně ztížené postupné evoluce. Celkově architektura s "počůraným" HTML (Angular, ale i Vue) může být zajímavá pro HTML kodéra, pro něhož není JavaScript (TypeScript) stěžejní nástroj. Pro nás core programátory to je spíše přítěž. Jo a Redux bych Ti také rozmluvil. Snadno bys mohl být zklamán i oproti Angularu. Alespoň ze začátku je lepší ho neřešit vůbec. Já používám vlastní global state management library na 40 řádků kódu, která má podobnou architekturu jako Redux, ale s několikanásobně menším boilerplate, což je velký problém Reduxu, který by mohl dojem z celého Reactu rychle zkazit... 25.11. 9:50
  • Mlocik97 : Táraš nezmysli... vit.herman 25.11. 13:16
  • vit.herman : @Mlocik97: Měl bys přestat být tak odrzlý, vzhledem k poměrně nedávným dotazům, kdys potřeboval pomoc s Node.js v úplných základech... 25.11. 13:53
  • Mlocik97 : Node.js je serverside, sú tu niektorý ktorý pracujú s clientside roky a serverside sa ešte nedotkli. Chceš ich ale označiť za hlupákov a že nič nevedia o clientside? 25.11. 14:01
  • vit.herman : @Mlocik97: Hlupáka děláš ze sebe akorát svou drzostí. Ne tím, že něco nevíš. I já bych byl radši, kdybys to co píšu přijal pozitivně a pomohlo by Ti to ve výběru frameworku. A vůbec nejradši bych viděl, jak si sám přijdeš na to, že to cos možná nesnášel je nakonec opravdu hodně dobré, a že Ti to opravdu pomohlo zefektivnit vlastní vývoj. Ale dlouhou praxi i nastudovanou terorii nelze jednoduše předat. Pokud tedy chci pomoci někoho nasměrovat, nemá smysl psát, že pro každého je dobré něco jiného a pro každý účel něco jiného. Co si z toho asi tak může vzít? Člověk ve skutečnosti dokáže posoudit jen to, co zkusil a až po dlouhé době praxe dokáže předem hodnotit na základě principiálních východisek jednotlivých řešení, která si již mohl dovolit díky praxi dostatečně zobecnit. Takže když se někdo ptá, tak já mu odpovím, co vím. On to přijme nebo ne. Já budu rád, pokud pomůžu. 25.11. 14:56
  • Taco : @vit.herman: co máš proti DI? 25.11. 21:02
  • harrison314 : @vit.herman: zaujimalo by ma, ako ty robis SPA aplikacie. 26.11. 7:14
  • vit.herman : @Taco: Přišel jsem na to, že DI ve své fundamentální podstatě přináší hodnotu v daleko menším počtu use cases, než jak bývá prezentováno. Avšak má svůj hodně nezanedbatelný boilerplate. Alespoň v C#/.NET business aplikacích, tak, jak vypadaly ve firmě, kde jsme měli na DI architektuře projekty stavěny. DI kontejner je dynamická záležitost. Nelze tedy v čase kompilace ověřit, že závislosti jsou resolvovány, a že správně. Uvědomil jsem si, že dynamické resolvování závislostí má smysl buď v případě, že nemám nebo nechci mít přístup ke zdrojovému kódu (tedy typicky objektové frameworky), a nebo, pokud je třeba umožnit definici závislostí dynamicky tak, aby to mohl nastavovat třeba zákazník (plug-in architektura). Avšak naše koncové aplikace jsou postaveny na automatickém deploymentu přímo ze zdrojových kódů, kolem kterých se vše pohybuje. I konfiguraci zákazníkovi spravujeme my. A proto je výhodné se této dynamičnosti pro běžnou business vrstvu v zakázkových aplikacích (existuje obvykle jedna instance + nějaký test a stage) vzdát ve prospěch statických závislostí. Sníží se boilerplate a závisllosti jsou ověřeny kompilátorem => aplikaci považuji za bezpečnější. U nás ve firmě pak zbývalo dokázat, že plné testovatelnosti lze dosáhnout i jinak, a to vždy dostupnou dekompozicí jakékoli funkce metody na interní pure funkci/metodu a na metodu, která ji volá a zároveň dodává závislosti. Tu pure funkci/metodu lze vždy testovat a dodat jakékoli třeba fake závislosti. Ve své podstatě se jedná o injection na daleko nižší úrovní internal metod/funkcí. Je třaskavé téma prezentovat, že DI je ve většině zakázkových aplikací více přítěží než užitečnou technikou. Mám o tom i svou prezentaci, kterou jsem dělal pro interní tým, a která jde do detailů. Naopak přirozeným use casem pro DI architekturu jsou objektové frameworky. Vysvětluji tedy, abychom odlišovali kódovou základnu frameworku a jeho infrastrukturních záležitostí, kde je DI dobrá technika. Ale zároveň dodávám, že je velmi výhodné nepoužívat stejnou techniku pro zakázkový kód, pro který je nastaven efektivní proces změny a nasazení na úrovni zdrojového kódu. 26.11. 8:48
  • vit.herman : @harison314: Jádrem jsou moduly v TS. Pro typickou webovou aplikaci má obvykle každá stránka svůj modul. Vše je modelováno moduly. Tedy například každá stránka se skládá z modelu (modulu), React komponenty, která je skutečně jen view navázaný na daný modul a sady stylů specifických pro stránku. Moduly jsou moduly v tom nejběžnějším slova smyslu, co modul v TS znamená. Avšak důležitá specialita: Všechny stavové záležitostí jsou externalizovány do immutable stavu a bindovány na React komponenty. Víceméně využívám nejčastěji globální stav, který je bindován na root komponentu Reactu. Krom stránek existují různé systémové moduly, jako např. pro autorizaci, pro formuláře s validacema, pro standardní seznamy. Opět vše s externalizovaným immutabilním stavem. Pro práci se globálním stavem netřeba žádné knihovny (ani Redux), hlavním nástrojem immutability je spread operátor jakožto součást TypeScriptu. Díky této architektuře je zamezeno peklu složitých propagací vlastností napříč hierarchií komponent. Každá komponenta může přistupovat k jakémukoli modulu a v komponentách samotných není žádná logika aplikace. Komponenta tedy plní pouze funkci šablony a místa pro navázání událostí na funkce modulu. Příliš nestojím o to, aby logika aplikace byla jakkoli zadrátována do React komponent. S moduly se pak dá pro testování pracovat i zcela bez React vrstvy a zcela bez závislosti na Reactu. Ale hlavně to nejcennější - logika aplikace - nemá žádnou závislost na jakémkoli frameworku. Tyto bussiness moduly jsou závislé na vlastních abstrakcích (httpRequest, formatting a mnoha dalších). Až tyto abstrakce implementují svou funkčnost přes dodané a stažené moduly. Hlavní zásadou je nezávislost cenné business logiky na konkrétním frameworku a konkrétních stažených modulech. Je marginalitou, že zvenčí to je ovládáno Reactem a buildováno webpackem, apod. Hlavním rozdílem oproti řešení na Angularu je, že mám vše plně pod kontrolou a využívám knihovny, a ne že to řídí framework. Nevyužívám tedy IoC,a tím jsem ušetřen veškeré magie, popřípadě mám nad ní plnou kontrolu. Jo a jinak za největší devizu považuji TypeScript a umět ho opravdu do hloubky. Snažím se o takovou míru typové bezpečnosti, aby run-time chyby byly prakticky vyloučeny. Což opravdu mimořádně pěkně funguje. Pokud bych si třeba vybíral programátora k sobě, tak by ani dosavadní neznalost Reactu nebyla překážkou. Ale hlavně je potřeba krom obecné algoritmizace, analytického způsobu myšlení umět JavaScript/TypeScript a to fakt do hloubky. To ostatní se dá snadno a rychle doučit. 26.11. 9:20
  • Kit : @vit.herman: Na DI nevidím žádný boilerplate. Snad jen několik řádek rozhraní, ale to je zanedbatelné. 26.11. 9:41
  • mazane : @vit.herman: Jak je myšleno to "hlavním nástrojem immutability je spread operátor". Jde ho použít nějakým způsobem, aby mi zajistil "klonování" objektů? 26.11. 10:03
  • vit.herman : @Kit: Kite, ale ty děláš v PHP, ne? Já píšu o reáliích na .NET platformě 26.11. 10:31
  • vit.herman : @mazane: Klonování (deep copy) zajistit nedokáže. U imutabilních struktur je ale žádoucí, aby nešlo o klony, ale aby se reference sdílely. A sdílet se můžou právě proto, že jsou struktury imutabilní. Pokud by se nesdílely, bylo by to paměťově extrémně neefektivní, až nepoužitelné 26.11. 10:36
  • mazane : @vit.herman: Já právě nerozumím tomu, jak pomáhá spread operátor tomu, aby to bylo imutabilní. Jaký je rozdíl mezi foo(acko,becko) a foo(...[acko,becko])? Pokud jsou acko a becko objekty, tak je jejich obsah stejně měnitelný, ať už jsou předány přes spread nebo nebo normálně. Nechci nic vyvracet, chci to pochopit. 26.11. 10:51
  • mazane : @vit.herman: Tak už asi vím, kdy to může pomoct. Můžu napsat foo(ar: number[]) { ar.splice(1,1); }, ale nemůžu to napsat ve foo(a1, a2: number). A přitom to vždycky volám na stejné pole, akorát v druhém případě se spread operátorem. Takhle to bylo myšleno? 26.11. 11:01
  • vit.herman : @mazane: jj, v pohodě. typický příklad je spíše, že JS objekt modifikuji takto: foo = { ...foo, field1: xxx } místo foo.field1 = xxx. Měl jsem tedy na mysli použití spread operátoru pro kompozici nového objektu na základě předchozího. A to, aby nešlo třeba omylem do objektu zapisovat zajistím jeho typem, kde veškeré properties jsou readonly 26.11. 11:14
  • vit.herman : @mazane: splice() modifikuje pole "na místě", pro imutabilní struktury je tedy nepoužitelná. Prvek lze immutabilně přidat takto: pole = [...pole, newItem] nebo odebrat takto: pole = pole.filter(i => i.id == idToRemove) nebo modifikovat: pole = pole.map(i => ( {...i, field1: i.field1.id == idToModify ? newFieldValue : i.field} )) 26.11. 11:25
  • Kit : V Javě je DI úplně stejně jednoduché. Nevidím důvod, proč by to mělo být na .NET složité a proč by tam měly být nějaké boilerplates jako třeba v Service Locator, který vypadá hnusně. 26.11. 11:53
  • Mlocik97 : @vit.herman k tomu včera o 14:56 lenže tys tu začal s argumentami o mojich dotazoch na node.js takže... inak názor ti neberem, len ako tys bral môj.... inak chcel si argumenty, tak tých je mnoho... JSX je úplne antiMVC antipattern, je to presný opak toho čo bys v aplikácii chcel,... JSX ta navádza k tomu abys miešal HTML a JS dokopy, abys miešal dáta, view, a logiku aplikácie dokopy, z čoho pak je pekný guláš... dajme tomu z pohladu CSS experta že prijde do dopolovice rozrobeného React projektu, kde nemá znalosť o tom akou logikou bola navrhnutá štruktúra projektu. Když máš HTML propreplietaný skrz JS, myslíš že to pomôže takémuto expertovi? Myslím že nie. A o tom že musíš čítať mnoho kódu abys pochopil jednu funkcionalitu nehovorím. Druhá vec je závislosti, áno ani Angular (či aj starší AngularJS) to neriešia úplne, ale podľa mňa je to horší problém v nich ako v Reacte. Ďalej React má horšiu syntax. Ostatne ber to ale ako môj názor. Aj keď sa musí dať za pravdu že u AngularJS bol problém výkon toho že všetko bolo permanentne sledované na zmeny. Angular to ale ceľkom vyriešil, nie úplne ale podľa mňa je to v pohode. 26.11. 12:51
  • vit.herman : @Mlocik97: Míchat to nemusíš, když nechceš. Ano souhlasím, že šablonovací systém Tě k tomu (a hlavně třeba nepořádné kolegy) může donutit, kdežto JSX ne. Ale když to nemícháš, není problém. Na oplátku máš v šabloně celou sílu JavaScriptu/TypeScriptu. Velmi dobrý trade-off. Takže logiku míchanou s view nemám a přesto spokojeně využívám TSX. Díky tomu splňuji i další požadavky, o kterých píšeš. Dodržuji programátorskou disciplínu, vedu k tomu intenzivně kolegy a komunikuji o tom jak věci dělat lépe, děláme review. Tím zajišťuji disciplínu v kódu raději na úrovni programátorů než na úrovni barikád v systému. Zbytečným chybám brání automaticky TypeScript a silné typování všeho, co máme. Používáme asi jen tři TSLint pravidla. Každé pravidlo musí jít snadno porušit, dává-li to smysl. To je základ efektivního vývoje, možnost zkoušet lecos a posouvá nás i programy rychle dopředu. K Angularu: Máš plné právo upřednostňovat syntaxi šablon Angularu, to je subjektivní záležitost, beru. Ale objektivně je z praktického hlediska výborná myšlenka JS/JSX/TS/TSX všude. Jde o jeden jazyk a kdo zná výborně JavaScipt, zná hned i šablony. Můžu po programátorech pak chtít pouze hlubokou znalost JavaScriptu a TypeScriptu a nic víc. Další znalosti lze pak snadno doplnit. A když se i po letech mrkneš na kód, lépe do něho pronikneš. Syntaxi Angularu spíš zapomeneš, pokud zmizí z mainstreamu. U JS/TS rodiny je naděje na ještě dlouhý život. A React je ve své podstatě až nechutně triviální v běžných scénářích. A ano, výkonové problémy s konvergencí stavu jsou v Angularu údajně vyřešeny a já to beru. Jsem si vědom, že kodérům HTML + CSS může být blíže Angular. Ale orientuji se zejména na kvalitní architekturu aplikace. HTML + CSS je jen součástí UI vrstvy a proto nemůže určovat technologii jádra nebo framework. 26.11. 13:32
  • mazane : @vit.herman: Přesně tak. Proto jsem ho právě uvedl jako příklad toho, před čím by mě použití spread operátoru mohlo ochránit, ale byl jsem vedle. :) Spread operátor je v tomto případě použit pro přidání/změně vlastnosti do objektu tak, aby se vytvořil nový a starý se zahodil a v tom je to immutable. To je elegantní řešení. K tomuto jsem se potřeboval dopátrat. Díky ;) 26.11. 15:02
  • vit.herman : @Kit: Důvody jsem podrobně popsal. Pokud vím, v Javě jsou podobné. Nelze to nevidět, lze to jen neakceptovat. A to už je každého věc. Kdo je na DI již zvyklý a má osobní zkušenost, že ho to dost posunulo, bude mít samozřejmě psychologickou bariéru uvěřit tomu, že to jde jinak, jednodušeji a bezpečněji... 26.11. 14:58
  • vit.herman : @mazane: Rádo se stalo :-) Je to přesně jak píšeš. A na pozadí se díky referenční transparenci (to znamená nemožnosti reálně zmodifikovat strukturu) ty struktury nekopírují, ale sdílejí, dokud na ně existuje kdekoli odkaz. A to platí i pro části těch struktur. V tom tkví to kouzlo. A díky těmto immutable strukturám dokážeš rozpoznat změnu jen na základě porovnání referencí a nemusíš dělat rekurzivní porovnávání hodnot. A toho využívají reaktivní knihovny jako React. Toto používání spread operátoru se zpočátku může zdát složité. Zápis je přece jen složitější, než pole.add(), pole.remove() Ale nakonec mi to přišlo stále nejelagantnější, protože při používání specializovaných immutable knihoven narážíš na problém potřeby stálého převádění mezi klasickými typy a immutable typy úplně všude. Což dost zaneřádí kód. Tedy zelegantníš operace, ale musíš přidat hodně kódu, stává se se to celé závislé na konkrétní knihovně (to je ale to nejmenší) a třeba immutable.js minimálně donedávna neměla podporu pro TypeScript. 26.11. 15:12
  • mazane : @vit.herman: Ohledně té DI, dekompozice funkce a její obalení funkcí, která jí ty závislosti dodá. To zní dobře, ale nejsou pak ty definice závislostí pak moc rozházeny po těch obalovacích funkcích? Mě vcelku vyhovuje předávání závislostí konstruktorem a pak v nějakém konfiguráku akorát definuji instance odpovídající typům parametrů v konstruktorech a factory na vytváření instancí, kam se doplní závislosti automaticky podle konfiguráku. Mám pak ty závislosti definovány všechny na jednom místě a pak se o ně už nestarám. Přijde mi to tak lepší, ale nerad bych něco přehlédl kvůli psychologické bariéře. :) Možná když se bavíme o Reactu, tak jsem zaslechl, že jsou tam prý mnohými považovány třídy za nepřehledné a píší jen funkce bez tříd. A bez tříd není konstruktorová DI. 26.11. 15:19
  • pudr : @Mlocik9 Neblábol. Stačí si přečíst tvé příspěvky tady nebo na rootu a je jasné, že buď trpíš mladickou prostořekostí nebo stařeckou demencí. 26.11. 15:41
  • Mlocik97 : mám 22 let, takže to je asi tá prostořekost... 26.11. 15:45
  • pudr : @Mlocik9 Já to chápu, napsal jsem to dost příkře. Ale až budeš o 10 let starší vzpoměň si na to, až ti někdo bude psát od boku svoje dojmy. 26.11. 18:17
  • mjonas4356 : @Mlocik97: Angular.JS měl velké problémy s výkonem, Angular verze 8 je na tom trošičku lépe, na normálním PC. Jakmile pustíš aplikaci s formulářem, kde je celkem 150 editačních prvků, na tabletu za 4000 Kč začneš přemýšlet co ořezat nebo upravit, aby to běželo rychleji. Nakonec jsem v tabletové verzi aplikace musel místo komponent pro formuláře dal nativní . Teď zkušebně převádím aplikaci na Angular 9 rc3, už jsem nad tím strávil dva dny, ne všechno je problém s Angularem samotným, něco je v AgGridu a pár drobností v PrimeNG. 26.11. 18:24
  • vit.herman : @mazane Ano, máš pravdu s tím rozházením dependecies. Ale jinak konfigurace používáme také. Jen se jedná spíše o datovou strukturu klíčů a hodnot a nikoli tříd. Konfigurace jako API klíče, e-maily a desítky dalších jsou normálně centralizovány v konfiguráku. Ale dependencies jsou úplně klasicky statické. Dnes je to sprosté slovo, protože takovou funkci/třídu nemůžeš jednoduše reusovat beze změny zdrojáku v jiné aplikaci. Tento resuing je to, v čem je DI pro objektovou architekturu jedinečné a nenahraditelné. Z toho vyplývá, že pokud architektura není principiálně objektová (což se týká všech běžných business aplikací) a pokud je kód specifický pro jednu aplikaci, přestává mít binární přenositelnost význam a naopak se výhodou stává statická kontrola závislostí. A protože svět už pomalu střízliví z OOP paradigmatu jako toho jediného nejlepšího pro všechny účely, a protože spravujeme obvykle aplikace až po fázi nasazení, můžeme naopak těžit z dříve ztracených výhod statických závislostí. Pro inspiraci: OOP se ukazuje jako velmi vhodné třeba v počítačové grafice, v některých aplikacích umělé inteligence. Pro bussines aplikace OOP nedává úplně smysl, protože v nich jde především o data a procesy. Pro UI rendering vrstvu je zase nejpřirozenější funkcionální paradigma. Jen pro malou část, a to pro UI modelování je OOP vhodné a využitelné. Tím padá nutnost postavit architekturu na DI, protože pokud nejsou třídy, ale jen funkce, lze použít tu dekompozici na pure a public funkci. Třídy jsou jen statické kontejnery a mají význam modulů. Vím, že to všechno zní extrémně, ale není nad pocit pochopit, kolik toho vlastně nepotřebuješ a kterak to urychlí vývoj, a nebo se můžeš soustředit na jiné také zajímavé věci, ale s vyšší přidanou hodnotou :-) 26.11. 18:46
  • Kit : @vit.herman: Nepleteš si DI s DIC, v kterém je těch bojlerplátů docela dost? Samotné DI kód nepřidává, ale spíš ubírá a zjednodušuje. 26.11. 20:09
  • skliblatik : @vit.herman Co máš přesně na mysli tím boilerplate Reduxu? Ptám se proto, že po té, co jsem nasadil typescript (a chvíli s tím zápasil) mi došlo, že nepotřebuji action creatory a ani definovat typy akcí jako konstanty (typescript mi pohlídá literály). Pak už mi to jako odpudivé boilerpate tak moc nepřijde - otypuju globální stav, otypuju akce (a udělám globální union) a napíšu reducery. Pravda je, že je to moje osobní tendence posledních let dávat přednost explicitnímu, hloupému kódu před super-stručnými zkratkami, u nichž má čtenář tendenci tušit a hádat. 26.11. 20:37
  • Taco : @vit.herman: docela by mne zajímala ukázka nebo popis projektů na kterých děláš. Protože, hmm, jak může být DI dynamický? DI se u objektového kódu skloňuje proto, páč to u něj není samozřejmost. Zatímco u funkcionálniho kódu (natož pure funkce) je to jeho inherentní součást. Psát funkcionálne a přitom nectít DI princip nejde. Jak tedy vypadá objekt s dynamickým DI? Jak to mám chápat? 26.11. 21:09
  • vit.herman : @Kit: Myslím, že nepletu 26.11. 21:17
  • vit.herman : @skiblatik: Jsou techniky, kterak se i Redux dá zjednodušovat. Pořád zbývá třeba definice explicitních akcí. Má to své výhody pro některé případy, hlavně pro sofistikované zpracování streamů akcí (skutečné reaktivní programování). Já toto ale v běžných aplikacích nepotřebuji skoro nikdy nebo ve velmi jednoduché podobě. Bohužel Redux je mainstreamem tlačen na základě převládajícího chybného argumentu, že jeho hlavním úkolem je global state management. Pravdou je, že pokud jde jen o toto, lze to řešit jednodušeji. Aplikace v Reduxu jsou akademicky krásné a dají se tvořit velice sofistikované věci. Dobrým důvodem pro Redux pak jsou existující middlewary, které využívají právě streamu akcí. Ale z praktických důvodů, hlavně kvůli produktivitě jsem zatím nenašel důvod to skutečně potřebovat pro takové ty běžné zákaznické aplikace typu admin rozhraní nebo přiměřené obyčejné SPA weby. Potřebuji pouze cyklus event -> zavolání funkce na modelu -> aktualizace glob stavu -> reaktivní překreslení UI. Stačí tedy plain TS, drobná vlastní knihovnička (40 řádků kódu) pro bind glob stavu na react a mám většinu výhod Reduxu bez Reduxu. Funkci reduceru, akce i action creatoru tak plní pouze jedna funkce, která může vykonat klidně i další věci a nemusí být pure. Vše okolo uživatelské akce je tak na jednom místě a nakodováno v pořadí, v jakém se to vykonává. Samozřejmě se tím zříkám automatické možnosti kompozice takových funkcí (lze vždy refaktorovat, aby to šlo), zříkám se zpracování akcí ve streamu a tedy všech middlewarů a toolingu okolo Reduxu. Jinak je to ale neuvěřitelně dobrá studnice pro inspiraci a výuku zajímavých funkcionálních konstrukcí. Na to ale mám rád úplně jiné hračky :-) 26.11. 21:54
  • vit.herman : @Taco: Uvedu na pravou míru. Ano, psát funkcionálně a nectít DI nejde. V tomto smyslu ho ctím. Vždyť i v mém popisu svým způsobem DI používám pro funkce. Pokud funkci dekomponuji na pure a na tu, která závislosti dodá, tak o co jde jiného, než o DI? Možná jsem se skutečně vyjádřil nepřesně a spíše kritizuji DI kontejnery, non-sense použití OOP a v té souvislosti contructor injections. A toto je výsostně dynamická záležitost. Opravdu jsem psal o jednom use casu, který se často školí, hodně využívá, a určitě je chyba zobecňovat konkrétní architekturu na celé DI. Za to se omlouvám, pokud tím matu. 26.11. 22:02
  • skliblatik : @vit.herman Rozumím tvému tradeoffu a je mi sympatický, i když mi ten zisk nepřipadne tak zásadní. Je tam i zřeknutí se obecně rozšířeného přístupu ve prospěch vlastního řešení - což může být někdy na překážku spolupráce (zvlášť když se objeví ona potřeba "refaktorovat, aby to šlo"). Mimochodem, opomněl jsem, že další věc, která boilerplate reduxu zmenšila a zpříjemnila práci s ním je např. hook useDispatch. Díky za odpověď. 26.11. 22:47
  • Taco : @vit.herman: OK, tak to pak jo. To pak nejde o žádné třaskavé téma. Nepoužívat DIC je úplně v pohodě. Možná trocha práce navíc, někdy možná ne. Ale nepoužívat DI, to už je horší, protože z toho potom lezou strašně hnusný věci. *** Ale obávám se, že to s tou dynamičností furt nevim. Mě se ještě nestalo, že by bylo vytváření grafu závislostí (aka DIC) nějak dynamické. Stalo se mi, že jsem musel "automatoru" pomoct, aby mi tam přiřadil to co chci, ale tu dynamičnost tam nějak nevidím. Když upřesníš jak to myslíš, budu rád. 26.11. 22:56
  • vit.herman : @skliblatik: Tyto věci jsem dlouho a pečlivě vážil. Má zkušenost z firmy, ve které jsem zvolil toto vlastní konkurenční řešení byla ta, že druhý tým jsou mladší nadšenci do nejnovějších novinek Reactu, Reduxu, Redux Thunku, později Redux Sagy, atd, atd. Problém byl v tom, že trochu vázlo dodávání včas a v dobré kvalitě. A kódu, souborů a hlavně balíčků bylo mnoho i pro jednoduché věci. Už jsem v jiné firmě, kde jsem dostal možnost s celým týmem nové řešení rozvíjet, tedy už to není řešení jednotlivce. Každému to sedět nemusí. Takže problém byl opačný, já nemohl skousnout kód s Reduxem, Sagama a mnoha dalšíma věcma. Aplikace a její logika se zcela ztrácela ve víru technologií. Takže jsem si nastudoval, co ty technologie přesně řeší, jak to řeší, na jakých principech jsou postaveny a zda se potkávají s tím, co bylo pro nás palčivé, apod. A došel jsem k výsledku, že byly zvoleny z větší části z důvodu prosté zvědavosti a nadšení. Tak jsem vše nepotřebné zredukoval. Mám pocit, že jde někdy o generační rozdíly mezi programátory :-) 27.11. 0:05
  • vit.herman : @Taco: Graf závislostí se vytvoří za běhu aplikace (obvykle při spuštění) - tedy dynamicky. Pokud však voláš z jedné funkce druhou, tak ty dvě funkce jsou propojeny staticky, tedy přímo v binárce. A toto propojení bylo ověřeno v čase kompilace. Myslím tím vážně jen tuhle triviální skutečnost :-) Může Ti přijít nepřirozené tyto dva případy vůbec porovnávat, ale pokud se na to podíváme z perspektivy vnitřních závislostí konstruktů prog. jazyka, tak to lze rozdělit na statickou a dynamickou vazbu. Je to docela abstraktní úvaha, ale docela zásadní a možná všeobecně málo uvědomovaná. Alespoň v kompilovaných jazycích. Třeba v PHP to nemusí nutně dávat úplně smysl :-) 27.11. 0:16
  • Taco : @vit.herman: V tom případě, jestli jsem tě dobře pochopil, tak nejde o dynamičnost jako vlastnost DIC. Ale o to, že zrovna to konkrétní řešení DIC, které máš/jste používali - bylo shodou okolností vytvářeno až za běhu aplikace. Pak ok. Jen je tedy pouze nutné pečlivě rozlišovat, kdo za to může :-) Tobě vlastně nevadilo ani DI, ani DIC :-D *** Díky za doplnění. 27.11. 0:19
  • vit.herman : @Taco: Když to takto píšeš, uvědomuji si, že i DIC může být klidně statický, jasně :-D Ano, ano, pak máš pravdu. Zkusím být ještě přesnější: Vadí mi DIC (statický i dynamický) pro třídy v business logice zakázkové aplikace, jejíž zdrojový kód dokážu v mžiku nasadit do produkce. Naopak DIC pro třídy je výborné řešení, pokud budu psát objektový framework nebo pluginy. 27.11. 0:31
  • Taco : @vit-herman: "pro třídy v business logice zakázkové aplikace, jejíž zdrojový kód dokážu v mžiku nasadit do produkce." - můžeš prosím vysvětlit? V čem je problém? 27.11. 1:16
  • vit.herman : @Taco: Hlavním účelem DIC je podstrkovat různé implementace závislostí bez nutnosti rekompilace kódu. Budu-li chtít třeba v nějakém OOP frameworku změnit způsob autentizace, jednoduše ve své aplikaci nastavím třeba vlastní implementaci třídy autentizačního modulu. Tedy jsem donutil framework používat třídu, kterou v čase kompilace neznal. V tom spočívá dynamičnost, o které jsem psal. Bez DIC těžko myslitelné. Pokud ale nepíšu framework, ale zakázkovou aplikaci, kde nasazení všech jejích binárek je omezené a mám vše plně pod kontrolou, tak mi nijak nevadí, že aplikace bude statickou vazbou o mé nové autentizační třídě vědět. Důsledkem je to, že při případném odstranění autentifikační třídy nepůjde aplikace přeložit, pokud je tato třída někde využívaná. Je tedy zajištěna integrita v čase kompilace. A to je naprosto automatická výhoda, která padá, pokud se využije DI architektura s DI kontejnerem, který závislosti injektuje dynamicky. Tam se na chybu v aplikaci přijde až po jejím spuštění a neodhalí to obvykle ani testy, pokud je v produkčním prostředí DIC konfigurován nějak výrazně odlišněji. Pomíjím tedď další nevýhody a soustředím se na rozdíl mezi statickou a dynamickou vazbou, ju? Těch nevýhod je více, např. obtížnější ladění, často magie na pozadí u některých DI kontejnerů nebo přímé porušování zapouzdření v rámci OOP. To nemusí být na škodu, ale těžko se pak mluví o OOP. Říkám tomu spíš programování s třídama, než OOP. 27.11. 13:28
  • Kit : Typické je používání statických tříd, ve kterých je DI prakticky nemožné. Pomocí DI se také elegantně zbavíme násobných dědičností. 27.11. 16:07
  • Taco : @vit.herman: Je vidět, že se na DIC díváme různě. Pro mně realita, že některá řešení DIC jsou dynamická je pouhopouhý implementační detail. Protože motivace DIC je čistě pohodlí, že se mi nechce dodávat všechny triviální závislosti ručně, když to stroj udělá za mě. Takto to vnímám já - toliko definice. Není, a nevidím v tom žádnou dynamičnost - apriory. U mě to funguje tak, že si vytvořím (ať tě trochu podráždím) funkci, tu zaregistruju do DIC, a zkontroluju si, co mi to vygeneruje za graf závislostí. Tento graf pak následně můžu nějak "zafixovat", nebo tiše předpokládat, že pro stejnou konstelaci závislostí to vygeneruje stejnej graf. To už záleží. Ale pak se samozřejmě nebavíme o problému nějakého dynamického DIC, ale o tom, zda a jak moc se tomu, či onomu řešení dá důvěřovat. *** Proč to rozebírám: protože to co popisuješ "Důsledkem je to, že při případném odstranění autentifikační třídy nepůjde aplikace přeložit, pokud je tato třída někde využívaná." je pro mě běžná věc. A nikdy mě nenapadlo v tom vidět nějakou dynamičnost. Ten DI kontainer to prostě dělá tak nějak normálně (ať už compile-time, nebo runtime). Nikdy jsem se nad tím nepozastavoval a hlavně nikdy jsem se o to nemusel namahat. Prostě normál. 27.11. 18:23
  • vit.herman : @Taco: Myslím, že rozumím. Soudě podle tvé věty, že je to pro Tebe běžné, že neexistence třídy Ti shodí kompilaci, tak jsi mimo use case, který jsem popisoval (možná ne dostatečně explicitně). V projektech, o nichž jsem psal, konstruktor injektuje převážně interfaces, jejichž implementace nemusí existovat a přesto se projekt přeloží. Pokud se injektují přímo instance tříd, tak pokud se třeba statickou analýzou ošetří, aby nebyly null, tak by to také bylo řešení. Ale pokud přenechám třeba DI kontejneru Windsor Castle pro .NET resolvování interfaces na základě nezávislé konfigurace, nejde to staticky zkontrolovat při kompilaci. Můžeš prosím napsat, jaké řešení a jakou platformu máš na mysli Ty? 27.11. 19:09
  • Taco : @vit.herman: Asi nemohu sloužit. Ale je pro mě užitečná informace, že Windsor Castle se chová, jak popisuješ (nemám s ním zatím totiž zkušenosti - a tak si dám pozor). *** Btw: vzato doslova "konstruktor injektuje převážně interfaces" je pěkná kravina :-) Ale samozřejmě chápu, co jsi chtěl říct. 27.11. 20:52
  • vit.herman : @Taco: Aby jsi byl spokojený, tak upřesním formulaci: Konstruktory přijímají dependencies ve formě argumentů typu interface. Uffff :-D 27.11. 21:29
  • rs : @vit.herman Java / Micronaut ten treba resi zavislosti uz pri prekladu. A jak uz tu padlo pro me je vyhoda ze nemusim skladat strom rucne. Mam jednotlive servisy / moduly ktere explicitne rikaji na cem zavisi. Nemusim je rucne dratovat dohromady resit singleton / request / session scope to za me dela kontejner a zaroven mam typovou jistotu ze vse funguje jak ma. 27.11. 21:45
  • vit.herman : @rs, @taco Díky za tipy, že to jde řešit i při překladu. V takovém případě je přínos neoddiskutovatelný. 27.11. 22:20
  • harrison314 : @vit.herman: k DIC, nic take ako ze ti chyba v runtime zavislost by sa ti pri spravnom pouziti stat nemalo, jednak autodiscover a pisanie tried do konfigu sa nepovazuje za dobru praktiku. Druhak tie lepsie kontainery si pri starte aplikacie skontroluju graf zavislosti, tkez ked si spravil ako programator chybu aplikacia nenastartuje a da sa to unitestovat. Ja som Windsor kvoli tomu opustil, ak si purista skor sa pozri po SimpleInjector, ten hadze polena pod nohy, ked budes chciet robit nieco zle. Este jestvuje Lamar, ten by mal vediet skompilovat kompozicny root natvrdo, ale tuto vlastnost som este neskusal. 28.11. 7:31
  • vit.herman : @harrison314: Díky za tip. Momentálně už se asi k .NET a C# trvale vracet nebudu, opustil jsem tento stack as před rokem. Ale děkuji za diskuzi, rozhodně jste mi pomohli trochu rozšířit obzor. Hlavně možnost kompilace té kompozice. Tím by řešení bylo čistou přidanou hodnotou, která jinde neubírá. To je pro mne informace, na jejímž základě bych tomu dal ještě šanci, pokud bych se k tomu dostal. 28.11. 10:38

Pro zobrazení všech 7 odpovědí se prosím přihlaste:

Rychlé přihlášení přes sociální sítě:

Nebo se přihlaste jménem a heslem:

Zadejte prosím svou e-mailovou adresu.
Zadejte své heslo.