This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-03-14
Channels
- # aleph (4)
- # announcements (10)
- # babashka (21)
- # beginners (67)
- # biff (7)
- # calva (4)
- # clojure (40)
- # clojure-europe (11)
- # clojure-gamedev (17)
- # clojure-losangeles (3)
- # clojure-madison (1)
- # clojure-nl (1)
- # clojure-norway (78)
- # clojure-uk (3)
- # clojurescript (83)
- # core-typed (18)
- # cursive (1)
- # datalevin (2)
- # datomic (2)
- # gratitude (2)
- # hyperfiddle (56)
- # introduce-yourself (1)
- # london-clojurians (1)
- # matcher-combinators (10)
- # membrane (161)
- # polylith (16)
- # portal (4)
- # reitit (4)
- # releases (3)
- # ring (2)
- # shadow-cljs (9)
- # squint (2)
- # timbre (10)
- # xtdb (14)
- # yamlscript (1)
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 ….
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
ingen diss til NAV, bare tilfeldig valgt “stor organisasjon” som antageligvis buker React
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 🤞
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 🙂
jeg tror en skiftenøkkel kastet inn i den tankerekken er at store team har mer glede av standardisering på kjente ting enn små
med mindre folk i store organisasjoner sitter på kveldstid og oppdaterer React-dependencies
Men primært min (og @slipset @larstvei @magnars sin) fritid, så kan sikkert holdes utenfor
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
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
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
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
Hvis du vil caniuse-e replicant: https://github.com/cjohansen/replicant/blob/main/src/replicant/dom.cljs
Det er helt riktig. Og så sjekka jeg hva snabbdom gjorde for å få til den samme featuren, og de har også to ticks 🙃
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.
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.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.
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?"
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…
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)
> “The computing scientist’s main challenge is not to get confused by the complexities of his own making.” -- Edsger Dijkstra
> 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.
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.
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)
“dynamisk typing krever så mye disiplin som man slipper med statisk typing” - funny because it’s not true
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?
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?
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?
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.
om man er lat, og unngår design og abstraksjoner, får du problemer - enten du bruker statisk eller dynamisk typing?
Og kanskje at med typesystemer så kommer du lenger med den framgangsmåten enn hvis du ikke har det?
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?
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
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.
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.Till exempel i någon funktion:
(defn foo []
:bar
(commment :baz))
Den kommer returnera nil
.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
.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 ; …
.
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.
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.
Emacs er i hvert fall sånn, og det er jo 50 år gammelt, så ja, burde ikke være helt ukjent.
De starter med en misforståelse: de tror man skal kopiere kode fra blokka og lime den inn et annet sted
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
De aller fleste er på 1., noen er på 2., og mange går glipp av gullet i nummer 3 (inkludert noen Clojure-folk)
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 😄
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)?