Fork me on GitHub
#clojure-norway
<
2022-03-22
>
magnars09:03:19

ClojureScript er jo Clojure sin killer app, folkens. Det er ikke noe sted Clojure sin tankegang gjør større løft enn i frontenden. IMHO. 😘

👍 2
slipset09:03:17

Problemet er jo at det er så veldig mange JS/TS folk/app’er der ute at det er vanskelig å få skvisa inn CLJS

slipset09:03:57

Pluss at frontendutviklerne stort sett er så unge at de ikke skjønner hvor ille de egentlig har det.

2
magnars09:03:01

Ja, omskriving av gamle app-er er sjeldent lønnsomt, det er klart.

magnars09:03:15

Men jeg går ikke med på at frontendutvikling er mindre komplisert, altså.

slipset09:03:34

Nei, nei, frontentutvikling er jo mye mer komplisert.

slipset09:03:53

Men problemet er litt sånn at når du er i ferd med å dø av thousand paper cuts og noen viser deg de enkelte kuttene, så sier du at jammen, det er jo ikke så ille.

magnars09:03:53

At folk har havnet i uføret å overlate frontenden sin til en gjeng jyplinger rett fra skolebenken som lager et eneste stort virvar med React hooks får de nesten skylde seg selv for 😅

😄 1
slipset09:03:53

Nå er det jo slik at hvis jeg får velge mellom et virvar av React hooks og litt god gammel miks av JQuery/Backbone/Handlebars så velger jeg nok React hooks.

magnars09:03:43

Stemmer sikkert, men en falsk dikotomi var det også. Fritt fra kontekst, i hvert fall.

slipset09:03:31

Men, liksom, bare noe så vanskelig som byggesystemer. Det er jo en dumpster fire uten like. Noe går feil, ja, ja, får nuke node_modules og kjøre en yarn install og håpe på at det fikser seg selv.

❤️ 1
slipset09:03:45

Husker ikke når sist jeg måtte røre .m2

magnars09:03:51

Ja, høres forferdelig ut. Ville bare få påpeke at det finnes en vei utenom. 🙂

slipset09:03:04

Og et økosystem som har version-ranges i depsa sine.

1
🧨 1
magnars09:03:51

Peer: Av veien, Bøyg! Den store bøygen: Gå utenom, Peer. Peer: Nei, gjennom!

😂 1
slipset09:03:55

Joda, jeg vet det finnes en vei utenom. Problemet er at en har 20 utviklere som sakte blør ihjel av bitte små kutt og er fornøyd med det.

magnars09:03:24

Ja, jeg ser problemet. Ikke har jeg noen løsning heller.

slipset09:03:35

Jeg vil ha løsninger, ikke problemer!

😹 2
magnars09:03:38

Prøver på min lille måte å vise frem en bedre vei, men det biter vel ikke.

❤️ 1
Jakub Holý (HolyJak)10:03:17

Nei? Zombiene er jo så flinke til å bite?!

magnars10:03:18

Det er sant det! Vi får håpe de også biter seg fast i bevisstheten til folk 😄

🙏 1
slipset09:03:28

Jeg setter veldig stor pris på ditt og @christian767 sitt bidrag. Om ikke annet så gleder det meg.

😊 3
💯 3
2
cjohansen09:03:32

Du kan rive ClojureScript ut av de stive, døde fingerne mine

cjohansen09:03:18

Diskusjonen om typer til side: Bare all tiden man sparer på å løpe etter JS-økosystemet er glatt verdt investeringen.

1
❤️ 1
magnars09:03:12

Så lenge man da klarer å løsrive seg skikkelig. Jeg vet om ClojureScript-prosjekter som fortsatt løper etter React-økosystemet, og da har man bommet litt, etter min mening.

cjohansen09:03:53

Jeg har lenge tenkt at jeg ikke kan se for meg at jeg kommer til å jobbe i en JavaScript-frontend igjen i overskuelig fremtid, men etter noen sånne diskusjoner så får jeg et lite masochistisk ønske om et 3 måneders opphold i et prosjekt for å se om det er jeg som misforstår og at det egentlig har blitt bra igjen. Men så kommer jeg på at man ikke engang kan bruke paredit i JS, og så roer det seg 😅

😅 3
fxii11:03:19

Sett på https://github.com/Fuco1/smartparens ? Den skal visst gjera litt paredit-greier for tøysespråk. (Har berre såvidt testa sjølv, så veit ikkje kor bra det funkar.)

cjohansen11:03:42

Noteres til en eventuell fremtid der jeg må forholde meg til ikke-lisp 🙂

slipset14:03:10

@christian767 vi driver og skriver om gammel js/backbone til TS/RxJS/React. Jeg kan kanskje klare å overbevise sjefen om å hyre deg inn i tre måneder.

slipset14:03:09

Jeg har en halvveis, veldig irriterende conf av paredit for React/TS gående…

cjohansen14:03:23

“dessverre” er jeg hyret inn for å drive med Clojure/ClojureScript 😢

cjohansen14:03:09

Men klart, en halvveis, veldig irriterende conf av paredit høres artig ut 😅

👍 1
leifericf10:03:14

Litt meta: Jeg føler at samtalene i kanalen hadde blitt enklere å følge hvis vi ble flinkere til å bruke samtaletråder, typ knappen “Reply in this thread” (snarvei T på tastaturet) ☺️ Hvis jeg får lov til å legge inn et velment organisatorisk forslag.

❤️ 3
cjohansen10:03:31

Meta fra meg: Slack-tråder er hvor meldinger går for å dø 🙃 Kanskje bare jeg som er vanskelig.

