hi folks, I am trying out Integrant library for state management. It's quite intuitive when it comes to managing (starting/halting) servers but I am confused regarding a certain use case. I want to use integrant to instantiate and destroy an object. As usual I defined defmethods init-key and halt-key! . The problem is that I want a reference to the initialised object from init-key . Is there an idiomatic way to do this? Should I just have it available in an atom during init-key ?
(defmethod ig/init-key :my-space/my-key [_ opts]
(let [account-id (:account-id opts)
license-key (:license-key opts)]
(MyObject. account-id license-key)))
;;How do I use the instantiated my object?
from where you want access myObject?
(defmethod ig/init-key :my-space/my-key [_ opts]
(let [account-id (:account-id opts)
license-key (:license-key opts)]
(MyObject. account-id license-key)))
;;Function in same namespace
(defn fetch-name
[id]
;;use MyObject Here)you can keep the initiated system available in some namespace. (def system (-> config (ig/prep) (if/init))) your object will be available under some key
wouldn't that lead to a cyclic dependency? • system namespace requires myobject name space (for it to instantiate the dependencies) • My object namespace requires system name space to get MyObject
I'm not follow, sorry
Typically systems created by Integrant will have some equivalent to a main loop. Perhaps this is a server of some kind, or perhaps a scheduler. Presumably fetch-name in your example will be called directly or indirectly from this component.
For example, if you had a server:
{:my-space/server {:my-object #ig/ref :my-space/my-key}
:my-space/my-key {:account-id ..., :license-key ...}}Sometimes a server will have subhandlers, so you could also write it:
{:my-space/server {:handlers [#ig/ref :my-space/my-handler]}
:my-space/my-handler {:my-object #ig/ref :my-space/my-key}
:my-space/my-key {:account ..., :license-key ...}}However, the point is to avoid global references, and instead make every dependency explicit, passed either via Integrant as a reference, or as a function argument.
(defn fetch-name [my-object id]
...)
Does that make sense?
@weavejester yes makes sense. If I understood this right, I have to pass all the dependencies top down. So I will have to define my edn in such a way that server depends on MyObject. This way I can pass MyObject from server all the way down to routes and handlers (and eventually to fetch-name )
Is that right?
Yep, exactly. There should be a clear, traceable graph of dependencies.
There are state management systems that use global variables, such as Mount, but Integrant is opinionated about making dependencies explicit.
yes understood. I can see where you are coming from. This definitely requires a shift in perspective. I was just watching your talk https://skillsmatter.com/skillscasts/9820-enter-integrant-a-micro-framework-for-data-driven-architecture-with-james-reeves and it gets clearer. Thanks a lot for making this library!
You're welcome 🙂