clojure-norway

emil0r 2026-06-10T04:26:22.330889Z

Morn

boosja 2026-06-10T06:07:53.514539Z

Morn!

hypirion 2026-06-10T06:21:08.599709Z

Morn!

eaj 2026-06-10T06:29:18.181909Z

God morgen!

msolli 2026-06-10T06:48:51.335859Z

Morn!

teodorlu 2026-06-10T07:18:01.399959Z

Morn :)

2026-06-10T07:36:55.333699Z

mrn

slipset 2026-06-10T08:03:21.548899Z

@andersmurphy that’s mine! mrn.

leifericf 2026-06-10T08:27:32.265369Z

Morn, morn!

teodorlu 2026-06-10T08:32:06.254699Z

Preferanser for concat parens / cat 🐱?

(concat '(1 2 3) '(4 5 6))
;; => (1 2 3 4 5 6)

(into []
      cat
      ['(1 2 3) '(4 5 6)])
;; => [1 2 3 4 5 6]

(into (sorted-set)
      cat
      ['(1 2 3) '(4 5 6)])
;; => #{1 2 3 4 5 6}

🐱 1
1
teodorlu 2026-06-10T08:33:05.110979Z

Jeg går rundt og tenker at concat er treg, men har ikke gjort noen benchmarks.

msolli 2026-06-10T08:55:49.045699Z

concat er lazy, det er vel det viktigste å vite.

teodorlu 2026-06-10T09:00:41.594549Z

ja, også derfor jeg føler meg skitten når jeg bruker den. Skulle egentlig ønske meg at

(defn concatv [& args]
  (into [] cat args))
var i standardbiblioteket; vi har jo mapv og filterv.

msolli 2026-06-10T09:03:00.282679Z

Ja, den hadde vært fin å ha. Tyr ofte til (into [] ...) for å være sikker på å få en vektor i stedet for noe lazy.

➕ 1
Ivar Refsdal 2026-06-12T14:32:25.452699Z

trur eg tidvis har brukt reduce into [] 🤷

2026-06-10T09:20:45.030779Z

@slipset but I made it popular 🤣

slipset 2026-06-10T09:22:19.335309Z

Fair!

eaj 2026-06-10T10:02:40.187359Z

Trodde du hadde byttet @slipset?

leifericf 2026-06-10T11:30:56.130549Z

"Functional Core, Imperative Shell" er en gjenganger i kanalen vår. Er det her konseptet/mønsteret opprinnelig stammer fra? 🤔https://www.destroyallsoftware.com/screencasts/catalog/functional-core-imperative-shellhttps://www.destroyallsoftware.com/talks/boundaries

2026-06-10T11:42:23.187299Z

Det er der jeg hørte om det, i hvert fall. Har ikke klart å finne noe tidligere. Nevner Gary i dette foredraget, som jeg endelig skal få holde på engelsk på NDC til høsten. 🙂 https://vimeo.com/1115871430

👀 1
leifericf 2026-06-10T11:45:22.791209Z

Takk for info, @magnars! Jeg ble bare litt nysgjerrig på historikken og hvor det kom fra.

gunnar 2026-06-10T20:25:20.755299Z

Vet ikke hva som kom først, men det sammenfaller litt med Ports and Adapters? Ren forretningslogikk i kjernen, "ports" som er interfaces til den "urene" omverdenen, og "adapters" som implementerer interfacene, og så et koordineringslag imellom det hele (tilsvarende imperativt skall). https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)

💡 1
👀 1
2026-06-10T20:59:05.101139Z

høres ut som OO-varianten av det samme, kanskje?

👍 1
gunnar 2026-06-10T21:01:15.795509Z

ja, det stemmer nok bra

cjohansen 2026-06-11T06:23:59.079799Z

Jeg er ikke veldig belest på hexagonal, men inntrykket mitt er at den arkitekturen er mest opptatt av å lage gode verktøy for det imperative skallet, mens fk/is er mest opptatt av å la den funksjonelle kjernen få så mye plass som mulig.

👍 1
leifericf 2026-06-11T06:28:48.362659Z