💯 1
augustl10:03:10

bare å børste støv av de gamle IRC-skillsa hvor man hadde 5-6 samtaler gående samtidig i samme kanal

😂 1
Jakub Holý (HolyJak)10:03:38

> Pluss at frontendutviklerne stort sett er så unge at de ikke skjønner hvor ille de egentlig har det. Den eldgamle Figwheel demoen av live utvikling av Angry Birds hjal meg nesten til å overbevise kolleger til å gå for cljs. Man trenger ikke bare utpeke problemer med JS, som ikke fungerer om målgruppa har ikke opplevd/skjønt nok av de. Man kan også vise det som er kult med cljs 🙂

augustl10:03:51

nå har forresten den ultimate Cloure-boken blitt skrevet! https://www.manning.com/books/data-oriented-programming

👍 1
leifericf14:03:06

Kjøpte den når MEAP kom! Men har ikke lest den enda. Takk for påminnelsen!

augustl10:03:10

litt som Simple Made Easy, argumenterer boka for Clojure uten å nevne Clojure i noen større grad

augustl10:03:41

jeg har holdt på sånn helt siden jeg oppdaget Clojure, ikke snakk om at jeg klarer å kose meg på frontend-prosjekt i JS uten Immutable.JS eller mori

magnars10:03:03

Interessant!

augustl10:03:28

og ikke nok med det: den boka er Manning sin bestselger for 2021!

💯 1
💰 1
augustl10:03:11

på hyggelig vis argumenterer den også for DDP men bruker lite energi på argumentere mot OOP, så jeg vil tro at den er ganske spiselig. Skal gis i julegave til alle utviklere som (i følge meg 100% definitivt uten tvil) trenger den

augustl11:03:05

jeg har snakket varmt om hooks her før. Men jo mere jeg bruker hooks, jo kaldere bli det... Det er mæget vanskelig å få de korrekt. På react-hook-frontenden jeg holder på med nå blir typ data fetchet et sted mellom 1 og 4 ganger avhengig av timing og race conditions. 90% av problemene kommer fra mangelen på god equality og value semantics. Jeg får det ganske greit til å gjøre det riktig (💪), men så har jo jeg 20 års erfaring med frontend-utvikling og. Andre flinke men mindre erfarne folk får det nesten aldri helt riktig

1
1
teodorlu11:03:08

Prøvd react query? Da sier du noe sånt som "sånn kan data hentes", gir det en ID som er unik over appen, så er den litt "lur" med deling av resultater og spørring etter ny data. https://react-query.tanstack.com/ Kanskje litt vel magisk for din smak?

👀 1
augustl11:03:33

høres lurt ut med noe sånt ja

augustl11:03:47

React-folka sier det jo selv, hooks handler mere om å eksponere primitiver som allerede finnes under panseret i React

augustl11:03:03

ser kult ut, takk for tipset!

👍 1
oddsor11:03:48

Jeg fikk inntrykk av at react-hooks på en måte tok over som “snakkis” over tilstandslagre som Redux. Vet ikke om det er slik andre opplevde det sånn :thinking_face: Iallefall gjorde det meg ganske skeptisk i lang tid. Det morsomme er jo at hooks på mange måter bare er en enklere måte å flytte tilstand tilbake inn i komponentene igjen. Så det blir liksom lavere friksjon på å gjøre komponenter mindre funksjonelle 🙈

oddsor11:03:24

@U04V5VAUN vi har vel en (eks-)kollega som omtalte hooks som “magic”, og han var derfor ikke interessert i det :rolling_on_the_floor_laughing:

magnars12:03:36

React-teamet har virkelig jobbet hardt de siste fem årene med å fjerne seg fra idéen som virkelig fenget: en effektiv enveis transformering av data til dom.

🙈 2
😄 1
augustl12:03:10

akkurat hooks er på en måte greit nok, som nevnt så er ikke det noe "ekstra" de har laget som går utover ytelsen osv, har forstått det som at hooks ble sett på som å eksponere det React allerede hadde under panseret. Tror feilen ligger i at hooks har blitt tatt i bruk av React-miljøet som et primitiv som er nyttig og bra nok for GUI-programmering

augustl12:03:52

pluss at en hook særlig, useEffect, gjør det for lett å gjøre I/O fra gui-komponentene og ikke ha noe state-behandling på toppnivå i det hele tatt. Men det er også et problem som ligger i React-miljøet, ikke React core, vil jeg si

👍 1
1
augustl12:03:09

imo så er det jo en nødvendighet å kunne ha små maskiner her og der i treet, av ytelsesgrunner

augustl12:03:34

aka "partial rendering" eller hva man skal kalle det

augustl12:03:06

da det er sagt så får jeg det jo fint til med snabbdom/dumdom, ved å bare rendre til et DOM-element via refs, så...

cjohansen14:03:27

> imo så er det jo en nødvendighet å kunne ha små maskiner her og der i treet, av ytelsesgrunner Jeg har jobba med frontend på dette viset i faen skjære meg snart 10 år, og kan telle på én hånd hvor mange ganger jeg har måttet til å gjøre noe annet enn top-down av ytelsesårsaker

cjohansen14:03:21

Og de få gangene jeg har hatt det problemet har det vært helt løselig på utsiden, uten å trå til med tilstand i komponentene

magnars14:03:16

Ja, det behovet for lokal state for ytelse er dramatisk overspilt.

1
augustl14:03:19

samme her faktisk, er bare i denne CMS-en min jeg har hatt behovet. Siden jeg lager min egen editor ble det litt heftig å rendre hele treet på hvert tastetrykk i et input-felt. Kan vel sies å være en nokså sær case

