clojure-norway

mokr 2025-12-19T06:41:32.137589Z

Morn!

msolli 2025-12-19T06:44:27.075689Z

Morn!

gunnar 2025-12-19T06:48:48.784909Z

Morn!

hypirion 2025-12-19T07:20:46.225659Z

Morn!

eaj 2025-12-19T07:25:27.621079Z

God morgen!

teodorlu 2025-12-19T07:39:49.677739Z

morn!

slipset 2025-12-19T08:52:26.225589Z

Mrn

emil0r 2025-12-19T09:13:26.014999Z

Morn

Zeniten 2025-12-19T10:57:22.480799Z

Morn!

boosja 2025-12-19T11:01:36.505699Z

Morn! 🎄

teodorlu 2025-12-19T11:24:24.182909Z

Jeg vil slå et slag for førsteklasses sider og førsteklasses ruter i Clojure-apper! Tidligere har jeg ofte sittet med en router som en svær dispatch-mekanisme or å finne ting. Det siste året har jeg fått en del av C&M sine ideer under huden. En idé jeg liker særlig godt er førsteklasses sider og førsteklasses ruter. Dette er en rute i systemet vårt: ["kjent-sted" :kjent-sted/id]. Denne ruten dekker feks https://matnyttig.mattilsynet.no/kjent-sted/nordkapp. (ikke en offentlig side, dessverre, vi lager kun internverktøy for nå). 🧵

teodorlu 2025-12-22T12:07:46.652309Z

Jeg stirret på en variant uten symboler og uten requiring resolve. Og jeg klarte ikke få meg selv til å like det! Så jeg tror dette er et tilfelle hvor jeg faktisk setter pris på symboltypen vi har i Lisp. Koden jeg skrev underveis i den øvelsen dyttet meg imidlertid til å skrive denne lille testen:

(def side1 "side1")
(def side2 "side2")