Elkjøp sine ~200 mikrotjenester er bygget i C# .NET med et internt rammeverk som heter Hexagon (fordi det var hexagonal arkitektur). Alle tjenestene kommuniserer indirekte via Azure Service Bus og Kafka. Lang historie kort: Det var overkomplisert og smertefullt å jobbe med.

cjohansen 2026-06-11T06:31:44.302179Z

Det er i hvert fall noe helt annet enn funksjonell kjerne/imperativt skall. Det er en arkitektur for hver enkelt prosess.

gunnar 2026-06-11T06:57:22.862719Z

Det blir vel arkitektur på to nivåer: ett nivå for selve mikrotjenestene, og ett nivå for koordineringen i mellom. Man kan jo gjerne ha en hexagonal arkitektur inne i alle tjenestene. Relatert er tjeneste-arkitekturen i Walmart som Scott Havens presenterte på DevOps Enterprise Summit i 2019: https://www.youtube.com/watch?v=FskIb9SariI Og de oppfølgende podcastene til Gene Kim: https://itrevolution.com/podcast/the-idealcast-episode-22/ https://itrevolution.com/podcast/the-idealcast-episode-23-2/

👀 1
leifericf 2026-06-11T07:19:18.240149Z

I og med at jeg nå snart bytter jobb til et selskap med mye (gammel) Java kode og en del Kotlin, setter jeg meg litt inn i design patterns igjen. Og oppdager at nesten ingen av dem trengs i Clojure 😅 Det ser ut som de fleste «Gang of Four» patterns er løsninger på OO-greier som ikke finnes her.

gunnar 2026-06-11T07:26:24.702429Z

Haha, det har sikkert rett i 😄

leifericf 2026-06-11T07:27:38.299109Z

OO-greier, mutable state og concurrency.

leifericf 2026-06-11T07:30:00.543569Z

Hvis man tar bort alle patterns som har med de tingene å gjøre så er det lite igjen.

gunnar 2026-06-11T07:30:55.782499Z

Jeg tok kurset til Martin Oderski og Co. funskjonell programmering i Scala for mange år siden. Siste del av kurset var Akka, og det hadde en ganske heftig innleveringsoppgave. Jeg slet fryktelig med den. Selve actor-orkestreringen var enkel (deklarativt), men alle feilene mine skjedde ifm muterbar state inne i actor'ene, og var vanskelig å følge i systemet. Så ja takk til FK/IS

leifericf 2026-06-11T07:34:39.426709Z

Det kurset startet jeg på året det kom ut på Coursera, men måtte gi meg halvveis fordi jeg ikke var smart nok 😅

leifericf 2026-06-11T07:35:36.732849Z

Men Erlang falt rett på plass i hodet mitt.

leifericf 2026-06-11T07:35:56.680229Z

Der er Actor modellen med «happy path» pattern matching inne i hver enkelt prosess (actor) mye bedre implementert synes jeg. På en forståelig måte.

gunnar 2026-06-11T08:48:47.536569Z

Interessant! Har alltid hatt lyst til å prøve Erlang, men har aldri funnet en anledning

leifericf 2026-06-11T08:53:12.161299Z

Jeg vil sterkt anbefale https://pragprog.com/titles/jaerlang2/programming-erlang-2nd-edition/! Den er fantastisk. Selv om man ikke vil bruke Erlang, kan man lære mye kult om parallelisert og distribuert computing på en måte som ingen andre økosystemer tilbyr. Erlang gjør det like enkelt å distribuere systemer på tvers av flere tusen maskiner, som Clojure gjør det enkelt å bruke alle kjerner på én CPU.

👌 1
gunnar 2026-06-11T08:53:45.374889Z

Takk, legger den i lista 🙂

👍 1
leifericf 2026-06-11T08:54:41.872299Z

Og Erlang er egentlig et veldig lite språk mtp. syntaks. Det er en Lisp-aktig filosofi som skjuler seg under den merkelige Prolog-aktige syntaksen, hehe

leifericf 2026-06-11T08:59:01.429659Z