magnars14:03:45

Jeg har også jobbet med frontend på denne måten i mange herrans år, og unntakene for min del har vært "et UI-element skal følge fingeren din". Da kan man oppleve at det lugger. Det er ikke nødvendig å vri hele frontendarkitekturen din rundt så sjeldne use cases (med mindre du bygger din egen editor 😄 )

slipset14:03:55

Men. Ikke pga ytelse, men pga letthet. Hvordan dealer dere med forms som skal fylles ut. Lagrer dere mellomtilstanden til formen i global state? Det er typisk et sted der jeg bruker lokal state for å fylle opp alle feltene, for så å shippe alt avgårde når brukeren trykker submit

2
magnars14:03:13

men kort fortalt: Input-feltene har allerede lokal state. Det hender jeg bruker det.

magnars14:03:44

Dersom det skal være dynamiske endringer i skjemaet avhengig av verdiene i feltene, så oppdaterer jeg global state underveis.

augustl14:03:52

gjør tilsvarende i CMS-en, editoren er implementert som om den var et input-felt. Har referanser til dem, og henter ut en value ved behov, oppdaterer ikke noe app-state på onChange (men kan hvis jeg vil)

slipset14:03:10

Right. Så lagre alle mellomstates i global state.

👍 1
augustl14:03:41

forms er også der jeg oftest ser forsøk på smarte abstraksjoner gå skeis.... kan være digg helt i starten med en generisk form builder, men så plutselig brakk man halvparten av formene etter en endring i form builderen pga en annen form, og i det hele tatt...

augustl14:03:01

rettelse: jeg lagrer form values onChange, for å alltid ha siste verdi liggende "sentralt", men jeg lagrer den tilstanden et eget sted som ikke automatisk fører til en ny render av hele appen

👍 1
magnars14:03:16

hva er dette "mellomstates" du snakker om, @U04V5VAUN?

slipset14:03:55

Når du har fyllt ut 2 av 4 ting i formen.

magnars14:03:44

er fullverdig data det også 😅

🎯 2
cjohansen14:03:07

Hvis du slenger dem inn i global storage så kan du lage fin validering osv uten å søle til form-komponenten

cjohansen14:03:38

Form-komponenten trenger bare å vite hvordan ting skal rendres. Er det en feilmelding så dukker den opp på rett sted. Den trenger ikke å vite hva som fører til hvilke feilmeldinger - det er kontekstuelt.

magnars15:03:33

Poenget her er jo å ha en ensrettet dataflyt. Fra store -> prepare -> render -> dom. Rene funksjonelle transformasjoner hele veien. Langt lettere å følge flyten enn "mange små maskiner"

slipset15:03:06

Interessant. Også fordi det blir en hersens mange actions som vi må (type) definere og lyttere på disse etc osv osv. ser at dette er mye enklere i cljs enn slik vi har endt opp

cjohansen15:03:44

Hvis du lager spesifikke actions til så får du veldig mange

cjohansen15:03:58

Vi bruker for det aller meste små generiske actions

slipset15:03:50

Joa, men de holder informasjonen man trenger, i eksemplet til @magnars så var det i form av «login-form/username» Vi ville sikkert hatt en dedikert action for det, ikke ulikt slik man velger å ha gettere/settere i Java.

magnars15:03:38

på grunn av typesystemet?

slipset15:03:21

Ja, eller noe. Jeg er ikke designeren av systemet, jeg er kun en stakkars utvikler.

cjohansen15:03:27

{:type "email"
 :placeholder (tr (:locale state) ::form-email)
 :value email
 :change [:save-in-store [:reception/login :email]]
 :disabled? (= :requesting-otp status)
 :autofocus true}
Dette er dataene til epost-feltet i login-skjemaet vårt

cjohansen15:03:42

email er her da (get-in state [:reception/login :email])

augustl15:03:49

får den inn en core.async channel elns i tillegg? Aka hvor sender den dataene i :change når eventet trigges?

magnars15:03:30

Det er en event-bus som snur avhengigheten.

cjohansen15:03:24

tldr; dumdom kan ha én global event-listener som dispatcher til event busen, slik at komponentene kan bruke data “som event-listenere”

augustl15:03:33

a-ha, dumdom har en toppnivå sak som tar imot sånt ja, smudings kjørings

magnars15:03:05

men dette er en arkitektur vi har brukt i årevis - dumdom sin feature er helt ny - så man trenger ikke verktøytstøtte for å få til dette altså 😅 Selv om det er meget sweet, så klart.

cjohansen15:03:33

neinei, det er bare krem på kaka

augustl15:03:36

@magnars ble nysgjerrig på detaljene bare, bloggposten din nevner vel ikke hvordan det løses teknisk

cjohansen15:03:56

Nei, med overlegg, for det er ikke egentlig et teknisk problem, men et designproblem 🙂

magnars15:03:34

Du kan se gist-en av idéen i s02e02 av zclj, når Christian lager en event-bus på 8 linjer kode eller hva det ble. 🙂

👀 1
augustl15:03:42

når CMS-en får seg navn/logo så må vi få mekka sånn logo-salat på github-siden til dumdom, "projects using dumdom" 💪 Sånn at dumdom kan få masse brukere som bare vil ha det mest populære cljs-biblioteket for rendring

😂 1
isak15:03:42

Hvordan håndterer dere store data volumer? Må en liste komponent re-rendres hvis en greie i listen endrer?

cjohansen15:03:12

Lista må re-rendres, ja

magnars15:03:19

I shadow-dom, vel å merke.

magnars15:03:00

