component

lukasz 2025-09-02T14:43:15.400079Z

I've been thinking about how to make Component a bit more declarative while retaining its good features (simplicity, reliance on protocols & records means better integration with JVM libraries) and I came up with Oreo: • integrates with Aero's facilities to unify application configuration, system definition and component config • makes everything declarative, and thanks to Aero's features allows for interesting system building tricks • very not-even-alpha, I'm using it in a couple of smaller backend services and I still have a few things to finalize (naming, 'API' and REPL workflow) Curious what y'all think :-) https://github.com/lukaszkorecki/oreo

technosophist 2025-09-09T19:09:06.235359Z

This is interesting. I've started thinking of my systems as having three phases: create, configure, start, and that's what I've been doing with https://github.com/thoughtfull-clojure/amalgam?tab=readme-ov-file#configure-and-run-systems

technosophist 2025-09-09T19:09:42.828889Z

not exactly the same, but I think in the same vein of thinking about a config that mirrors the structure of your system

technosophist 2025-09-09T19:09:53.549749Z

(which is kind of like integrant)

lukasz 2025-09-09T20:21:15.252889Z

That’s the thing - the config in Oreo is the system, it doesn’t mirror anything. I really need to compare Integrant again it’s been a while since last time I tried it

technosophist 2025-09-09T20:21:46.404109Z

yeah that is more like integrant

seancorfield 2025-09-02T14:51:08.334049Z

This feels like Integrant (which I don't like) so I'll have to sit with this for a bit to decide whether I'd use it or not 🙂 That said, in several of our apps, we build the system map conditionally... although I guess we could still use Oreo for the unchanging core of the system, and then just conditionally add in our dynamic pieces, between oreo/create-system and component/start?

lukasz 2025-09-02T14:53:24.096129Z

heh, I felt the same when I started working on 3 years ago - I think I added a note about Integrant in the readme

lukasz 2025-09-02T14:54:01.767419Z

as for conditionally building the system, this works: https://github.com/lukaszkorecki/oreo/blob/main/test/oreo/profile-test.edn

👀 1
seancorfield 2025-09-02T14:54:21.694979Z

It's seems a bit odd/confusing on first glance that there are three different ways to specify :create fns? #oc/ref! symbol, #oc/ref :keyword, and plain :keyword

lukasz 2025-09-02T14:55:22.573269Z

that must be a bug in the readme - only #oc/ref and #oc/ref! work now

lukasz 2025-09-02T14:56:07.493399Z

originally it started just with qualified keywords and symbols, but it was too magical and I still needed to support ref/ref! to configure components

seancorfield 2025-09-02T14:58:19.669849Z

Don't be put off by my initial reactions. I like and use Aero so that's a big plus. I like and use Component so that's a big plus. I may experiment with it in a branch at work if I get time this week...

lukasz 2025-09-02T14:58:47.360669Z

oh, I'm not put off at all - any feedback is appreciated!

lukasz 2025-09-02T14:59:45.282309Z

your point about having too many options is definitely valid - I had a hunch that supporting qualified symbols is confusing already, so dropping them and requiring keywords only feels right

seancorfield 2025-09-02T15:07:49.048899Z

Would that completely remove the need for #oc/ref! -- I was confused about the :store comment about it deref'ing an atom there...?

lukasz 2025-09-02T15:14:47.887969Z

Oreo is basically requiring-resolve under the hood, so I run into this when testing the library with an older codebase: • a http server component required the Ring handler to be a function, it wouldn't accept a var • the system also had a couple of stateless components - a function (where passing a var works) but also an atom - so to use it as such, I had to unpack the value from the var obtained via requiring-resolve using deref:

user=> (requiring-resolve 'clojure.walk/postwalk)
#'clojure.walk/postwalk
user=> (class *1)
clojure.lang.Var
user=> @(requiring-resolve 'clojure.walk/postwalk)
#object[clojure.walk$postwalk 0x3c1e23ff "clojure.walk$postwalk@3c1e23ff"]
user=> (class *1)
clojure.walk$postwalk
user=>
technically both are fixable in some other way, but I wanted to provide features that make it easy to migrate to Oreo, and ideally adopting it only requires changing how the system is built, and nothing else but yes, there's an explanation in the readme for when to use ref vs ref! - but maybe there should be just ref which does what ref! does

seancorfield 2025-09-02T15:18:10.612889Z

Perhaps #oc/ref and #oc/deref then, to be clearer about the behavior?

lukasz 2025-09-02T15:19:24.737529Z

nice, I like that