Fork me on GitHub
#clojure-norway
<
2024-03-14
>
augustl07:03:07

god morgen!

augustl08:03:29

shower thought: om 10 år bør noen gjøre et studie som (antageligvis) viser fordelene med å bruke Clojure i staten. Koden til parenteser-gjengen i mattilsynet lever fortsatt, og den er ikke utdatert, og den oppdateres fortsatt, og null tid er brukt på å oppdatere rammeverk, og ….

augustl08:03:05

tid brukt per teammedlem i mattilsynet på å lage sin egen “React”: 40 timer (?) tid brukt per teammedlem i NAV på å oppdatere React-dependencies: 600 timer

augustl08:03:57

ingen diss til NAV, bare tilfeldig valgt “stor organisasjon” som antageligvis buker React

oddsor14:03:54

Can confirm at vi bruker React, og foreløpig er så kobla til det at designsystemet tilbyr react-komponenter 😢 Men vi har et par folk på huset som har lyst til å fristille oss litt fra React-økosystemet, så krysser fingra for at det vil endre seg 🤞

augustl14:03:29

er en del greier der ute som shippes som web components, så er react-greiene bare en wrapper rundt dem. Det virker jo som en forholdsvis grei sak 🙂

augustl14:03:00

men da må man naturligvis implementere greiene sine uten React da, med “ren js”

magnars08:03:32

jeg tror en skiftenøkkel kastet inn i den tankerekken er at store team har mer glede av standardisering på kjente ting enn små

magnars08:03:52

nok et argument for små team, kan man jo da si

💯 4
augustl08:03:05

haha det er jo sant. Det er bare én av mange fordelene til store teams trollface

cjohansen08:03:30

Det har gått noe mer enn 40 timer inn i replicant 😅

augustl08:03:43

per teammedlem, da! Og bare arbeidstid teller, ikke kveldstid

augustl08:03:59

med mindre folk i store organisasjoner sitter på kveldstid og oppdaterer React-dependencies

cjohansen08:03:35

Men primært min (og @slipset @larstvei @magnars sin) fritid, så kan sikkert holdes utenfor

💯 1
cjohansen08:03:00

hvis du bare teller arbeidstid så er det sikkert close enough

augustl08:03:45

det er også projisert over 10 år - med litt flaks så “lander” vel replicant snart og, og om 5 år sitter man ikke og lager en sykt fet v2 som ikke er bakoverkompatibel med v1, osv

cjohansen08:03:09

nei, målet er å skamme meg over at den har et versjonsnummer med 2024 i 2025 😄

augustl08:03:10

og så skal jeg forte meg å lage replicant-drag-and-drop, og lære masse og komme med en v2 med mye fetere API som man må bruke for å støtte siste versjon av Chrome

😂 1
cjohansen08:03:46

nesten alt replicant gjør funka i IE6 😄

💯 2
cjohansen08:03:17

(med DOM-API-et. “nesten”)

augustl08:03:24

haha, det blir vel som i linux, hvor Linus Torvalds møysommelig sørger for at selv bugs de har shippa vedlikeholdes og ikke endrer oppførsel, og så kommer libc (standardlibbet som ikke er i kernelen) og brekker userspace med jevne mellomrom likevel

cjohansen08:03:16

jeg vurderte her om dagen om det var noen anledning for at replicant burde ha støtte for transisjons-api-ene som kommer, men kom frem til at nei, det fikser du bare sjæl

cjohansen08:03:21

digg å lage fokuserte verktøy ass

augustl08:03:54

(hvorfor venter on-next-frame to ticks av requestAnimationFrame, og ikke ett?)

cjohansen08:03:17

det har jeg ikke noen god forklaring på, annet enn at det er nødvendig

😂 1
slipset08:03:37

“if you have to ask that question, you’ll never be able to understand the answer”

pez08:03:12

“Jag försökte med en, och det räckte inte.”

cjohansen08:03:34

Det er helt riktig. Og så sjekka jeg hva snabbdom gjorde for å få til den samme featuren, og de har også to ticks 🙃

pez08:03:02

De kanske vet varför, men höll det hemligt.

slipset08:03:36