Det er jo en diff-algoritme som lager et minste sett av DOM-operasjoner, "old school React"-style.

augustl15:03:04

nøyaktig ingen har vel helt løst det med å smooth rendre tusenvis av elementer i en liste. Ikke engang de som ha fått det til, de gjør det jo ved å ikke rendre alt i lista

cjohansen15:03:40

Er ikke så ofte jeg har trengt å rendre virkelig store datamengder

isak15:03:51

Det jeg liker litt med reagent er at det er lett å få det til slik at bare en ene re-rendres

cjohansen15:03:03

Det er lett å få til, men er det nødvendig?

cjohansen15:03:20

Det jeg misliker med reagent er at det er lett å gi slipp på enveis dataflyt 😅

1
isak15:03:23

I vår app ja, og selv det holder ikke noen ganger.

magnars15:03:36

Da ofrer du mye på ytelsens alter, vil jeg si.

magnars15:03:23

Mennesker kan jo normalt sett ikke forholde seg til tusenvis av elementer i en liste, så her tenker jeg at løsningen vil være å bygge UI-er som mennesker kan bruke - da gjerne ved å vise et utvalg av lista av gangen.

❤️ 1
isak15:03:25

Jo men man får mye igjen, vertfall i vårt tilfelle

augustl15:03:16

er man pokka nødt så er det relativt håndterlig å løse dette uten reagent og. Rendre lista, en key per element, bruk en ref, ta vare på key + ref, rendre dem én og én ved behov

isak15:03:41

Det er sikkert en god løsning for de fleste apps, men hvis man har en der brukeren lager queryen selv, med custom group by, aggregering, osv., blir det vannskelig

cjohansen15:03:15

Den kjøper jeg ikke helt uten videre. Jeg har ihvertfall laget nokså spesialiserte søkegrensesnitt tidligere med masse sånne verktøy og ikke hatt behov for å gi avkall på enveis dataflyt.

magnars15:03:26

Det finnes sikkert tilfeller der man må gi opp ensrettet dataflyt og rene funksjonelle transformasjoner for å få den ytelsen man trenger, men ikke den skalaen det gjøres i vår industri.

augustl15:03:29

en ting skal sies. Både med hooks i React og subscriptions i reagent, så blir dataflyten enveis. Bare sånn for å henge meg litt opp i det. "Enveis dataflyt" og "alle data på toppnivå" er ikke det samme. Så det blir ikke et sånt OO-graf-virrvarr med hooks/reagent

augustl15:03:08

en hook i react er lokal til komponentet og kan bare sende data nedover, samme med subscriptions i reagent

magnars15:03:33

da bruker jeg antagelig ordene mine feil, for "mange små maskiner som sitter på deler av dataene og lever i sin egen livsyklus og oppdaterer deler av UI-et" er ikke innenfor det jeg mener. 🙂

augustl15:03:15

hvis man f.eks hadde sendt inn et atom til hele treet og endret på det dypt der nede som førte til at noe over den selv i treet rendret seg på nytt, så er man på OO-graf-kaos-kjøret, men det er heldigvis ikke sånn man gjør det i reagent 🙂

isak15:03:16

Mulig det ikke er nødvendig å gå bort fra enveis dataflyt, jeg bare har ikke sett på det som viktig. Vi har noen re-frame/reagent problemer, men det er ikke det.

augustl15:03:56

men det blir jo ikke data driven programming og referentially transparent og alt det der på den måten. Men det blir enveis ihvertfall 😄

isak15:03:35

Ja, jeg tror jeg er enig med @U0MKRS1FX, fordi vi har omtrendt all data på topp nivå

magnars15:03:51

Der tror jeg du traff spikeren på hodet, @isak. Du har ikke sett på det som viktig. Og det er jo problemet vårt her. Å klare å kommunisere hvorfor det er bedre.

magnars15:03:06

Litt som å prøve å selge inn Clojure.

magnars15:03:44

Hvorfor er det bedre? "Nei, du jobber med data istedet for en objektgraf, også er det pure functions, og sånn." "Mja, har ikke egentlig noen problemer med objekter vi!"

isak15:03:11

Ja. Det er mange ting folk har tenkt var viktig over tiden. For eksempel det med property-based testing for UI, om.next med co-located, queries, osv. Jeg sier ikke at det ikke var viktig, men det har en kostnad som må vurderes.

augustl15:03:35

hva er grunnen til å foretrekke å ha all tilstand på toppen i en enveis dataflyt, og gjøre det litt mere tungvindt å rendre sub-trær, vs å ha lokal tilstand i render-treet en enveis dataflyt, som gjør det trivielt å rendre sub-trær?

magnars15:03:13

Fordi det er en grunnleggende enklere modell.

augustl15:03:16

eller for å snu på det, når snubler man hvis ikke all data ligger på toppnivå?

isak15:03:31

Hmm @magnars er du enig i det @U0MKRS1FX sa i at det å ha alt i app-state kan lett gjøres uten enveis dataflyt? Med enveis dataflyt, regner jeg med at du mener at alt sendes nedover direkte via props, ikke sant?

isak15:03:34

Jeg er med på å ha alt i app-state, bare ikke å sende absolutt alt nedover via props

magnars15:03:54

Nå er vi langt forbi stadiet hvor vi kommer til å forstå hverandre i denne tråden. 😅

1
❤️ 1
augustl15:03:57

mulig vi snakker forbi hverandre på dette med "enveis dataflyt", det jeg snakker om, uansett hva vi kaller det, er at data bare flyter nedover i GUI-treet, og sånn bli det både med all tilstand på toppen, og med lokal tilstand i komponentene

