This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-02-02
Channels
- # announcements (4)
- # babashka (1)
- # beginners (4)
- # cider (4)
- # clerk (3)
- # clojure (25)
- # clojure-brasil (5)
- # clojure-europe (6)
- # clojure-nl (1)
- # clojure-norway (48)
- # clojure-uk (4)
- # clojuredesign-podcast (3)
- # clojurescript (1)
- # conjure (1)
- # emacs (23)
- # hyperfiddle (3)
- # jobs (6)
- # lsp (12)
- # off-topic (5)
- # polylith (13)
- # reagent (8)
- # reitit (18)
- # sci (20)
- # shadow-cljs (8)
- # specter (3)
- # squint (3)
Av og til glemmer jeg litt hvor fantastisk immutability er. Fra greiene over, så gjør vi ting som
(baz (assoc ctx :foo bar))
Dette kan vi gjøre helt trygt fordi immutability. Ingen, bortsett fra baz og de funksjonene den kaller vil se denne endrede ctx
’en.
Tenk på dette i en Spring verden. Da må du ha life cyclen til ctx
i hodet for å forstå om dette er trygt eller ikke, mest sannsynlig er det ikke det, og du må minst huske på å cleare :foo
når kallet til baz
er ferdig.
Godt med alle de tinga man ikke behøver tenke på.
Ja, det er ikke lenge siden jeg satt og beundret akkurat samme situasjon. Jeg fikk et flash fra gamledager av "er dette trygt?" med tilhørende ubehag, helt til jeg skjønte at ... Jeg skriver Clojure nå. Det er helt trygt. 😄
Ja, det er ikke lenge siden jeg satt og beundret akkurat samme situasjon. Jeg fikk et flash fra gamledager av "er dette trygt?" med tilhørende ubehag, helt til jeg skjønte at ... Jeg skriver Clojure nå. Det er helt trygt. 😄
> Dette kan vi gjøre helt trygt fordi immutability. Ingen, bortsett fra baz og de funksjonene den kaller vil se denne endrede ctx
’en.
>
> Tenk på dette i en Spring verden. Da må du ha life cyclen til ctx
i hodet for å forstå om dette er trygt eller ikke, mest sannsynlig er det ikke det, og du må minst huske på å cleare :foo
når kallet til baz
er ferdig.
Jeg vil også legge inn et slag for FP+ren data. Du får de samme immutability-garantiene med Haskell. Men du kan ikke bruke assoc
og dissoc
, fordi du må tenke typer på dataen din. Ref gårsdagens “https://clojurians.slack.com/archives/C061XGG1W/p1706777452109809”. Går ikke i Haskell, fordi assoc
og dissoc
ikke funker med typene.
Bittelitt uenig i deg her. Vi har modellert ctx
omtrent sånn:
(s/def ::ctx (s/keys :req-un [::org
::org-ds
::ardoq-ds
::org-db
::user-db
::common-db
::user]
:opt-un [::branch ::scope ::client-request-id :context/provenance ::user-time]))
Det betyr jo i f.eks Haskell-land at du har en Maybe(userTime)
eller deromkring (evt en Union type greie). Uansett, vi har definert opp ctx
til å ha en del greier som man da også i Haskell-land ville kunne endre på.Det jeg ikke kunne gjort i Haskell (gitt den definisjonen over) var
(assoc ctx :jeg-bare-trengte-denne-akkurat-nå bla)
(og, for å gi litt credit til Haskell, det er jo f*ckings umulig å vite hva folk assoc
’er på ctx
rundt om i kodebasen. Det over er jo muligens kanskje et hint om et subset som kanskje er i bruk 🙂
dere har da et sett med funksjoner som alle tar et ctx
-argument først, ala
(f ctx x y z)
?Ja, du ser jo det fra spec’en, den har vel en 4 -5 db connections til mongo og pg.
Vi har funksjoner som gjør
(defn bla [ctx]
(fn [lol]
(repo/query! foo-repo/config ctx pq/all)))
Og da har du plutselig mista oversikten…Her kunne kanskje Haskell ha hjulpet, i og med at type-systemet ville tracka at du var i impure-land?
Jepp, du måtte returnert en IO noe
hvis du skulle kunne gjort sideeffekter. (selv om det går an å ødelegge den garantien med unsafePerformIO
)
En sånn halvveis artig greie som jeg kunne tenkt meg å leke med når jeg blir pensjonist er hvis du tar funksjonen over og gjør den om til:
(defn bla []
(fn [lol]
(make-query foo-repo/config pq/all)))
Dvs at heller enn å utføre effekten, så beskriver du den, og så drar du det ut av beskrivelsesland og inn i bivirkningsland helt på slutten.Mao, typen til bla
måtte vært Ctx -> IO Noe
, der Noe
er typen til resultatet fra (repo/query! ,,,)
Da har du kommet tett på hvordan Haskell funker i praksis! Du kan fint evaluere noe som gir et IO
-resultat, men det skjer ikke noe hvis det resultatet ikke “bobles opp” til at IO-effekter skal kjøres.
Det er litt kult hvis man tenker på dette litt (og det hender det at jeg får tid til å gjøre)
Heller enn å kombinere resultatet fra flere queries, kan man kombinere queriene og få et resultat.
Hva vil motivasjonen være for å “dytte sideeffektene helt til slutten”? Jeg kjøper at kontroll på sideeffekter er nyttig. Men ville du konkret vunnet feks ergonomi fra REPL-en eller testbarhet hvis du hadde gjort det i dag?
Litt avhengig av alt, lissom, men en tur til databasen koster skjorta. Så la oss ta no’ helt gal kode:
(let [record (db/query! db record (by-id 3)]
(map #(db/query! db song (by-id %)) (:songs record))
Dette er så feil det kan få blitt, men sånn var en del av koden da jeg kom til ardoq, selvom den kanskje egentlig så ut som:
(let [record (record-dao/by-id db 3)]
(map #(song-dao/by-id db %) (:songs record))
Klassisk n+1 drittkodeMen, det kan også være (og det ser vi) at PG snubler i indeksene sine og at av og til så er det billigere å utføre to spørringer enn det er å konbinere dem.
Jepp. men ville tro at man står fritt til å skyte seg selv i foten med Datomic også, selvom det kanskje er vanskeligere enn med Mongo.
(let [record (record-dao/by-id db 3)]
(map #(song-dao/by-id db %) (:songs record))
Er vel fullt mulig i Datomic også, men det gir kanskje mindre utslag på performance?hvis du kjører spørringer mot en peer som kjører i samme prosess som JVM-koden din, kan du vel gjøre så mange spørringer som du vil uten at det er noe problem?
Det var det ene, det andre jeg tenkte på er at les i prinsippet er pure, og side-effekter utføres ved å bygge transaksjoner av data
> les i prinsippet er pure
Så lenge man sender inn en DB-versjon til funksjonen, feks ved å putte en DB-versjon på et ctx
-map eller et req
-map?
Jeg synes det er helt utrolig hvor dypt det funksjonelle kaninhullet går. Jeg trodde liksom jeg hadde skjønt det da jeg skrev Haskell for første gang, og kunne stole på hva som skjedde hvor — i kontrast til java-kode jeg hadde skrevet tidligere. Men det har så utrolig mye å si for arkitektur av én app, og design av systemer hvor flere apper skal snakke sammen.