I helt andre nyheter, så tror jeg kanskje jeg har forstått noe idag 🙂

👀 1
slipset08:03:34

Jeg har litt vondt for å formulere det ennå, men det har noe med typer å gjøre, hvordan vi koder når vi ikke har typer og hvordan man har lett for å kode når man har typer.

🍿 6
slipset08:03:00

Så greia er at jeg lager en ny pakke/modul/whatever på frontenden. En api-pakke. Altså en dings som gir funksjoner for å kunne snakke med apiet. For enkelhetsskyld, så har vi funksjoner av typen:

const fetchFoo = (id:Id): Promise<Foo|Error>  =>  ...
Det første halvsmarte jeg gjorde var å introdusere en type:
type ApiResponse<T> = Promise<Foo|Error>;
Da kunne jeg endre på retur typen til disse funksjonene (det ble etterhvert lurt å ha en feiltype til. I tillegg, og jeg tror dette var det riktig smarte, så ble jeg lurt til å lage et type predikat sånn omtrent som:
const isError= (x:unknown) x is Error => ...
Som lar deg gjøre ting som:
const result = api.fetchFoo(id);
if (isError(result) { // her vet kompilatoren at vi har en Error } else { // her vet kompilatoren vi en Foo }
Dette kunne jo fint sikkert vært implementert som:
if (result instance of Error) { ...}else {...}
Men trikset er at hvordan vi implementerer feilgreia er skjult bak isError Så noen vil sikkert bare si at jeg har oppdaget enkapsulering, og det stemmer nok, men min påstand er at når man koder i visse typer statisk typa språk, så er det lett å glemme enkapsulering, fordi “røde squigglies redder dagen”, men når man koder utypa så blir man tvunget til det, nettopp på grunn av mangelen på squigglies.

slipset08:03:27

Og, kanskje det er dette Rich snakker om i en eller annen talk (Speculation?) at det er fint å kunne switche på typer, men når du har type Foo = Bar | Baz og du har glemt å enkapsulere dette, og du ønsker at en Foo nå også skal kunne være en Qix , altså: type Foo = Bar | Baz | Qix Så må du rundt i tusen filer for å legge til en ny case i switch’en din.

magnars08:03:57

Oppsummerer jeg det riktig sånn her? "Når du koder med typer er det lett å klare seg uten nyttige abstraksjoner, fordi du kan så lett lene deg på editor-krykka di?"

🎯 1
❤️ 2
augustl08:03:49

not sure if good or bad at man må rundt i tusen filer - for man har jo eksplisitt håndtert de andre tilfellene, og nå er det et tilfelle til som ikke håndteres, og det sier typesystemet i fra om - og det er jo bra? Men så er problemet i praksis at 90% av de stedene så er håndteringa “gjør ingenting”? Men, betyr det at man manglet en “else” man burde hatt der uansett? Clear as mud…

augustl08:03:29

kanskje anti-patternet ikke er typer i seg selv, men at switch-statements på typer ut av boksen burde feile om du ikke har en generisk “else” i switchen sånn at du får map-aktig oppførsel. Så kan man heller opte inn til “her vil jeg alltid håndtere alt” (space shuttle style)

augustl08:03:49

> “The computing scientist’s main challenge is not to get confused by the complexities of his own making.” -- Edsger Dijkstra

teodorlu09:03:15

> Oppsummerer jeg det riktig sånn her? “Når du koder med typer er det lett å klare seg uten nyttige abstraksjoner, fordi du kan så lett lene deg på editor-krykka di?” kanskje litt krasst, men jeg er ikke uenig! Gode navnerom (gode abstraksjoner) er jo målet. Og gode abstraksjoner er utrolig deilig å jobbe med. Jeg vil kanskje passe meg litt før jeg generaliserer fra Typescript til alle språk med typer. Jeg er fremdeles kjempeglad i Haskell. Jeg foretrekker Clojure i praksis, men tror vi har noen ideer vi kunne vunnet på å stjele.

cjohansen09:03:56

På den ene siden har du: > Når du koder med typer er det lett å klare seg uten nyttige abstraksjoner, fordi du kan så lett lene deg på editor-krykka di? På den andre: > Når du koder uten typer er det lett å være inkonsekvent/lage masse ad-hoc representasjoner av samme konsept fordi du ikke trenger å eksplisitt formulere typen på sammensatt data (eks maps) Altså to måter å bomme på "nyttige abstraksjoner", på hver sin ytterkant.

cjohansen09:03:11

Personlig skulle jeg ønske at Rich ikke ga seg før han fikk til spec, sånn at vi hadde en godt integrert måte å beskrive data en funksjon tar som insentiverte oss til å kalle den samme tingen for det samme (type namespaced keys etc)

👀 2
2
augustl09:03:18

“dynamisk typing krever så mye disiplin som man slipper med statisk typing” - funny because it’s not true

😁 1
😸 1
cjohansen09:03:49

Om jeg leser @slipset rett så kjenner jeg meg litt igjen, for vi har en variant av samme felle i den dynamiske verdenen: Å gjøre et lokalt oppslag i et map, der man egentlig skulle hatt et funksjonskall. (when (:error res) ,,,) funker en stund, helt til man trenger å sjekke en ting til og angrer på at man ikke gjorde (when (error? res) ,,,). Eller misforstår jeg?

👍 1
cjohansen09:03:37

Dette er litt kinkig, for en av fordelene med data er at man bare kan lese dem, så det er ikke ønskelig å gjemme alt bak oppslagsfunksjoner. Men kanskje det er noe der om at man bør putte avgjørelser i en funksjon?

augustl09:03:50

data er jo også en abstraksjon i seg selv, når er det riktig å sjekke på :error og når er det riktig med en funksjon av et map?

slipset09:03:55

Du misforstår ikke @christian767 En vei ut av akkurat det eksemplet er vel å bruke namespace’a keywords? En annen ting som oppstår fordi man ikke trenger å lage nyttige abstraksjoner, er at man heller ikke får gode byggeklosser som man kan gjenbruke. Det medfører lengre utviklingstid (fordi vi må skrive samme ting om igjen, gjerne på en litt annen måte) og større kodebase, som gjør at det blir enda vanskeligere å finne eksempler på de abstraksjonene man burde hatt, som igjen fører til at man reimplementerer og får en enda større kodebase.

cjohansen09:03:47

Jeg er bare ikke helt overbevist om at dette er et type-problem

1
augustl09:03:52

om man er lat, og unngår design og abstraksjoner, får du problemer - enten du bruker statisk eller dynamisk typing?

🎯 2
slipset09:03:52

Og kanskje at med typesystemer så kommer du lenger med den framgangsmåten enn hvis du ikke har det?

augustl09:03:54

hmm, det kan være ja. Guard rail driven programming? 😄

😸 1
teodorlu10:03:22

Kanskje et tiltak er å gå fram litt roligere, og bruke litt mer tid på programvaredesign — ikke bare kode opp det første man ser for seg så fort som overhode mulig?

magnars12:03:40

I forbindelse med at jeg sitter og forfatter tirsdagens bloggpost så fant jeg tilbake til denne fantastiske klassikeren. Anbefales på det mest hjertelige. 😄 https://www.usenix.org/system/files/1311_05-08_mickens.pdf

magnars12:03:36

La meg dra ut ett lite avsnitt for å sette standarden 😅

😂 6
😁 1
leifericf13:03:25

I går fanget jeg opp en tråd i LFE-miljøet som fleipet med hvordan (comment ...) er en rar/tåpelig greie. Selv Virding forstod ikke verdien. "Men man kan jo bare bruke ;; ... og copy/paste code til REPL!" Men når jeg viste/forklarte "REPL-connected editor" ble de litt mind-blown. Det er ganske utrolig hvor lite som skal til får å krysspollinere disse miljøene, altså! Lære av hverandre. Jeg leter etter noe å bringe tilbake til Clojure også. En annen ting jeg tenkte: Nå tar jeg "REPL-connected editor for gitt." LFE er en Lisp. Når selv ikke andre Lisp utviklere forstår idéen og verdien av det, så forstår jeg bedre hvorfor det er vanskelig å selge inn idéen til andre som ikke er kjent med Lisp i det hele tatt.

leifericf13:03:47

Litt av tråden 🙂

🔥 2
pez07:03:42

Något att vara medveten om vad gäller ignored är att comment är ett macro som inte är mycket mer än

(defmacro comment [& body])
D v s, vad som än är i body så kommer comment-utrycket att returnera/evaluera till nil. Det är därför bättre att uttrycka det som att det “evaluerar till nil” än att “det ignoreras”. I praktiken är det ibland samma, och ibland inte.

💡 1
pez07:03:10

Till exempel i någon funktion:

(defn foo []
  :bar
  (commment :baz))
Den kommer returnera nil.

💡 1
pez07:03:15

Eftersom det är ociviliserat att ignorera ut en massa Clojure-kod med ;, finns det en reader tag: #_ som man kan sätta framför ett s-expression/form. Den gör att Readern inte kommer ta med uttrycket i datat som den ger till kompilatorn. Taggen kallas ibland _ignore tag_ eller ignore marker.

(defn foo []
  :bar
  #_ :baz)
Returnerar :bar.
(defn foo []
  :bar
  #_ (if a
       :b
       :c))
Returnerar :bar.

💡 1
pez07:03:13

En sak comment och #_ har gemensamt är vad som nämns i tråden: _Koden behöver kunna parsas_. Vilket inte gäller line comments ; ….

👍 1
magnars13:03:28

Fascinerende hvordan et verktøy ikke kan tas ut av sin kontekst. De fant kommentar-blokken, men ikke de tilhørende bitene, og da gir det ingen mening. Det er som om du har bare spiker og finner en skrutrekker. For en rar hammer! Først når noen viser deg skruene så gir det mening.

👍 1
leifericf14:03:51

Yeah! Men jeg trodde dette med "interaktiv/REPL-driven development" var en velkjent greie fra Common Lisp for mange tiår siden, og lenge før Clojure. Typ via SLIME for Emacs, etc. Derfor overrasket det meg litt av slev Virding, skaperen av LFE (en Lisp), attpåtil for BEAM (en svært dynamisk VM), ikke var kjent med det. Er dette en greie som er unikt for Clojure? Eller kanskje vi bare har dratt det til det ekstreme i Clojure-miljøet.

magnars14:03:13

Emacs er i hvert fall sånn, og det er jo 50 år gammelt, så ja, burde ikke være helt ukjent.

👍 1
cjohansen15:03:20

De starter med en misforståelse: de tror man skal kopiere kode fra blokka og lime den inn et annet sted

cjohansen15:03:29

Jeg tenker at REPL-forståelsen har 3 nivåer: 1. Et shell for programmeringsspråket ditt. Kan kjøre små kodesnutter 2. Et integrert verktøy som lar deg evaluere kode fra editoren din 3. Koden og prosessen er samme sak, alt kan evalueres til enhver tid, Her kommer comment-blokkene på plass

👍 1
cjohansen15:03:04

De aller fleste er på 1., noen er på 2., og mange går glipp av gullet i nummer 3 (inkludert noen Clojure-folk)

leifericf16:03:35

Jøss, jeg er kanskje stuck nr. 2 faktisk :thinking_face:

cjohansen16:03:50

Jeg klarer ikke helt å formulere forskjellen på 2 og 3. Når du har comment i fingrene (og koden din!) så mener jeg du er i mål 😄

👍 1
Olav17:03:08

kanskje en liten digresjon, meeen.. Var innom (comment ...) i en diskusjon i går hvor noen snakket med noen om hvordan doc-strenger i Rust med rustdoc fungererer. Altså eksempelkode man skriver i doc-strenger blir også sjekket ved kompilering, og kan kjøres som enhetstester om jeg husker riktig. I clojurekode har jeg har ofte endt opp med at noen comment-blokker liggende igjen som eksempelkode der det passer seg. Det kunne vel i en del tilfeller også vært nyttig å brukt den samme koden som enhetstester (litt ala rustdoc)?

cjohansen19:03:01

Det der kommer fra python tror jeg

cjohansen19:03:29

Stuart halloway har laget noe greier for å fange REPL sesjoner som tester