cjohansen15:03:58

@U0MKRS1FX du kan ikke trivielt svare på “hva er tilstanden til appen min nå?“. Har implikasjoner for din evne til å forstå appen, testing, reproduksjon, feilsøking, etc.

🎯 3
augustl15:03:07

der er jeg helt enig i prinsippet, men jeg må innrømme at jeg ikke synes det er så alt for vanskelig å legge inn noe logging i komponentet det gjelder, når jeg er i state-over-alt-verden

cjohansen15:03:29

Det jeg ikke skjønner er hvordan man har blitt solgt på Clojure (og/eller ClojureScript), men krangler på at det å gjøre UI-et så funksjonelt og datadrevet som mulig er en god ting 😅

3
isak15:03:12

Ok hva med det eksemplet å lett legge til undo/redo uten å touche en set av components @U0MKRS1FX ?

augustl15:03:21

å preppe alt på toppen kan jo sies å innføre kompleksitet og. Toppnivå må vite om behovene til alle children. Det kan bli vanskeligere å flytte rundt på ting. Ref å f.eks sende rundt en datomic db hvor man kan kjøre queries, mot for å måtte kjøre query først og vite om alle behovene til alt nedenfor

👍 1
augustl15:03:39

men kanskje man kan se på det som positiv kompleksitet 🙂 Det blir jo veldig transparent hva som foregår

cjohansen15:03:10

Jeg tenker ikke på det som at man prepper ting til en spesifikk komponent. Jeg tenker på det som at jeg transformerer ALLE dataene mine til ett view på dem. Og så gir jeg dem til et komponent-tre for å rendre det.

👍 2
magnars15:03:28

jeg klarer ikke svare på spørsmålet ditt i denne tråden, @isak, men jeg har skrevet (ganske kort) om hva jeg mener med "ensrettet dataflyt" her: https://www.kodemaker.no/blogg/2020-01-enkel-arkitektur/ Det handler om mer enn bare "props" (hva enn det er for noe 😄)

2
isak15:03:47

@U0MKRS1FX Akkurat det med query som bestemmes av en komponent, men fremdeles respekterte enveis dataflyt ble løst av om.next. Men det ble veldig komplisert.

slipset16:03:08

En klar ulempe med lokal state er at hotreloading funker dårligere? Du mister jo den lokale state’n?

slipset17:03:40

Husker forøvrig jeg hadde en slags diskusjon m Eric Norman om dette: > That’s a great question. > > Re-frame and Reagent give you the best of both worlds. You can write pure components. Or you can write impure components. In my experience, pure components are great up until they are not. Reagent gives you a nice way to convert a pure function returning hiccup into a stateful component. > > But that brings up the question: when are pure components not great? > > I don’t know if I have a great holistic answer to this question, but in my experience, as UIs get more sophisticated, the data you have to flow through your functions becomes tightly coupled with the DOM structure. Let me explain with an example: let’s say you want to have a label that shows the currently logged in user’s name. That label appears down in a component deep within the main panel of the app. To make that work in a pure way, every component has to know the name of the user, all the way from the top, down through many layers, until that label. It is essentially global information, since so many components know about it. Now, the requirements change. The label needs to appear not there, but in a cousin tree. You have to reflow the name of the user to go down that other tree. The more distant the tree, the more components you have to touch. > > The solution in Re-agent is that that is simply global data, available via a named subscription. You can easily copy and paste the component from one tree to another, and not have to deal with re-flowing data. It is common enough for components to move around while an app is being designed that it can significantly reduce the development overhead--especially since the dom structure rarely corresponds to anything rational and stable. > > Having calculations in subscriptions is great because it lets you separate out the view from derived data. > > And after all that, I’m leaving out another important aspect when it does come up: being able to re-render only a small subset of the dom instead of the entire thing. This starts to be important with large doms, such as with thousands of spreadsheet rows. > > Finally, I think Re-frame is probably better classified as reactive programming instead of functional programming. A lot of the functional programming ideas are still there, but there’s the new idea of derived values (such as the dom) being a function of changing data. There’s an idea of a “current value”. > > I tend to think of Reagent components as having 2 sources of inputs: function arguments and subscriptions.

💯 1
👍 1
isak17:03:02

> En klar ulempe med lokal state er at hotreloading funker dårligere? Du mister jo den lokale state’n? Det er sant, men det er vist noen tricks man kan gjøre for å få det tilbake. (Ikke at jeg er for lokal state)

isak17:03:15

@U04V5VAUN Det er en god forklaring. Jeg tenkte også på det med en spreadsheet, fin eksempel der performance er kritiskt.

teodorlu18:03:31

Kan jeg få et konkret eksempel på noe som er enkelt å gjøre i Reagent, vanskelig å gjøre med dumdom og Enkel Frontendarkitektur Som Funker (TM), og hva man ville gjort i stedet med EFSF(TM)? Jeg henger ikke helt med. Er det som forskjellen på Elm Architecture og React-greier? I Elm sørger typesystemet at det eneste en komponent kan gjøre er å sende en action? Og da kan man lage test : State -> Bool?

augustl18:03:56

hvor mye domene-data pleier å havne i resultatet av prepare?

cjohansen18:03:26

Ideelt sett så skal datene som kommer ut av prepare være i UI-domenet, og ikke i det heletatt i appens/forretningens domene

cjohansen19:03:25

Men i praksis så hender det at det lekker litt, kanskje særlig i de øvre lagene, ettersom det grøvste av layout handler mye om hvilke ting som skal hvor og kan være klønete å finne gode abstraksjoner for

