Morn
Morn!
Morn!
God morgen!
Morn!
Morn :)
mrn
@andersmurphy that’s mine! mrn.
Morn, morn!
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}Jeg går rundt og tenker at concat er treg, men har ikke gjort noen benchmarks.
concat er lazy, det er vel det viktigste å vite.
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.Ja, den hadde vært fin å ha. Tyr ofte til (into [] ...) for å være sikker på å få en vektor i stedet for noe lazy.
trur eg tidvis har brukt reduce into [] 🤷
@slipset but I made it popular 🤣
Fair!
Trodde du hadde byttet @slipset?
"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-shell • https://www.destroyallsoftware.com/talks/boundaries
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
Takk for info, @magnars! Jeg ble bare litt nysgjerrig på historikken og hvor det kom fra.
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)
høres ut som OO-varianten av det samme, kanskje?
ja, det stemmer nok bra
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.
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.
Det er i hvert fall noe helt annet enn funksjonell kjerne/imperativt skall. Det er en arkitektur for hver enkelt prosess.
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/
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.
Haha, det har sikkert rett i 😄
OO-greier, mutable state og concurrency.
Hvis man tar bort alle patterns som har med de tingene å gjøre så er det lite igjen.
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
Det kurset startet jeg på året det kom ut på Coursera, men måtte gi meg halvveis fordi jeg ikke var smart nok 😅
Men Erlang falt rett på plass i hodet mitt.
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.
Interessant! Har alltid hatt lyst til å prøve Erlang, men har aldri funnet en anledning
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.
Takk, legger den i lista 🙂
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
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).
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
Bruker du FK/IS i Kotlin, @augustl?
oh yes! Over en lav sko
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.Ser at morgenene er tilpasset VM 😄