Fork me on GitHub
#mount
<
2016-09-22
>
kurt-yagram07:09:50

just wondering: defstate is something like a global 'constant'(?) atom? If so, well, I always have a rather weird feeling with globals. So the use case for mount, is it about managing 'system state' rather than the state of a namespace? I'm trying to find out the main difference between mount and component. I did check https://github.com/tolitius/mount/blob/master/doc/differences-from-component.md#differences-from-component already. The only thing that actually bothers me about mount is that state is a global 'constant'(?).

dm313:09:59

yes, it's a global constant

dm313:09:28

the same way a System of components is a global constant if you store it in a Var

dm313:09:55

(in whatever sense we use the word "constant" here)

tolitius14:09:10

@dhruv1: is it still a problem, or you're just wondering why it happens?

dhruv114:09:35

it’s no longer a problem.

dhruv114:09:36

and i’ve figured out why it happens. mount has an atom internally which keeps track of the state and that’s where i was running into the problem

dhruv114:09:10

i was wondering if there was a way to avoid this situation. it took me a bit of time to figure out why I kept getting the error.

tolitius14:09:13

@kurt-yagram: I would not call it a constant necessarily since the state does change: does not remain to be "constant" between start and stop. the key here is that it is managed, i.e. it is not just a global singleton, as some people claim: but a managed state. > The only thing that actually bothers me about mount is that state is a global what exactly does bother you about it? the idea is that you'd make a state for an external resource, for example a database. In case you need a state (connection) to another database / different schema, you have plenty of options: https://github.com/tolitius/mount/blob/master/README.md#swapping-alternate-implementations or you can just create a different state. it reflects the reality if you think about it: database is your resource, and it is "single", you need connections to two different databases? it would be two different states (could be the exact same function to create these states, given the different configs, but two different instances with connections to two different databases).

kurt-yagram14:09:56

@tolitius : yeah, it bothers me because of bad experiences with it, probably. It always bothered me and I don't really know why. Maybe I should just get over it. now, I might have to use mount a little different, but what I do know is: I read my config from, well, that doesn't matter, but I have like 1 configuration map, containing the config for different parts of may application. So I do:

(mount/start-with-args (::datomic config)
                         #'my.ns.db/conn)
  (mount/start-with-args (::security config)
                         #'my.ns.security/config)
  ...
In my.ns.db:
(defstate conn
  :start (new-connection (mount/args))
  :stop ...)
Now, I would prefer to use just (mount/start), or something like in the docs:
(-> (only #{#'foo/a
            #'foo/b
            #'foo/c
            #'bar/d
            #'baz/e})
    (with-args {:a 42})
    (except [#'foo/c
             #'bar/d])
    (swap-states {#'foo/a #'test/a})
    (swap {#'baz/e {:datomic {:uri "datomic:"}}})
    mount/start)
However, swapping my.ns.db/conn is a connection and can't be started/swapped with the map. So I would actually have to call new-connection where I call mount. I just can't figure out what's the best thing to do here: calling a bunch of functions to configure the state (like new-connection) in the main of the application, or passing the general config to all parts as mount/args? (In the latter, I pass actually way to much configuration). It's just: if I do the former, I get a cyclic dependency (unless I put methods as new-connection not inside the my.ns.db namespace?)

tolitius14:09:16

@dhruv1: usually you would do something like (reset) https://github.com/tolitius/mount/blob/master/README.md#the-importance-of-being-reloadable but I agree, it might make sense to potentially have a some kind of (mount/reset) that could take params: i.e. (mount/reset :ignore-errors true). which, if well documented, could help in situations like this one. could you create an issue, so we don't forget?

dhruv114:09:33

@tolitius sounds good. thanks 🙂

dhruv114:09:43

created. thanks @tolitius

tolitius14:09:02

@kurt-yagram: trying to piece the problem together... one sec

tolitius14:09:28

@kurt-yagram: not understanding this piece:

swapping "my.ns.db/conn" is a connection and can't be started/swapped with the map

tolitius14:09:03

do you need to create a different connection depending on the arguments? i.e.

tolitius14:09:06

(defstate conn
  :start (new-connection (config :store))
  :stop ...)

tolitius14:09:42

where (:config store) may return different (say database schemas)?

tolitius14:09:29

i.e. -Dconf=prod-config.edn vs. -Dconf=dev-config.edn?

kurt-yagram15:09:45

yeah, although not with -D parameters as such. The main struggle I have is: the way I start the application now is a bunch of mount/start-with-args. Now, I'm starting to realize that there's probably no way around this. I can use mount/start-with, and put create-... and new-... methods somewhere in the 'main' namespace. I don't really have a default state, so I always need to add the state during start. Or, taking the sms example ( https://github.com/tolitius/mount/blob/master/README.md#swapping-states-with-values ): create-sms-sender is inside the app.sms ns, so I can't call it from the ns where it is mounted. I can't do mount/start-with {#'app.sms/send-sms (app.sms/create-sms-sender (:sms config))}.

tolitius15:09:32

> the way I start the application now is a bunch of mount/start-with-args why not via a single config? > I can't do mount/start-with {#'app.sms/send-sms (app.sms/create-sms-sender (:sms config))} what I don't understand is why you need to do it 🙂 i.e. why not just https://github.com/tolitius/stater/blob/master/smsio/src/app/sms.clj#L12-L13 where (:sms config) would be different depending on the config file / profile / etc.. ?

kurt-yagram15:09:13

Yeah, well, I actually just didn't want pass all configuration to each part, but only the component-specific configuration. Anyway, maybe I shouldn't make things so complicated 😛.

kurt-yagram15:09:55

using (:whatever config) should do fine...

tolitius15:09:06

@kurt-yagram: yea, I usually find as the app grows in size and gets more components, a config is a very convenient way to provide runtime dependent values. also, since config could be edn it is not that difficult to destructure, or you can just use cursors: https://github.com/tolitius/cprop#cursors 🙂

kurt-yagram17:09:07

cprops... I like