En liten OBS: Det finnes egentlig ingen god grunn til å bruke Erlang nå som Elixir eksisterer. Elixir kompilerer til samme BEAM byte code, og en kan bruke Erlang libs der. Elixir er på en måte det samme for Erlang/BEAM, som Clojure er for Java/JVM. Elixir syntaksen ligner ganske mye på Ruby og er enklere for de fleste å forstå umiddelbart, men har også mye mer syntaks enn Erlang. Jeg synes det var ganske nyttig å lære Erlang før jeg lærte Elixir, fordi da er fokuset mer på grunnleggende konsepter i OTP og BEAM (som Elixir også bruker).

👍 1
2026-06-11T09:19:23.587479Z

kjenner jeg blir sliten bare av og tenke på at folk bruker OO og ports and adapters og heksagonal arkitektur og alt sånt. Klarer helt fint og kode i Kotlin og Typescript, men klarer ikke å kode objektorientert

gunnar 2026-06-11T10:20:09.200689Z

Bruker du FK/IS i Kotlin, @augustl?

2026-06-11T11:18:37.595029Z

oh yes! Over en lav sko

2026-06-11T11:21:20.655379Z

har en AI-agent som reviewer kode for FC/IS:

## Mental Model

Snowbee's integration "functional core" is pragmatic, not pure.

The core may:
- Take raw IDs/options plus `Session` or `SBDataSourceCtx`.
- Query the database directly with normal `entities`, `queries`, and service helpers.
- Build fully mapped payloads/data classes ready for the external system.
- Return a typed decision such as `Skip`, `Upsert`, `Delete`, `Sync`, `InventoryOnly`, `ProductSet`, or a posting/write plan.

The core must not:
- Call third-party APIs.
- Send queue messages.
- Invoke webhooks.
- Treat integration job status as business truth.
- Add DB wrapper/repository layers just for testability.

The imperative shell:
- Listens to events/webhooks/Titanic/outbox/jobs/routes.
- Calls the core.
- Switches on the returned decision/plan.
- Calls the external integration.
- Persists operational bookkeeping/results as needed.

## Rules

- Keep Snowbee business logic in planner/action/decision functions.
- This pattern is for external integrations, not a general mandate to wrap internal Snowbee domain commands or DB-only workflows.
- Let the core query DB directly; do not introduce intermediate mapping or integration layers unless they solve a real reuse problem.
- Prefer late binding: event payloads carry identifiers, and the core reads current domain state before deciding.
- Return sealed classes/data classes that make the shell's choices explicit.
- Put outbound payload mapping in the core when practical, so the shell does not contain business mapping.
- Keep the shell boring.
- Do not mock external services by default. Test the core instead.
- Automated tests for the imperative shell are usually not important unless the shell has meaningful local branching.

## Review Inputs

- For code, diffs, or files, cite findings as `file:line`.
- For implementation plans, cite findings as `plan:<section or short quote>`.
- If the user asks for plan review, review the proposed flow, boundaries, and test strategy rather than requiring existing files.

## Review Rules

- Flag business decisions embedded directly inside API-call loops or external-integration shells.
- Flag outbound payload mapping that is mixed with HTTP calls when it could be returned as a tested draft/plan from core code.
- Flag code that bases domain decisions on `integration_sync_job`, Titanic outbox state, retry status, or previous attempt status.
- Flag external-integration shell tests/mocks that exist mainly because integration business logic is trapped in the imperative shell; suggest moving logic into a core planner and testing that instead.
- Flag planner/core functions that call external systems, enqueue work, invoke webhooks, or write operational job bookkeeping.
- Flag speculative wrapper/repository layers introduced only to pretend the core is pure. Snowbee core may query the DB directly.
- Do not flag DB reads in the core. DB-backed planners are expected.
- Do not flag DB writes that are themselves returned as explicit write plans unless the function executes those writes while also making external calls.
- Prefer small typed sealed classes/data classes that make shell choices explicit.

gunnar 2026-06-10T20:35:10.517099Z

Ser at morgenene er tilpasset VM 😄