💯 1
cjohansen19:03:16

Ellers må jeg si at resonnementet fra Eric Normand over leser som om det jeg driver med på jobb er både upraktisk, og yter dårlig. Det stemmer ikke med min erfaring.

cjohansen19:03:41

Når det argumenteres for tilstandsfulle komponenter så er det alltid pga ytelse og fordi det er dumt at alle komponentene må vite om all data. Jeg lurer på i hvor stor grad disse argumentene har rot i praktisk erfaring vs teoretisk problematisering. Ytelsesproblemet er alltid en variant av "spreadsheet"/masse data, men de aller fleste apper har helt håndterbare mengder data, og du kommer lenger enn du tror før ytelsesproblemene trer inn. Når det gjelder å sende data nedover så opplever ikke jeg det som spesielt upraktisk eller vanskelig. Som tidligere nevnt tenker jeg på dataene som skal rendres som "UI-et, i dataform" - ikke som data til disse 700 forskjellige komponentene. Komponentene som sender data nedover plukker stort sett ut én ting som sendes til et subtre. Fordelen med denne modellen er at du når som helst kan sitte med hele datastrukturen for enhver tilstand i UI-et ditt i hånda. Det gir deg super powers og er verdt å jobbe litt for.

👌 2
augustl21:03:23

lurer på om jeg har en liten mental sperre her. Her og nå slo det meg at selve GUI-et er jo også bare data. Altså hiccup. Det visste jeg jo, men når jeg ser en :div så føles det ikke som data, men som noe annet. Litt knotete forklart kanskje. Men sånn sett er det jo "bare" tre lag? Først domene-dataene, det du skriver til, som er en database eller noen maps eller noe annet. Så transformeres de til noe som er mye mere GUI-data og har minst mulig domene i seg (prepare). Så transformeres det igjen til 100% GUI-data (altså hiccup og render-steget)

augustl21:03:03

domene-data (read/write, flatest mulig, mest mulig query power) ⬇️ GUI-data (read-only, litt struktur) ⬇️ render-data (read-only, masse nøsting og struktur)

1
augustl21:03:44

og for å ta det med CMS-en min igjen, så funker det helt fint å optimalisere der det trengs. F. eks disse hjemmelagde input-feltene mine skriver faktisk til domene-dataene på toppen men trigger ikke en prepare/render. De rendter seg selv via refs og maskineri, som er helt oversiktlig og fint, og nødvendig (fordi fps var lav når man skrev, ikke fordi premature optimization)

augustl21:03:22

det er jo ikke noe rammeverk som bestemmer hvordan ting skal funke, så det er jo bare å lage seg det man trenger for å få til det man trenger

cjohansen05:03:47

En vesensforskjell mellom UI-data og hiccup er at førstnevnte er en konsis strukturell beskrivelse av et grensesnitt, mens hiccup inneholder masse flyktige detaljer for å få rett design. UI-dataene har både en tydeligere struktur og er mer stabile over tid. Det er også disse dataene som gjør det mulig å gjenbruke de samme generiske komponentene for mange forskjellige domenekonsepter.

🎉 1
augustl07:03:24

pluss at jeg tipper UI-dataene ikke nødvendigvis er strukturert for rendering heller? Hiccup får jo masse nøsting, men det er ikke sånn at UI-dataene representerer hiccup-nøstinga 1:1?

cjohansen08:03:56

Nei, ikke på detaljnivå

augustl08:03:52

nå ble det litt sånn utspørring her... 🙂 Jeg er veldig tilhenger av namespaced keys. Eneste unntaket er libraries som tar inn maps, og typ å sende inn options til en funksjon. Men alt av data som sendes rundt foretrekker jeg namespaced keys på. Både domene-data og gui-data egentlig. Tanker?

augustl08:03:31

i domenet er det ihvertfall bra med namespaced keys, og det får man jo "gratis" om man bruker datomic/datascript

augustl08:03:19

det følger kanskje litt den trestegs flyten. Domene-data 100% namespaced keys, UI-data en god del namespaced keys, hiccup 0% namespaced keys

Jakub Holý (HolyJak)09:03:37

@magnars du kan angre å ha tiltrukket min oppmerksomheten til tråden :) > Fordi det er en grunnleggende enklere modell. Helt enig med det! Jeg er i båten med Christian og Magnar her. Jeg vil bringe litt perspektiv fra Fulcro. Jeg har mye mindre erfaring med å bygge FE enn dere men det jeg har opplevd ledet meg til Fulcro som en mye bedre løsning. Og dens autor, Tony Kay, har masse erfaring med å bygge full-stack apps på denne måten og det tydeligvis fungerer for ham (& andre). Jeg har stor respekt for Tony og hans dybt design thinking. > å preppe alt på toppen kan jo sies å innføre kompleksitet og. Toppnivå må vite om behovene til alle children. (same thing that Erik Norman mentioned) > > @U0MKRS1FX Akkurat det med query som bestemmes av en komponent, men fremdeles respekterte enveis dataflyt ble løst av om.next. Men det ble veldig komplisert. Interessant å høre at Ch&M ikke opplever dette som et problem. Praksis <> teori :) Ellers prøver react-query å løse problemet i JS verden. I cljs er Fulcro den beste løsningen jeg vet om. Jeg vil adressere "Men det ble veldig komplisert." Om.next var komplisert for det var egentlig en forskningsprosjekt. Fulcro "streamlines" og forenkles det mye, siden den er laget for å skrive og vedlikeholde kommersielle apper. Mange tror at også Fulcro er komplisert - men det er en myte som jeg ønsker å fordrive i ClojureD :) IMO er den mindre komplisert enn hvilken som helst sammensetning av en UI lib + state management lib + data fetching lib. Nevneverdig - Fulcro er egentlig en "loose set of few core, many optional parts". Men nok om det; de interesserte kan lese mer på https://github.com/fulcro-community/guides/blob/split-mft/modules/tutorial-minimalist-fulcro/pages/ -> index.v2.intro.adoc Ang. diskusjon om hvor lagrer man form state - Fulcro har den i global state (så at ui=f(state). Når man endrer på et felt så kan man bruke et triks - om nødvendig! - så at bare input komponenten rendres på nytt. Men det er gjennomsiktig til utvikleren, dataene går fortsatt via global state, og neste full render vil fungere som om man ikke brukte trikset. Så den enkle modellen på utsiden og noen triks for bedre ytelse på innsiden. Ytelse & Big data - som nevnt, trikset er å ikke rendres masse unødvendig data som ingen menneske kan fordøye :) Fulcro hadde en optimizer renderer som bare re-rendret komponenter med endret data uten å rendres dens foreldre. Men det viste seg at i reelle prosjekter er ytelseforbedringen ikke verdt den ekstra kompleksiteten. Dvs ytelse er mye mer et teoretisk enn reel problem (men nyttig å ha "escape hatches" for når du virkelig har problemet).

🎯 2
magnars09:03:03

Jeg angret ikke, @U0522TWDA 😄 Må sjekke ut Fulcro, skjønner jeg.

❤️ 1
augustl11:03:59

> i reelle prosjekter er ytelseforbedringen ikke verdt den ekstra kompleksiteten. Dvs ytelse er mye mer et teoretisk enn reel problem (men nyttig å ha "escape hatches" for når du virkelig har problemet)

augustl11:03:07

all you need to know about GUI development in 1 easy step

Jakub Holý (HolyJak)12:03:37

Premature optimisation... :)

Jakub Holý (HolyJak)12:03:51

For 10 min intro to Fulcro, if y prefer video https://youtu.be/UrpYLyGy4Lc

👍 1
magnars15:03:25

Tråder i Slack har det med å begrave interessante diskusjoner for de som ikke har deltatt i tråden, så tenkte bare jeg skulle gjøre oppmerksom på at det har foregått mye interessant prat i tråden over ☝️ 🙂

👍 2
1
🙏 1
leifericf16:03:26

Har fulgt litt med på diskusjonen der innimellom slagene på kontoret i dag, men har ikke så mye å bidra med rundt temaet 😅

isak17:03:51

Jeg leste denne @magnars: https://www.kodemaker.no/blogg/2020-01-enkel-arkitektur/ Mitt intrykk (fra en re-frame bakgrunn) er at det løser noe som i min erfaring har vært et lite problem (de å forstå hvilken data brukes hvor), og introduserer et større problem - en global performance degradation som må da vurderes i hvert tilfelle i hver app om det er OK eller ikke, eller om en workaround (for eksempel "shouldComponentUpdate") rundt modellen må benyttes. En annen ting er at jeg ville tro det blir veldig tungvindt. Hvis jeg jobber med en "leaf" component som trenger mere data, må jeg da finne alle steder den blir brukt, gå gjennom hele "call stack" hvert sted og passe på at dataen sendes nedover. Enig at det blir lettere å se dataflyten, men det er jo en ganske ekstrem kostnad.

magnars17:03:58

Jeg har jobbet slik i mange år uten noen av disse ytelsesproblemene. 🤷

❤️ 1
magnars18:03:13

Men det er ikke første gang jeg har blitt fortalt at teknikker og teknologier jeg har brukt i mange år antagelig ikke fungerer i praksis, det pleier bare ikke skje på Clojure-slacken. 😛

😂 1
isak18:03:05

Jeg tror du misforstår litt, jeg sier ikke "dette vil aldri funke", jeg bare tar opp ulempene. Det er ikke bare fordeler med den strategien. Før i threaden virket det som du synes det var rart at ikke alle var on-board med dette, så jeg prøver å gi et mere balansert persperktiv.

magnars18:03:37

Min erfaring er vel heller at så godt som ingen gjør det på måten jeg prøver å fortelle om, ikke i JS/TS-verdenen, naturlig nok, men ikke engang i Clojure-verdenen.

magnars18:03:54

Jeg kan si at det er ikke veldig tungvindt, og det er ikke store ytelsesproblemer, men på samme måte som med Clojure generelt så hjelper det fint lite å diskutere. Jeg kan si så mye jeg vil at "du blir vant til parentesene", "joda, selv om funksjonene ikke har side-effekter så får man faktisk gjort noe", og "nei, Clojure er faktisk veldig raskt, selv om det er en lisp" - men det hjelper ikke stort. Man må nesten oppleve det selv.

magnars18:03:16

Det er også derfor jeg i hovedsak bruker tiden min på å vise frem hva som er bra, heller enn å prøve å overtale andre. 🙂

magnars18:03:30

Skjønner at jeg gikk på en smell her i dag, da. Skal gi meg nå!

teodorlu20:03:44

Nei, ikke gi deg!

😘 1
Jakub Holý (HolyJak)09:03:02

Jeg verdsetter at du deler perspektiven og erfaringene dine! Å overbevise folk er vanskelig / umulig men en åpen debatt er likevel veldig givende, IMO

magnars09:03:50

Hyggelig å høre! Men jeg tror jeg kan bidra bedre ved å lage videoer og skrive bloggposter enn å diskutere kvelden lang på slack 😅

augustl18:03:36