(def kilde
  {:id->page-var
   {"id1" #'side1
    "id2" #'side2}})

(deftest kilde->sider
  (is
   (= (set (hent-sidene/kilde->sider `kilde))
      #{"side1" "side2"})))
… som jeg synes ble riktig så hyggelig. Og den er kun mulig å skrive sånn fordi jeg kan sende symbolet inn til hent-sidene/kilde->sider!

teodorlu 2025-12-19T11:25:40.741579Z

Tilsvarende er dette en sidedefinisjon:

(ns kontoret.sider.kjent-sted.page
  (:require [kontoret.sider.kjent-sted.ui :as kjent-sted-ui]
            [matnyttig.page-definition :as page-definition]
            [matnyttig.ui.layouts :as layouts]))

(def page
  (page-definition/define
    {:id :pages/kjent-sted
     :route ["kjent-sted" :kjent-sted/id]
     :layout layouts/app-layout
     :required-permissions #{:rettighet/føre-tilsyn}
     :render #'kjent-sted-ui/render
     :data-requests
     [{:feed [:feed/kjent-sted {:kjent-sted/id [:params :kjent-sted/id]}]
       :as :kjent-sted}]}))
Hvorfor er dette gøy, da? Sider og ruter blir håndfaste! Jeg skrev sitemap i dag. Sidekart, om du vil! Dette er koden som finner alle sidene:
(def sidekilder '(kontoret.sider.index/page-index
                  kjokkenet.sider.index/page-index))

(defn kilde->sider [kilde]
  (->> kilde requiring-resolve deref :id->page-var vals (map deref)))

(defn side->sidedata [side]
  (select-keys side [:id :route]))

(defn finn-sidedata []
  (->> sidekilder
       (mapcat kilde->sider)
       (map side->sidedata)))

teodorlu 2025-12-19T11:26:51.591559Z

siden rutene også er førsteklasses, og parameterne globalt identifiserbare (nøkkelord med navnerom), kan vi også generelt fylle inn eksempelparametre til sidekartet:

(def eksempelparametre
  {:kjede/id "burgerking"})

(defn fyll-inn-eksempelparametre [route]
  (mapv #(get eksempelparametre % %) route))
… som til slutt gir oss klikkbare lenker til enkelte av sidene på sidekartet.

gunnar 2025-12-19T12:02:26.465229Z

Støtter meg bak dette! Veldig nyttig med kolokalisert rute- og sidedefinisjon, og ikke minst request-definisjoner også 🤩

🎉 1
hypirion 2025-12-19T12:15:42.788039Z

Hvordan er kontoret.sider.index/page-index definert, og hvorfor brukes requiring-resolve her? Det er nok noe jeg ikke helt skjønner vil jeg tro 😊 Også er jeg litt usikker på hva du mener med førsteklasses sider og ruter. Altså at de er verdier du kan kjøre spørringer på, og at de ikke er opake?

teodorlu 2025-12-19T12:22:03.041059Z

> Hvordan er kontoret.sider.index/page-index definert Vi har litt kodegenerering på plass. En dev-funksjon for å lage, slette og døpe om sider. Indeksene blir laget ved å se på sidedefinisjoner (kondo find-usage av page-definition/define).

teodorlu 2025-12-19T12:24:58.775989Z

> hvorfor brukes requiring-resolve her Det ville vi sikkert gravd dypere i hvis vi satt samme og så på koden nå! Det korte svaret er sykliske avhengigheter. indeksen laster inn alle sidene, og nå er sidekart-siden "avhengig" av å vite side-indeksen. Det lengre svaret er at sidekart-siden ikke vet om alle sidene, siden det er løst i en feed. Så dette kan kanskje like gjerne være en statisk avhengighet 🤷 (`:require`) Det tredje svaret er at vi kan, det funker, og jeg ikke ser noen videre problemer med det!

teodorlu 2025-12-19T12:25:45.795769Z

> Også er jeg litt usikker på hva du mener med førsteklasses sider og ruter. Altså at de er verdier du kan kjøre spørringer på, og at de ikke er opake? Nettopp — de er data. Rutingen er ikke en funksjon fra URL til sideeffekt, rutingen er avledet fra sidedefinisjonene. Data 🎉

teodorlu 2025-12-19T12:30:10.914769Z

@hypirion hva ville du tenkt? "ikke bruk dynamisk require med mindre det faktisk er nødvendig"?

hypirion 2025-12-19T12:54:17.241099Z

Jeg har ikke noen spesielle tanker rundt det altså, bare det at det er unormalt. Lurte på om det var noen grunn til hvorfor. Og... vel, ja, ikke bruk dynamisk require om du ikke trenger.

teodorlu 2025-12-19T13:46:59.420189Z

Det var vel noe med at systemet er interaktivt, så jeg ønsker å slå opp "hvilke sider har vi nå igjen?" på tidspunktet koden blir kjørt, i stedet for å innføre en hard avhengighet. Men det går jo an å slå opp en var runtime også thinking-face

teodorlu 2025-12-19T13:48:21.296689Z

Jeg ser nå at Clojure-LSP ikke finner referanser til kvalifiserte symboler 😔 Så det er kanskje grunn nok til å la være.

teodorlu 2025-12-19T13:54:26.496539Z

Uten dynamisk require:

(ns kontoret.feeds.hent-sidene
  (:require [refinery.source-definition :as source-definition]
            kjokkenet.sider.index
            kontoret.sider.index))

(defn kilde->sider [kilde]
  (->> kilde :id->page-var vals (map deref)))

(defn side->sidedata [side]
  (select-keys side [:id :route]))

(defn finn-sidedata []
  (->> [kontoret.sider.index/page-index kjokkenet.sider.index/page-index]
       (mapcat kilde->sider)
       (map side->sidedata)))
Jeg synes egentlig det blir litt styggere? Hvis man def-er opp sidekildene i hent-sidene, må def-en holdes i synk med funksjonen for å finne sidedata. Og hvis man ikke def-er opp sidekildene, har man ikke lenger sidekildene som data tilgjengelig i navnerommet.

hypirion 2025-12-19T14:15:29.703459Z

(defn sidekilder []
  [kontoret.sider.index/page-index
   kjokkenet.sider.index/page-index])

...

(defn finn-sidedata []
  (->> (sidekilder)
       (mapcat kilde->sider)
       (map side->sidedata)))
Men jeg er enig i at det er teit å "wrappe" sidekilder her, uavhengig av om det er en var med symboler du må dereffe eller som en funksjon du må kalle. Men det er jo derfor man bruker https://github.com/tonsky/clj-reload

teodorlu 2025-12-19T15:30:26.116029Z

ja, ikke sant. Det kommer litt an pa bruken. Jeg har lest litt av ui-koden tonsky skriver med ui-biblioteket sitt, og der bruker han mye def. Og deretter clj-reload for a synke def-ene. (Beklager fravar av norske bokstaver - jeg har en moroklump av en telefon. Fysisk tastatur som dessverre mangler norske bokstaver)

👍 1
2025-12-19T19:29:29.822619Z

tldr: klasse-hierarkier setter opp begrensninger i kommunikasjon mellom deler av koden. Med andre ord, OO er offer for Conway's Law 😱😭 https://youtu.be/5IUj1EZwpJY?si=TJ4TWWDmtsNXN_ta