Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

mount.extensions.namespace-deps does not discover state dependencies via empty namespaces #18

Closed
dryewo opened this issue Jan 4, 2019 · 5 comments

Comments

@dryewo
Copy link
Contributor

dryewo commented Jan 4, 2019

Hello Arnout!

We are using mount-lite extensively in several projects. It works quite nicely and makes testing subsystems really easy thanks to "start-up-to" function variants.
However, there is a small issue that makes the experience less than perfect.

Consider this example: namespaces A and C contain states a and c, but are required via namespace B, which contains no states:

A(a) -> B() -> C(c)

Expected behavior when starting the app up to state a is that it starts both a and c, because the inferred state graph is:

a -> c

In practice it does not find the dependency and starts only a.
A workaround is to put dummy states in all empty namespaces. It's not ideal, because people who are new to the codebase don't understand it and usually spend some time debugging some weird issues.

I found that the problem lies in mount.extensions.namespace-deps/ns-graph->state-graph function, which only considers namespaces that have states.

I'm eager to help fixing it, I already tried to do it locally, but before opening a PR I wanted to discuss solution approach with you. I have the following thoughts:

First, the simplest fix involves pre-processing namespace dependency graph by excluding empty namespaces from it and replacing them with additional dependencies, for example:

A(a) -> B() -> C(c)
we remove B and add an arrow from A to C
A(a) -> C(c)

However, for a general DAG it's not an easy procedure. It can be easily solved by means of loom, a graph processing library.

After the preprocessing is done, the existing algorithm works just fine.

Right now mount-lite already depends on clojure.tools.namespace (requiring it only when you use mount.extensions.namespace-deps). I think we can bring another optional library that makes our life much easier.

Second, if we bring loom, we can also simplify the existing ns-graph->state-graph algorithm by relying on loom. Current implementation is quite hard to understand because it does not operate graph concepts like edges and vertexes but rather low-level representation details.

Third, I could also imagine that mount-lite extensions can be distributed as separate libraries:

functionalbytes/mount-lite
functionalbytes/mount-lite.ext.explicit-deps
functionalbytes/mount-lite.ext.namespace-deps
...

For simplicity they can always be released at the same time and assigned the same version using some Leiningen plugin like lein-monolith.
Having separate libraries for extensions would facilitate using of additional third-party libraries such as loom in those extensions - there will be no need to dynamically load them.

Then, users might use the extensions on opt-in basis, as well as for development only by including them under :dev profile (as we do, we use mount.extensions.basic, mount.extensions.data-driven and mount.extensions.namespace-deps just for tests).

Please let me know what you think.

@aroemers
Copy link
Owner

aroemers commented Jan 15, 2019

Hi Dmitrii!

Sorry for not responding earlier; busy times.

About the issue at hand. I either do not fully understand the problem, or your use case seems to work fine. I created a small test project to reproduce the issue. There it all seems to work fine, both in the REPL, and running it using lein run. If you still have the issue, can you supply a minimal codebase that reproduces it?

Third, I could also imagine that mount-lite extensions can be distributed as separate libraries:

You are right, that would be nicer indeed. Moving namespace-deps to another library would break current users that expect it in the core library. If major work will be done for mount-lite, I will definitely consider this!

@dryewo
Copy link
Contributor Author

dryewo commented Jan 16, 2019

Hello Arnout!

I opened a PR to illustrate: aroemers/mount-lite-18#1
The issue is reproduced, it only happens when you rely on "start-up-to" functionality - which we use in tests extensively.

aroemers pushed a commit that referenced this issue Jan 26, 2019
@aroemers
Copy link
Owner

Hi Dmitrii,

Could you check out https://github.com/aroemers/mount-lite/tree/fix-18 and see if it fixes the issue for you?

@dryewo
Copy link
Contributor Author

dryewo commented Jan 28, 2019

Hi Arnout,

Thanks for the quick fix! It indeed works, it let us get rid of roughly half of dummy states in the codebase. The other half has to do with needing to start parts of system in slightly different way that "start-up-to" currently supports, I will open a separate issue for that soon.

Could you please release the changes so that we can officially upgrade?
Thanks again.

@jmcs
Copy link

jmcs commented Apr 29, 2019

@aroemers are you going to do a release with this fix?

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants