luminus

mokr 2020-08-27T07:46:13.014400Z

Hi! What’s the trick to using the config created as <myproject>.config/env by the Luminus template? If I use it as a map directly it might not be ready yet and cause nil values. If I defer it I see a message that it is not started and that mount/start should have been called for that to happen. Since the Luminus code doesn’t do the latter I guess there’s something I’m missing. Help for reliable use would be appreciated.

Casey 2020-08-27T08:58:25.015Z

The first thing you should do after getting your repl is call (start)

Casey 2020-08-27T08:58:32.015300Z

then the config will be setup

mokr 2020-08-27T09:56:19.023100Z

@ramblurr I don’t see how that will help. What about code that is already evaluated before that, eg. a (def foo (:bar env)) in another ns (effectively assigning nil to foo as env is not ready). In addition I start it with lein run and would like it to get into a fully working state without any repl interaction. Sorry if I’m missing something obvious here, but I don’t see how having required repl steps is attractive. Sound like something that is easy to forget from time to time. Feels like I’m missing the idea behind this design.

Casey 2020-08-27T10:11:28.023400Z

The luminus documentation on this pattern is described here https://luminusweb.com/docs/components.html

Casey 2020-08-27T10:12:49.024800Z

The intention is that any use of env will occur after the config component is mounted (which is done as part of (start)) . If you are def ing something that needs a value from the config, then whatever you're defing should probably become a component itself, and managed via mount's start and stop.

Casey 2020-08-27T10:13:16.025100Z

You can use defstate for this, see the docs I linked.

mokr 2020-08-27T10:18:41.029400Z

Thanks, I will have to sit down and read that doc more closely. My previous skimming through it did not give me the answers I was looking for. I’ve previously attempted to only access env from inside defstate but that just propagated the problem in the sense that whatever uses what I define will also have to be inside a defstate… That issue told me that it was something I had not really grasped. My underlying “problem” is that that Luminus template has been serving me very well, so I haven’t really spent the required time on getting to know all the libraries well enough.

Casey 2020-08-27T10:20:11.029800Z

FWIW I stumbled through the same issues when I was getting started with it.

Casey 2020-08-27T10:22:04.031600Z

The simplest advice I can give on this topic, is to realize that when you are (def foo (:bar env)) you are declaring state that depends on something external (as opposed to a constant like (def foo 3.14)). Anytime you have state that depends on something external, declare it with defstate.

Casey 2020-08-27T10:26:25.035800Z

In your example, foo is just a config key from env. Presumably this foo will be used in some other piece of state, like a database connection. You do not need to (defstate foo :start (:bar env)) but rather defstate the thing that will consume :bar, (defstate a-thing :start (fn [] (let [foo (:bar env)] (do-thing-with foo)))) then whatever (do-thing-with) returns can be accessed via a-thing.. or in other words that defstate is similar to (def a-thing (do-thing-with (:bar env)))

Casey 2020-08-27T10:30:42.037500Z

for more background: luminus uses the mount library to manage stateful components (that's what (start) is calling). mount is an adaption of stuart sierra's https://github.com/stuartsierra/component . I recommend watching stuart's talk that explains (in 45 minutes of detail) what this is all about

1👍
Casey 2020-08-27T10:31:07.038100Z

https://www.youtube.com/watch?v=13cmHf_kt-Q

mokr 2020-08-27T10:40:20.039900Z

Thanks again, @ramblurr, very helpful. I kind of know what all of this is, but it hasn’t clicked yet. I just have to sit down and read, watch and code until it does. 🙂

1🙌