mount

tolitius 2016-02-02T01:22:34.000142Z

@wkf: let me know which solution worked for you, so I can keep a note of it, in case others need help with the start order, thx!

wkf 2016-02-02T01:28:24.000143Z

took a break for dinner, but I’ll let you know when I try it :simple_smile:

wkf 2016-02-02T14:17:15.000144Z

@tolitius: I got it working for now, just by putting the elasticmq namespace before the sqs namespace

wkf 2016-02-02T14:17:29.000145Z

I say “for now” because it feels brittle

wkf 2016-02-02T14:17:43.000146Z

fwiw, I really miss having a way to formally express dependencies

wkf 2016-02-02T14:18:39.000147Z

it would be nice to be able to pass dependencies like component, maybe something like (mount/using {#’app.sqs/sqs [#’app.elasticmq/elasticmq]})

wkf 2016-02-02T14:19:05.000148Z

so you could add constraints to the inferred dependency graph

wkf 2016-02-02T14:22:27.000149Z

also, despite my criticism, mount feels better than component when developing at the repl

wkf 2016-02-02T14:23:02.000150Z

also, I’d like to help, if you’re open to this kind of feature

tolitius 2016-02-02T14:23:12.000151Z

@wkf: I agree. the only case where it proves useful so far is in case of "one off" states that need a specific start order. I did not want to make it a requirement, but I agree, this is a very valid use case. it's actually not a bad idea.. to be able to specify some desired order before (mount/start) I actually welcome criticism, since it helps me think harder :simple_smile:

wkf 2016-02-02T14:24:23.000152Z

excellent… I have some other thoughts as well, if you’re interested

tolitius 2016-02-02T14:24:33.000153Z

sure, keep them coming :simple_smile:

tolitius 2016-02-02T14:25:18.000154Z

I am trying to be very careful not to complicate the API, hence I am still thinking on depends-on feature.. for about a month now

wkf 2016-02-02T14:25:52.000155Z

It seems like it would be quite useful to be able to wrap or transform states. for instance, I’ve got app.config/config, and in development, I’d like to add/change a few values

wkf 2016-02-02T14:25:58.000156Z

I could add a new state, and swap it out

wkf 2016-02-02T14:26:09.000157Z

but really, I just want to modify it slightly

tolitius 2016-02-02T14:26:12.000158Z

i.e. it might make sense to add :depends-on on the actual state..

wkf 2016-02-02T14:26:57.000159Z

would be nice to have something like (mount/hook #’app.config/config (fn [c] (assoc c :whatever 123)))

wkf 2016-02-02T14:27:43.000160Z

but, hey, let’s put a pin in that, and talk about :depends-on

tolitius 2016-02-02T14:28:53.000161Z

hooks: https://github.com/tolitius/mount/issues/16 agree

wkf 2016-02-02T14:29:10.000163Z

ha, sorry for not searching first :simple_smile:

tolitius 2016-02-02T14:29:34.000164Z

all good, it's only an idea at this point

wkf 2016-02-02T14:29:37.000165Z

I think a central place to specify dependencies can add clarity

wkf 2016-02-02T14:30:29.000166Z

it’s nice to be able to look at the graph, as data

wkf 2016-02-02T14:30:48.000167Z

I’ve used component a bunch, and I’ve never really liked component/using

wkf 2016-02-02T14:30:58.000168Z

I almost exclusively use component/system-using

wkf 2016-02-02T14:31:12.000169Z

and at a glance, I can see how the pieces of my system fit together

tolitius 2016-02-02T14:31:20.000170Z

I hear you.. thinking :)

tolitius 2016-02-02T14:32:23.000171Z

there is some visual: https://github.com/tolitius/mount/issues/12#issuecomment-167150505

wkf 2016-02-02T14:34:09.000173Z

ah, interesting

tolitius 2016-02-02T14:34:11.000174Z

what I didn't want to do is specify all the dependencies, since it will have to be kept in sync with a natural order.

wkf 2016-02-02T14:34:22.000175Z

yah

wkf 2016-02-02T14:34:28.000176Z

I think of it more like you’re enriching the natural dependencies

wkf 2016-02-02T14:34:45.000177Z

to handle indirect dependencies (ie, I depend on a rest api provided by another state, not its namespace)

tolitius 2016-02-02T14:34:57.000178Z

but I agree. explicit dependencies to help out structure the start order are very good to have

tolitius 2016-02-02T14:35:20.000179Z

right

tolitius 2016-02-02T14:37:11.000180Z

one difficulty that I see with enriching is validation.. but it might be easier than I think :simple_smile:

tolitius 2016-02-02T14:41:01.000181Z

i.e. in case a state a is "enriched" with a dependency on state b, how do we know that by starting b a bit earlier to satisfy this dependency we not hurting it (`b`) by now not yet starting states that b naturally depends on

wkf 2016-02-02T14:59:15.000182Z

but if we were to have access to the natural dependency graph, we could add new constraints

wkf 2016-02-02T14:59:25.000183Z

and derive a total order

wkf 2016-02-02T15:04:48.000184Z

I see the problem though

tolitius 2016-02-02T15:04:54.000185Z

access is there, "graph" is not so much :simple_smile:

wkf 2016-02-02T15:04:55.000186Z

we’re left with just the linear order

tolitius 2016-02-02T15:04:59.000187Z

yep

wkf 2016-02-02T15:04:59.000188Z

from clojure

tolitius 2016-02-02T15:06:27.000189Z

I "feel" there is a solution without breaking the idea of relying on the compiler, but I have not worked hard on validation yet..

tolitius 2016-02-02T15:07:02.000190Z

(the :depends-on idea)

tolitius 2016-02-02T15:07:16.000191Z

whether it is on a state level or central..

wkf 2016-02-02T15:08:46.000192Z

yah, where to put it is just an api question, and component does both

wkf 2016-02-02T15:08:50.000193Z

still have to solve the problem...

tolitius 2016-02-02T15:08:54.000194Z

if it is on a state level, but a final explicit order is still available via (graph/states-with-deps), I feel specifying :on-depends on the individual state still has value of only needing to (mount/start) without remembering (mount/something-else args) beforehand

tolitius 2016-02-02T15:09:17.000195Z

yep, agree

wkf 2016-02-02T15:09:25.000196Z

so, here’s something interesting...

wkf 2016-02-02T15:09:31.000197Z

in my original example

wkf 2016-02-02T15:09:43.000198Z

the sqs component has an indirect dependency on elasticmq

wkf 2016-02-02T15:09:55.000199Z

in other words, I couldn’t place it on the component directly

wkf 2016-02-02T15:10:01.000200Z

err, state

wkf 2016-02-02T15:10:05.000201Z

because it doesn’t always have that dependency

tolitius 2016-02-02T15:11:38.000202Z

("component" / "state".. same thing), yes, I am not dismissing the central meta for :depends-on, I see it being useful

wkf 2016-02-02T15:11:59.000203Z

gotcha, gotcha

wkf 2016-02-02T15:13:42.000204Z

just thinking out loud here… I’m not sure I would care if, as a first pass, the mount/using api required I (the user) specify all dependencies

tolitius 2016-02-02T15:13:42.000205Z

maybe some kind of :after / :before can work here.. then elasticmq can be:

(defstate elasticmq :start foo 
                    :stop bar
                    :before #{#'app/sqs})

wkf 2016-02-02T15:13:58.000207Z

that’s interesting

tolitius 2016-02-02T15:15:21.000209Z

usually (from my experience) introducing a public API is rarely a temp solution :simple_smile:

wkf 2016-02-02T15:15:29.000210Z

😉

wkf 2016-02-02T15:15:31.000212Z

haha

wkf 2016-02-02T15:16:06.000213Z

maybe an even looser constraint would work… if you use mount/using, and you specify dependencies for a state, you must specify all its dependencies

wkf 2016-02-02T15:16:17.000214Z

ie, once you take it out of the natural order, you need to take full responsibility

tolitius 2016-02-02T15:16:41.000215Z

huh.. that's not a bad idea

wkf 2016-02-02T15:16:41.000216Z

meh, I’m wrong, that still wouldn’t work

wkf 2016-02-02T15:17:01.000218Z

actually, yah, it would

wkf 2016-02-02T15:17:09.000219Z

just working it through in real time

wkf 2016-02-02T15:17:11.000220Z

sorry for the spam 😉

tolitius 2016-02-02T15:17:27.000221Z

I am not a fan if using since it feels too generic in this context

tolitius 2016-02-02T15:17:34.000222Z

(as a word)

wkf 2016-02-02T15:17:40.000223Z

oh, sure

wkf 2016-02-02T15:17:49.000224Z

mount/start-with-deps or something

wkf 2016-02-02T15:17:52.000225Z

might be more clear

tolitius 2016-02-02T15:17:59.000226Z

yea, the name will come naturally :simple_smile:

wkf 2016-02-02T15:18:30.000227Z

oh, that reminds me… any thoughts on separating the “configuration” from the “starting”?

wkf 2016-02-02T15:19:12.000228Z

seems like it might feel nice to express the ways in which you’re modifying load order/dependencies once

wkf 2016-02-02T15:19:17.000229Z

outside of the lifecycle

tolitius 2016-02-02T15:23:44.000230Z

you mean something like a conf driven by boot / lein / -D ?

wkf 2016-02-02T15:25:11.000231Z

nothing so glamorous, something like (mount/with-states {#’blah #’bloop}) (mount/with-deps {#’hello #’sir}) (mount/start)

wkf 2016-02-02T15:25:42.000232Z

“persistent” changes to the way mount/start and mount/stop work

wkf 2016-02-02T15:26:03.000233Z

seems useful, especially when I’m using more than one start-with-* function

wkf 2016-02-02T15:27:41.000234Z

(an alternative would be a start function that takes different kinds of modifications… state swaps, deps, hooks, etc)

tolitius 2016-02-02T15:32:31.000235Z

ah.. yea, that's definitely on the road map

tolitius 2016-02-02T15:35:39.000236Z

I might sacrifice the idea of (mount/start-with) taking swaps, and have it to just take a map. this is not exactly "persistent" (i.e. before a start is called), since I like it to stay atomic, but it should achieve the flexibility:

(mount/start-with {:swap {} 
                   :only #{}
                   :except #{}
                   :with-deps {}})

tolitius 2016-02-02T15:36:04.000238Z

something like that..

tolitius 2016-02-02T15:36:20.000239Z

is there any specific reason you want them persistent?

wkf 2016-02-02T15:37:08.000240Z

if there were separate functions for setting up deps, swaps, hook

wkf 2016-02-02T15:37:15.000241Z

I’d like to set them

wkf 2016-02-02T15:37:20.000242Z

before starting the states

wkf 2016-02-02T15:37:23.000243Z

but if I can do it all at once

wkf 2016-02-02T15:37:29.000244Z

that’s probably preferable

tolitius 2016-02-02T15:39:29.000245Z

another way I was thinking some time ago is:

(-> (with {#'app.nyse/db test-db
           #'app.nyse/publisher test-publisher}) 
    (without #{#'app/nrepl feed-listener})
    (with-args args)
    start)

tolitius 2016-02-02T15:41:08.000249Z

but start-with taking a map looks less confusing and "easier" to visualize / share / understand

wkf 2016-02-02T15:41:20.000250Z

yah

wkf 2016-02-02T15:41:27.000251Z

could easily have both, since those functions above could just create the map

wkf 2016-02-02T15:41:51.000252Z

though, data > dsl

tolitius 2016-02-02T15:42:02.000253Z

well, I'll definitely have all those functions to process the map internally anyway :simple_smile:

tolitius 2016-02-02T15:43:32.000254Z

yea, something like a map can find usages / be provided from many places: * REPL * boot task / lein profile * config * dev.clj * etc..

tolitius 2016-02-02T15:44:42.000255Z

it's a bit shaky to break (mount/start-with) though since people's tests depend on it.. but I don't think / hope it is not too late

wkf 2016-02-02T15:45:26.000256Z

yah, luckily it’s still 0.x

wkf 2016-02-02T15:45:38.000257Z

not too late to make changes, especially since it’ll lead to a better tool

tolitius 2016-02-02T15:47:53.000258Z

you're right, the version would help here

tolitius 2016-02-02T15:48:38.000259Z

hopefully this is something people read: https://github.com/tolitius/mount/blob/master/CHANGELOG.md :simple_smile:

arnout 2016-02-02T16:31:38.000263Z

Hi @wkf and @tolitius. I saw you mention me (and mount-lite) on GitHub.

arnout 2016-02-02T16:31:54.000264Z

Mount-lite actually has a 'parallel' branch now: https://github.com/aroemers/mount-lite/tree/parallel

arnout 2016-02-02T16:32:43.000266Z

In it are both a automatically deduced state dependency graph, and a way to influence that graph.

arnout 2016-02-02T16:33:10.000267Z

Maybe this can be some inspiration to Mount and above discussion?

wkf 2016-02-02T16:33:51.000268Z

oh, awesome

wkf 2016-02-02T16:34:00.000269Z

seems super useful

arnout 2016-02-02T16:37:04.000270Z

(just like I hope to inspire a composable API for Mount, which you also discussed I see 😄)

wkf 2016-02-02T16:42:53.000272Z

:simple_smile:

tolitius 2016-02-02T16:48:30.000273Z

@arnout: the compatibility is definitely a great idea :) I saw the parallel work, it may not work for ClojureScript though

wkf 2016-02-02T16:48:56.000274Z

@tolitius: I wrote a parallel dependency loader in javascript

wkf 2016-02-02T16:48:58.000275Z

https://github.com/mojotech/entwine

wkf 2016-02-02T16:49:19.000277Z

would have to think a bit how to do it clojurescript

wkf 2016-02-02T16:51:15.000278Z

“parallel”

tolitius 2016-02-02T16:51:37.000279Z

the idea of building a graph of off vars don't really project well to cljs since, unless bootstrap is used, have no support for Clojure ns API in :advanced mode

arnout 2016-02-02T16:52:23.000280Z

True

tolitius 2016-02-02T16:53:00.000281Z

simply following @wkf idea of providing the full graph in :with-deps might solve it in use cases that need it

arnout 2016-02-02T16:53:50.000282Z

Heh, removing suspend and resume? Cool, I can then remove "I don't need suspending" from mount-lite's README 😉

arnout 2016-02-02T16:54:26.000283Z

Hmm, I think Mount is great, because of the implicit dependency "graph" it creates (whether a proper graph or sequential does not matter)

arnout 2016-02-02T16:54:59.000284Z

"It just works" - except for when it doesn't, in @wkf's use case

wkf 2016-02-02T16:55:06.000285Z

haha

wkf 2016-02-02T16:55:12.000286Z

it’s interesting that you say that

tolitius 2016-02-02T16:55:22.000287Z

yea, I stumble upon these (suspend/resume) often enough to question their need. You saw it first :)

wkf 2016-02-02T16:55:36.000288Z

to me, the real value proposition comes form the way mount affects working at the repl

wkf 2016-02-02T16:55:39.000289Z

vs component

wkf 2016-02-02T16:55:51.000290Z

I never found it particularly tedious to express the dependency graph with data

tolitius 2016-02-02T16:56:06.000291Z

yes, development was the essential motive

wkf 2016-02-02T16:56:08.000292Z

not being able to easily “play” at the repl was the real downer

arnout 2016-02-02T16:57:36.000293Z

But do you want to globally store such a data structure, like set-dependencies? Or do you want to specify it each time you do one of the many REPL actions (`start-with`, start-except, etc.)?

tolitius 2016-02-02T16:57:40.000294Z

@arnout: agree with the value of implicit graph, but am option to override it does seem like a valid feature

tolitius 2016-02-02T16:58:47.000295Z

I would tend to do something like: https://github.com/tolitius/mount/issues/48

tolitius 2016-02-02T16:59:04.000299Z

(the example there)

tolitius 2016-02-02T16:59:31.000300Z

typing from a phone.. :)

arnout 2016-02-02T17:00:09.000301Z

Sure, that's a very valid way to go

tolitius 2016-02-02T17:00:26.000302Z

yea, I think your real graph in lite is quite powerful

arnout 2016-02-02T17:05:54.000303Z

Boasting myself here, but that graph also makes for quite a nice :up-to start/stop option. It only starts (or stops) the necessary states to start/stop the given "up-to" state.

arnout 2016-02-02T17:07:05.000304Z

And that :up-to option is actually also used for the "cascading stop" on a redefinition; meaning never a running state that suddenly lost its dependency. Which can still be overridden of course by the :only option.

arnout 2016-02-02T17:07:24.000305Z

./boasting-mode off

tolitius 2016-02-02T17:07:50.000306Z

:) can you share a use case for :up-to?

arnout 2016-02-02T17:09:00.000307Z

Whenever you want to test a certain state for example. Just (start (up-to #'state/under-test)) and your good to go, as all its dependencies will have started as well, without needing any knowledge of what states that would be.

arnout 2016-02-02T17:09:38.000308Z

Or if you only want to stop part of your system, but some base states can keep running.

tolitius 2016-02-02T17:11:14.000309Z

do you see it used instead of start-without / stop-except ?

arnout 2016-02-02T17:11:15.000310Z

And, with the automatic "cascading stop", you can safely redefine a state. It will only stop the necessary part of the app, and after a (start) everything is back up.

arnout 2016-02-02T17:11:51.000312Z

Yes, because those two require knowledge about the implicit state dependency sequence/graph.

arnout 2016-02-02T17:12:31.000313Z

Those functions are enough of course, but up-to is eh.. more convenient in that case?

tolitius 2016-02-02T17:15:00.000315Z

I see. I tend to minimize the number of states.. so I don't have that many in a single app usually. Since I tend to create states for external resources, and usually there are not a lot of those. But I guess when apps have many, yea, it could be more convenient

wkf 2016-02-02T18:15:52.000316Z

thinking more about :with-deps, and the proposed changes to starts-with, and I think it’s more complicated than it needs to be

wkf 2016-02-02T18:28:56.000317Z

I’m thinking of a data structure like this:

(mount/start-with
  {:states
   [#'app.config/config
    #'app.server/server]
   :dependencies
   {#'app.server/server [#'app.config/config]}})

wkf 2016-02-02T18:29:28.000318Z

which is expanded to something like this...

wkf 2016-02-02T18:29:57.000319Z

{:states
  {#’app.config/config #’app.config/config
   #’app.server/server #’app.server/server}
…}

wkf 2016-02-02T18:30:12.000320Z

(I left out the dependencies, but they are still there)

wkf 2016-02-02T18:30:27.000322Z

“swaps” could be handled in the :states map

wkf 2016-02-02T18:30:54.000323Z

but basically… mount/start-with takes a whole “system”

wkf 2016-02-02T18:31:10.000324Z

and under the hood

wkf 2016-02-02T18:31:23.000325Z

perhaps we could generate that “system” data structure

wkf 2016-02-02T18:31:33.000326Z

seems like we could describe :only, :except, :with-deps

wkf 2016-02-02T18:31:38.000327Z

as modifications to that data structure

wkf 2016-02-02T18:32:26.000328Z

we could also come up with some well defined semantics for how the “natural system” could be merged with the provided system

wkf 2016-02-02T18:32:30.000329Z

in other words...

wkf 2016-02-02T18:32:57.000330Z

(mount/start-with-merge
  {:states 
    {#’app.config/config #’app.repl/config}})

wkf 2016-02-02T18:33:13.000331Z

would merge the states from the “natural system” with the above data

wkf 2016-02-02T18:33:22.000332Z

and have the effect of a swap

wkf 2016-02-02T18:34:20.000333Z

under the hood, there could be some refactoring to implement the start* functions in terms of this system data structure

wkf 2016-02-02T18:34:46.000334Z

with a 0-arity mount/start call using the “natural system”

wkf 2016-02-02T18:35:03.000335Z

mostly just thinking out loud

tolitius 2016-02-02T19:09:09.000336Z

hm.. if I understood you correctly start-with-merge would mutate the running system?

tolitius 2016-02-02T19:10:35.000337Z

what's the benefit of hiding intentions (i.e. :only, :except, ...) behind a vector / map?

wkf 2016-02-02T19:23:01.000338Z

sorry, there was no mutation in that case, let me try to explain more clearly

wkf 2016-02-02T19:23:35.000339Z

I’m thinking of a data structure that would contain an exhaustive list of states and dependencies

wkf 2016-02-02T19:23:49.000340Z

and then using that data structure to start/stop the states

wkf 2016-02-02T19:24:12.000341Z

this is mostly a question of implementation

wkf 2016-02-02T19:24:50.000342Z

right now, there’s only an implicit set of states and dependencies

wkf 2016-02-02T19:27:06.000343Z

let’s call that the system

wkf 2016-02-02T19:28:05.000344Z

a definition of the states in the app, and their dependencies

wkf 2016-02-02T19:29:11.000346Z

if we had that data structure, it would be pretty straightforward to implement the stop/start behavior as it exists now

wkf 2016-02-02T19:29:43.000347Z

in fact, I think start and stop could be functions of a system-spec

wkf 2016-02-02T19:30:04.000349Z

and then :only, :except, :with-deps, etc

wkf 2016-02-02T19:30:10.000350Z

would be transformations of the spec

wkf 2016-02-02T19:30:19.000351Z

that would yield a valid system spec

wkf 2016-02-02T19:30:33.000352Z

but with fewer states, or different deps, etc

tolitius 2016-02-02T19:47:47.000353Z

looks like you are talking about a https://github.com/tolitius/yurt :simple_smile:

tolitius 2016-02-02T19:48:06.000355Z

i.e.

dev=> (yurt/blueprint)
{:components
 {"neo.conf/config" {:status :not-started},
  "neo.db/db" {:status :not-started},
  "neo.www/neo-app" {:status :not-started},
  "neo.app/nrepl" {:status :not-started}},
 :blueprint
 {"neo.conf/config" {:order 1},
  "neo.db/db" {:order 2},
  "neo.www/neo-app" {:order 3},
  "neo.app/nrepl" {:order 4}}}

tolitius 2016-02-02T19:48:54.000356Z

a detached system which internally (by it's type), knows how to be started / started-with / stopped

wkf 2016-02-02T19:57:45.000357Z

I’ll have to take a look

wkf 2016-02-02T19:58:41.000359Z

ha, yah

wkf 2016-02-02T19:58:52.000361Z

looks like it’s pretty close to what I was talking about

tolitius 2016-02-02T20:01:43.000362Z

right.. it still does not do lifecycle fns composition, since.. well, it is just 4 days old

tolitius 2016-02-02T20:02:15.000363Z

it was really written to mostly show that mount design does not limit developers by a single(ton) system, and many more than one system can be created, bound locally and used in the same runtime

tolitius 2016-02-02T20:02:37.000364Z

but it can very well be used beyond that, of course

tolitius 2016-02-02T20:05:43.000365Z

as to mount, I would like to keep it system transparent, and mostly worry about the meat of the app (that has nothing to do with mount). I see "composable lifecycle" as something that is mostly helpful in testing. I do however agree that "indirect dependencies" should be a core feature that is a lot more important to have

arnout 2016-02-02T21:07:16.000368Z

@wkf: In mount-lite, there are these start* and stop* functions you talk about. They take a single spec: {#'statevar {:start ... :stop ...}, ...}. This spec is being created by supplying one or more maps containing :only, :except and :substitute (and more mount-lite specific) keys to start/`stop`. Whenever you supply this to start (or stop) it is munged into the simple spec that start* expects, by starting with a complete spec, and processing the :only, :except etc options on it. This design has suited me well, by allowing me to add more options quite easily, without altering the current API. Is that what you meant?

wkf 2016-02-02T21:16:57.000370Z

yah, something similar to that

wkf 2016-02-02T21:19:24.000371Z

@tolitius: I’m not as concerned about supporting multiple systems, I’m just thinking that the “system” abstraction internally might be a decent way to handle the indirect dependencies

wkf 2016-02-02T21:19:53.000372Z

I cloned down the repo, I’ll take a stab at it with code, you can see what it looks like