This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-10-16
Channels
- # aleph (73)
- # babashka (12)
- # beginners (17)
- # calva (9)
- # clerk (8)
- # clj-otel (1)
- # clojars (8)
- # clojure (3)
- # clojure-europe (13)
- # clojure-nl (3)
- # clojure-norway (66)
- # clojure-uk (3)
- # clojuredesign-podcast (2)
- # clojurescript (11)
- # clr (8)
- # conjure (2)
- # core-typed (1)
- # data-science (11)
- # datahike (4)
- # etaoin (5)
- # events (1)
- # graalvm (2)
- # honeysql (27)
- # hyperfiddle (26)
- # introduce-yourself (3)
- # lsp (3)
- # membrane (1)
- # off-topic (60)
- # polylith (20)
- # practicalli (4)
- # reitit (3)
- # shadow-cljs (18)
- # specter (2)
- # xtdb (1)
Kanskje dumt eller no. I TS/JS har man nå fått (eller sikkert hatt en stund) foo?.bar
som basically gir deg en slags nil punning, dvs du trenger ikke sjekke om foo
er null før du prøver å aksessere bar
. Gitt at foo
er null, ville foo.bar
kasta en exception, mens foo?.bar
returnerer null.
Jeg rynker litt på nesen når jeg ser foo?.bar
i koden vår og tenker at disse frontenderne ikke har kontroll på noe som helst , men klarer ikke helt å fri meg fra at vi gjør jo dette implisitt i Clojure i og med at (:bar foo)
returnerer nil
når foo
er nil
Har jeg blitt schitzofren?
js/ts er jo litt i midten av “typene beskriver det som er” og “ting er dynamisk”. Jeg trives godt i Clojure (ting er dynamisk) og godt i Elm (typene beskriver det som er).
Usikker på om midtpunktet mellom de er et sted jeg ønsker å være. Enten gjør jeg en jobb med modellering av data så dataen passer inn i typene, og jeg har kontroll på hvor typene er på et gitt tidspunkt. Ellers koder jeg defensivt mot data, og returnerer nil
hvis jeg ikke kan returnere noe fornuftig (med feks when-let
).
(så hvis du er schitzofren er jeg litt schitzofren jeg óg)
For CSS: Det er et hav av valg hva gjelder styling og CSS, og jeg sliter litt med å se hvilke av disse "CSS rammeverkene" som er best fit med Clojure, Hiccup og HTMX. Bruker dere https://github.com/noprompt/garden (eller noe annet) i kombinasjon med Hiccup, og bruker dere https://getbootstrap.com, https://bulma.io, https://get.foundation, https://tailwindcss.com, https://m2.material.io/develop/web, eller andre "CSS rammeverk?" Hva liker dere (ikke)?
Jeg tror at problemet mitt er mer å få ting til å se pent ut enn hvordan jeg implementerer det pene.
Jeg spurte en front-end utvikler kollega her nå. Hun sier at alle de kule kidsa bruker Tailwind i disse dager.
Samme her, @U04V5VAUN! Jeg blir så utrolig irritert av å gjøre front-end stuff 😅 "Neeei! Ikke sprett bort der da, din jævel!"
Tanken var å få ting til å se relativt pent ut raskt uten å måtte gjøre så mye CSS-fikling selv.
Du har løst problemet med så få deps som over hodet mulig.Ja, det er et veldig godt poeng. Kanskje jeg må endelig må tvinge meg selv til å bli komfortabel med CSS fra first principles.
https://github.com/slipset/www.bonzai-hvaler.no/blob/main/index.html er min siste reise i den verdenen. Dette er omtrent det enkleste jeg kunne komme opp med for å løse et problem.
"Det var et interessant navn på et bibliotek! Åja… Det er en nettside. Er den for bonsaitreentusiaster på Hvaler? Så sært! Nei, det er en restaurant! LOL!"
Jepp. Har hytte på Hvaler, Ei dame har starta opp en thai greie der, de “fantes” bare på facebook med meny i bilder , så jeg kjøpte domenet, og mekka meny i html.
Hovedpoenget mitt er vel at dette kunne vært uendelig mer komplisert, men det er det ikke.
Jeg bruker Bulma for når jeg bare vil ha noen ferdige klasser å slenge på elementene for å få det “godt nok”. Når man ikke har noen designer, eller er spesielt flink med design selv (meg begge deler), er det fint å bare bruke noe som ser greit ut fra før. Inkluder CSS-fila, skriv HTML, ferdig.
Hvor på Hvaler er det hun thai-dama holder til, @U04V5VAUN? Skal dit i helga, og det var mye godt på den menyen!
Haha, elsker det @U04V5VAUN 😄
Liker trenden med små thai-sjapper som dukker opp overalt på mindre steder i Norge. Hadde en fantastisk matopplevelse på Ørnes i Nordland i fjor sommer, fra en sånn liten vogn utafor matbutikken.
Det er faktisk to av dem på under 200m. Den jeg har laget meny for er ved bensinstasjonen og ser ut som Jafs.
Jeg synes forøvrig, sånn fra et Product Manager perspektiv at det er litt gøy å se hva en MVP faktisk kan være. Tenk om man var et eller annet selskap som skulle lage nettsted til den sjappa? Automagisk alt mulig, men hvor mye verdi ville det faktisk bringe over at man har en enkel html meny der man kan ringe inn (sånn bortsett fra at de ikke er så flinke til å ta telefonen 🙂?
tailwind er vel på en måte det samme for CSS som “Christian sitt” pattern er for kode - CSS-en vet absolutt ingenting om domenet ditt, og er helt generisk 😄
egentlig er hovedgrunnen til at jeg digger Tailwind at man kan gjøre pseudo selectors og media queries med inline “styles”
Dette er kanskje utrolig pirkete, men… jeg liker at koden kan leses "fra toppen og nedover," slik at hvis funksjon A kaller funksjon B, så er funksjon B under funksjon A i kildekoden. Jeg oppdaget at jeg kan bruke clojure.core/declare
for å oppnå dette. Men er det god praksis, eller hva synes dere om det? Her er et konkret eksempel:
Før:
(defonce server (atom nil))
(defn app [req]
(case (:uri req)
"/" (h/home)
"/greet" (h/greet req)
(h/not-found)))
(defn stop []
(when-some [s @server]
(s :timeout 100)
(reset! server nil)))
(defn start []
(stop)
(reset! server (-> #'app
(wrap-params)
(hk/run-server {:port 3001}))))
(defn -main []
(start))
Etter:
(defonce server (atom nil))
(declare start stop app)
(defn -main []
(start))
(defn start []
(stop)
(reset! server (-> #'app
(wrap-params)
(hk/run-server {:port 3001}))))
(defn stop []
(when-some [s @server]
(s :timeout 100)
(reset! server nil)))
(defn app [req]
(case (:uri req)
"/" (h/home)
"/greet" (h/greet req)
(h/not-found)))
I Clojure kan du ikke bruke kode før den er definert. Det er en styrke (gjør ting veldig forutsigbart), men som @U06BEJGKD er inne på, en tilvenningssak
jeg pleier også å unngå declare — med mindre jeg har to mutually recursive funksjoner, feks eval og apply. (men det er sjelden jeg trenger mutual recursion i praksis!) Noe i hodet mitt liker veldig godt at avhengighetsgrafen er super-eksplisitt. Nå har jeg lest ned til linje 80. Det eneste som kan være i bruk er koden som allerede er skrevet over. Når jeg leser kode, hopper jeg typisk til funksjonen jeg er nysgjerrig på. Så fortsetter jeg å lese funksjonene den funksjonen bruker (bruker “go to definition” og “go back” og “find usages” veldig aktivt i editoren min).
Det hender (sjeldent) jeg bruker declare
hvis jeg vil ha to funksjoner "ved siden av hverandre" fordi de ligner eller noe, men avhengighetene ikke går opp.
støttes, jeg er helt vant med å scrolle nederst til fila for å se “hovedkoden” i Clojure(Script)
urelatert til spørsmålet ditt, @leif.eric.fredheim, jeg synes at koden din begynner å likne et megagodt “hvor bør man starte når man skriver en clojure-app”! Du har en veldig liten kjerne hvor det gir mening å bruke tid på nesten alle bitene du har med (kanskje unntatt wrap-params, vet ikke hva den gjør)
Uten wrap-params
, når jeg går til http://localhost:3001/myhandler?name=param1¶m2
i nettleseren, kommer parameterne inn som en rå tekststreng à la name=param1¶m2
som jeg måtte ha parset selv. Når jeg bruker wrap-params
, får jeg parameterne som et map bak en ny :params
nøkkel som jeg kan bruke i handlerne mine slik: (get-in request [:params "name"])
. Men kanskje det finnes en bedre måte å gjøre dette på uten wrap-params
? Det var den første løsningen jeg fant når jeg søkte rundt etter hvordan en bør parse request parametere.
Jaa. Wrap-params er kanskje fra ring? (jeg mente mer “jeg skjønner ikke hvor denne kommer fra” enn “denne hører ikke hjemme”!)
Aha! Jepp, det er ring.middleware.params
https://github.com/ring-clojure/ring/blob/1.9.0/ring-core/src/ring/middleware/params.clj#L48
Ha! Det er ikke så dumt å dusje en gang i blant. Jeg kom plutselig på talken jeg skal sublitte til alle konferanser som et i neste år: «10 years with Clojure». Den lar meg snakke om alt jeg synes er lurt :). Og det som trigget ideen er web-appen til @leif.eric.fredheim :)
Jeg hadde mitt første betalte Clojure-oppdrag i 2013! Men måtte krype tilbake til JS-verdenen en liten stund etterpå
Av nysgjerrighet, hvor godt kjent var du med Clojure (eller LISP mer generelt) før du fikk det oppdraget? Var du allerede på Clojure-toget før oppdraget kom?
Oppdraget ba ikke spesifikt om Clojure, det var @U07FCNURX og mitt påfunn 😅 tror ikke jeg hadde gjort veldig mye Clojure før det, husker ikke helt akkurat når jeg plukka det opp. Jeg fikk sansen for Lisp via Emacs Lisp, det var vel kanskje et år eller to i forveien.
Det er digg med kunder som stoler på en og lar en gjøre teknologivalgene uten restriksjoner 🔥
Det viser seg forøvrig at jeg roter noe fælt. Dette oppdraget var i 2014, ikke 2013
Det var relativt enkelt å bruke https://bulma.io i Hiccup. Eksperimenterte litt med å lage "templates" via Hiccup og endte opp med dette:
(ns handlers
(:require [hiccup2.core :as h]))
(def headers {"Content-Type" "text/html; charset=UTF-8"})
(defn hiccup-html->str [hiccup]
(-> hiccup (h/html) (str)))
(defn inject-body [content]
[:html
[:head
[:meta {:charset "utf-8"}]
[:meta {:name "viewport"
:content "width=device-width, initial-scale=1"}]
[:title "My App"]
[:link {:rel "stylesheet"
:href ""}]]
[:body
[:section.section
[:div.container content]]]])
(defn home []
{:status 200
:headers headers
:body (-> '([:h1.title "Front Page"]
[:p.subtitle "You are now on the front page."])
inject-body
hiccup-html->str)})
(defn greet [req]
(let [name (get-in req [:params "name"])]
{:status 200
:headers headers
:body (-> `([:h1.title "Greeting Page"]
[:p.subtitle "Hello, " ~name "!"])
inject-body
hiccup-html->str)}))
(defn not-found []
{:status 404
:headers headers
:body (-> '([:h1.title "Page Not Found"]
[:p.subtitle "This page does not exist."])
inject-body
hiccup-html->str)})
Funker gjør det! Men det er kanskje ikke den beste måten å gjøre det på 😅Av nysgjerrighet, hvor godt kjent var du med Clojure (eller LISP mer generelt) før du fikk det oppdraget? Var du allerede på Clojure-toget før oppdraget kom?
Uten wrap-params
, når jeg går til http://localhost:3001/myhandler?name=param1¶m2
i nettleseren, kommer parameterne inn som en rå tekststreng à la name=param1¶m2
som jeg måtte ha parset selv. Når jeg bruker wrap-params
, får jeg parameterne som et map bak en ny :params
nøkkel som jeg kan bruke i handlerne mine slik: (get-in request [:params "name"])
. Men kanskje det finnes en bedre måte å gjøre dette på uten wrap-params
? Det var den første løsningen jeg fant når jeg søkte rundt etter hvordan en bør parse request parametere.