Fork me on GitHub
#tools-deps
<
2020-07-04
>
p-himik18:07:36

If A depends on B, and my project depends on A and B but doesn't really care about the version of B as long as it's compatible with A, how should I specify this dependency on B in deps.edn? Or should I just omit the dependency on B from deps.edn?

seancorfield19:07:41

I would figure out what version of B your chosen version of A depends on and explicitly specify that in deps.edn -- and add a comment about the version selection reason. Assuming you mean that your project has an explicit dependency on B.

p-himik19:07:50

That was exactly my thought initially. But now that I've given it some thought - wouldn't it be more practical to just omit it altogether? If A starts to depend on a different version of B, I should be unaffected, and I won't need to change anything. If A drops the dependency, the code will just not run because there's an explicit :require. And specifying B in my deps.edn seems like just giving myself more work when I update my dependencies.

seancorfield19:07:03

If A changes the version of B it depends, it also changes its own version -- so unless you are changing the version of A you depend on, you wouldn't be affected 🙂

seancorfield19:07:04

That's my point: if you choose to depend on a newer version of A, you should also verify the compatibility of the newer version of B that it now depends on as well. Having an explicit dependency on B lets you force the earlier version of B if you need that.

seancorfield19:07:18

If A stops depending on B, that also means a new version of A and you could decide to stay with the old version or move to the new version -- and because you have an explicit dependency on B, you code won't break (at least, not because A's transitive dependency on B went away).

seancorfield19:07:23

I really don't like relying on transitive dependencies. I much prefer to have all my dependencies listed explicitly. I've learned that over the years after a decade of Clojure in production 🙂

p-himik19:07:35

Hmm, I think I didn't give enough context. I definitely agree with your reasoning about the generic case of relying on a transitive dependency. But in my particular case, the code should either break completely if B is changed/removed, or it should continue working just as I expected it to. So the compatibility with my project is not a concern. At the same time, if I manage to forget to update B after updating A, I may introduce some incompatibilities between A and B that are hard to test.

p-himik19:07:57

To be more concrete - I'm just using ring.util.mime-type/ext-mime-type function without having an explicit dependency on ring/ring-core.

p-himik19:07:36

Of course even such a dead simple function can potentially be broken with an update. But I consider it so improbable that it's not worth taking into account. Akin to how I don't expect clojure.core/map to suddenly start giving me different results.

seancorfield19:07:59

But you have code in your project that depends on Ring namespaces?

seancorfield19:07:42

To be concrete, what are A and B specifically in your project?

p-himik20:07:09

A - yada/core B - ring/ring-core I need only ring.util.mime-type/ext-mime-type from B, which I consider stable in a sense that any changes around it either break the app startup or don't affect the app at all.

p-himik20:07:30

I don't depend on anything ring-related but that small function.

seancorfield20:07:20

Ah, OK. If that is the only Ring namespace you're touching then maybe I would agree and just depend on Yada. It still feels a bit sketchy to me. We depend on Ring and we don't use that var -- we have our own MIME type structures (because we want a specific set of supported values, rather than a generic list).

p-himik20:07:21

I wish I would have a specific set. :) Yeah, I can see how it can feel sketchy. I'm still not sure about the way I work with my dependencies at all right now, given that there's also CLJS and a build process that involves shadow-cljs. Maybe this all could be made nice and simple with aliases. An unrelated to the rest of the thread question - aliases cannot be grouped together under a new alias, right? So I will probably have to write a script to call clj -A:al1:al2:al3.

seancorfield20:07:04

Nope. Grouping of aliases is a common request.

p-himik20:07:06

I see. Anyway, thanks for the input Sean. Much appreciated. :)

seancorfield20:07:09

It's why at work we have a build shell script that wraps the clojure script so we can have "higher-level" aliases.

p-himik20:07:05

Right, I've seen this pattern before. Sometimes even with -Sdeps, to avoid cluttering the main deps.edn I guess or to make the script more portable.

seancorfield20:07:52

Our build script serves two purposes: to allow us to run a series of clojure commands from a single invocation, and to provide various shorthands for common combinations of aliases (our aliases tend to be very granular). But we're all Clojure / backend. I suspect if we were managing ClojureScript as well, we'd be even more reliant on our wrapper script!

seancorfield20:07:14

I'm looking forward to tools.build -- I suspect it will help simplify our tool chain quite a bit.

p-himik20:07:21

I don't think I've heard of it and I can't find anything that seems relevant. Is there an announcement or something like that?

seancorfield20:07:35

Alex mentioned it in an Inside Clojure blog post and has mentioned it several times here.

p-himik21:07:53

Heh, found it: "tools.build - shh, top secret"

seancorfield21:07:05

Giving Cognitect's solid track record of producing simple, well-considered, composable tooling that addresses core Clojure developer needs, I'm looking forward to whatever this turns out to be 🙂

👍 3