shouldComppnentUpdate er vel uansett implementert ut av boksen i alle gui-toolkits til cljs, håper jeg

augustl18:03:49

men det blir vel fortsatt dyrt å gjøre shouldComppnentUpdate på keyup i en liste med tusenvis av elementer (?)

augustl18:03:01

når man har mye nok data får man også problemer andre veien. I CMS-en jeg lager bruker jeg f.eks core.rrb-vector til å representere en flat liste med characters, fordi concat på to vectors (sette inn en character midt inne i lista) er O(N) og man skal ikke ha veldig mye tekst i et tekstfelt før man ikke klarer å svare kjapt nok på keyup på folk som skriver litt fort https://github.com/clojure/core.rrb-vector

augustl18:03:48

jeg opplever også at "Magnar-pattern" funker fint, jeg bruker det. Og hopper ut og gjør ting mere direkte der det trengs. Som Magnar sier, ting som skal følge bevegelsen på musa f.eks. Jeg render text selection med dumdom, men i en egen verden isolert fra resten av appen, så det bare er selve de blå strekene som viser selected text som rendres på mousemove

augustl18:03:46

samme med sortering ved drag & drop, lager en egen datastruktur for å sjekke mot på mousemove, og når det trigger en resort, rendres det på nytt igjennom appen på vanlig måte ved å sette state

augustl18:03:24

så det jeg sier er vel at jeg kan bekrefte at patternet holder mål, og at kjapt snappy GUI ikke løses med reagent, det går dypere

augustl18:03:16

tror også at det stemmer at akkurat det å ha en liste med tusenvis av elementer og bare oppdatere en av de er mindre jobb å få til med reagent. Men erfaringsmessig er det ikke bare tut og kjør med sånne GUI-er, blir fort en del custom greier og knot og optimalisering, så "overheaden" man eventuelt får med "Magnar-pattern" er ikke noe rødt flagg i min bok ihvertfall

cjohansen19:03:33

@isak selvfølgelig er det ikke "bare fordeler", men det er en kjempefordel der som jeg ikke forstår helt hvorfor flere ikke ønsker seg 😊

cjohansen19:03:59

> Jeg ville tro det blir mer tungvint Vel, det kan jeg si deg av årevis med erfaring at det ikke gjør. Det blir åpenbart noe mer eksplisitt, men det er i min bok en fodel. Av og til blir det også litt busywork, men ikke noe som tar betydelig med tid. Dette er et argument jeg ofte leser og som ofte er på formen "det virker veldig upraktisk" (altså kanskje med noe manglende erfaring), som jeg også skrev litt om i megatråden over

isak19:03:40

Jeg tror dere undervurderer litt hvor mye erfaring de fleste har med den pattern. Man kan jo gjøre samme pattern i re-frame - det er bare å bruke færre subscriptions. Enig at de blir vannskelig å overbevise folk, de fleste har jo erfaring med noe som de synes funker. Jeg kan godt gi meg der også, forstår at det blir pinlig å diskutere for folk.

cjohansen19:03:59

Godt mulig jeg undervurderer, men når du skriver "jeg vil tro" så høres det mer ut som gjetning enn praktisk erfaring.

cjohansen19:03:13

Pinlig? Kom igjen, a.

isak19:03:37

Leste jeg Magnar sin melding feil?

cjohansen19:03:27

Ganske sikker på at han ikke syns det var pinlig å diskutere, ja 😊

isak19:03:01

Ok. Det med performance har jeg praktisk erfaring med, forresten.

isak19:03:57

Hundrevis av rader med 10+ editerbare kolonner, da ble det litt tungt å bare sende alt ned.

isak19:03:13

Jeg forstår at man kan jobbe rundt det med onblur, pagination, local state, osv, men det er jo fint hvis man slipper.

magnars19:03:56

Til info så mente jeg ikke at det var pinlig å diskutere (en litt rar ting å syns?), men at det ikke er en effektiv form for overføring av idéer, og jeg i dag hadde brukt for mye tid og krefter på noe som har lite payoff. 🙂

1
isak19:03:21

Ok, jeg har bodd i USA en stund, jeg misforsto sikkert denne: > Skjønner at jeg gikk på en smell her i dag, da.

magnars19:03:41

Stemmer nok, den må ses i sammenheng med setningen over, hvor jeg prøvde å formidle at jeg vanligvis forsøker å etterfølge "show, don't tell".

1
👍 1
slipset20:03:04

Er forøvrig i Bergen og kom dit med fly. Og på flyet kom jeg på ideen om at jeg kanskje skulle se om jeg klarte å implementere zombie-ts? Bare for å se hvordan det ville blitt?

❤️ 1
slipset20:03:31

Men da må jeg jo klare å sette opp et react prosjekt…

slipset20:03:30

og ikke minst, hvor ligger koden til denne sesongen?

teodorlu20:03:26

https://clojurians.slack.com/archives/C061XGG1W/p1647977516090889 Jeg har lest både "En enkel frontendarkitektur som funker" og "Samspill mellom generiske UI-komponenter" før. Skjønte noe, men det var mye som ikke ga mening. Etter dagens Slack-meldinger gir det mer mening.

😊 1
augustl21:03:48

problemet er at Magnar har klart å koke ned det som kunne vært en bok på 300 sider til en bloggpost :) ❤️

🎯 2
augustl21:03:29

er et fint pattern, det. Skulle ønske mere informasjon var tilgjengelig i formen setning ➡️ avsnitt ➡️ artikkel ➡️ bok

augustl21:03:49

nå trenger vi bare boka :thinking_face: @christian767 på tide med bok nummer to? 🥳🥳🥳

👀 2