beginners

Colton Goates 2025-10-06T22:52:28.545139Z

Here is the stack trace for the question above ⬆️

2025-10-06T02:26:48.241009Z

Hey all, I’m toying around with Clojure and have some grasp of the syntax and how to build out the project I want to build, but as I transition to getting my project structure in place I’m a little lost. I’m a infrastructure/build tools guy at heart so I always take the time to set up my projects in a way that makes sense for me from a devex perspective have noticed one thing that seem to be missing from Clojure: locked dependencies. Most languages encourage you to lock dependencies, and I can’t help but feel like it’s an obvious best practice - you should know exactly what you’re about to download and use in your project at any given time. Is my google/chatgpt/stackoverflow-fu that bad, or is there really no way to work with locked dependency versions in Clojure?

2025-10-08T03:59:10.420209Z

Invalid versions is cool, don’t know if I need these but I’ll definitely keep them in my back pocket. Thanks!

2025-10-06T02:28:35.874699Z

What does "lock dependencies" mean to you?

2025-10-06T02:31:08.274489Z

Yeah, great question! Maybe I’ll edit, but something that guarantees exactly what all the direct and transitive dependencies that will be included in the build will be.

2025-10-06T02:31:19.564999Z

The majority of clojure dependencies are consumed via maven, which requires specifying a dependency version(there are some pseudo versions for things like LATEST, but use of that is rare, and bad practice)

2025-10-06T02:32:34.283889Z

Depending on which build tool you use there is a specific deterministic algorithm that is used to resolve transient dependencies conflicts

2025-10-06T02:32:40.042769Z

The guarantee that I want is that the transitive dependency that I download and use when I first add a direct dependency is the same that a new person to my project would get in a month

2025-10-06T02:33:21.080009Z

I’m currently using deps.edn for my project.

2025-10-06T02:34:03.703009Z

That is how it is supposed to work

2025-10-06T02:35:21.451919Z

Maybe Clojure projects are different, but when I’ve run Kotlin or Java projects, dependencies tend to just recommend a transitive dependency version, so you can get different versions if a new one is released after you add the dependency but before the next person resolves theirs

2025-10-06T02:35:26.498479Z

Technically, if the maven repo you use allows artifacts to be overwritten that can break that

2025-10-06T02:35:55.175799Z

That doesn't sound correct

2025-10-06T02:36:37.586999Z

Maven is primarily a java build tool, so if you were using it you should only get the version you ask for

2025-10-06T02:36:56.780449Z

Maybe you were using gradle or some other build tool

2025-10-06T02:37:24.015479Z

Oh is Gradle really that different? I thought it used the Maven resolver

2025-10-06T02:37:39.920109Z

The clojure ecosystem is to some degree built around the idea that behavior is distasteful

2025-10-06T02:37:59.178299Z

So you don't have separate notions of lockfiles

2025-10-06T02:38:11.279879Z

You specify what you want, and that is what you get

2025-10-06T02:39:28.948449Z

What happens when 2 direct dependencies disagree on the version of transitive dependency? In Java a very common shared dependency would be Jackson - I think the work project I work on has 5 different suggested versions of Jackson to resolve (but this is Gradle, so potentially caveats)

2025-10-06T02:39:43.013549Z

This would be a cool mindset change if I didn’t have to think about it

2025-10-06T02:43:33.178469Z

It depends, the lein uses mavens resolution strategy to pick a version, but tools-deps uses a slightly different algorithm. They are both deterministic, and both will result the same version chosen every time. The only way to get something new is if you change something, add a new dependency or change a version of a dependency

2025-10-06T02:44:09.018759Z

Oh that’s amazing then, thank you!

2025-10-06T02:44:22.798569Z

And if I recall for both something you explicitly choose always wins over anything from transient dependencies

🙌 1
2025-10-06T02:46:34.909059Z

https://youtu.be/sStlTye-Kjk?si=AZqN5Bks6dz9TnpZ might be an interesting watch, it is tools-deps focused and discusses some other stuff like git dependencies, but even for that tools-deps forces you to depend on a specific sha, you cannot depend on something that could change (tag, branch, etc)

1
pithyless 2025-10-06T05:20:59.023259Z

For different levels of paranoia personal comfort, here's some extra things you may be interested in (just to add, not contradict what @hiredman has already pointed out): • clj -A:with:your:aliases -Stree will give you a nice full dependency list of transitive deps. Feel free to scan it or even better - with some basic text scripting/manipulation, you can automate a check for new "unexpected" deps or potential conflicts • From https://clojure.org/reference/deps_edn be aware of: ◦ :exclusions:override-deps:classpath-overrides • As was mentioned, deps-tools will use any version of a dependency in your deps.edn (since it's higher in the tree) OVER the one asked for via a transitive dep. So one way to override any transitive dep is to ensure it's directly in your deps (or one of your aliases that is always pulled in). • For the truly paranoid, you can actually have your main deps.edn define all the deps (use -Stree to ensure you get them all) with an invalid target (eg. {:mvn/version "INVALID"}. Running your build will crash (red test) and you can then explicitly add a proper version e.g to an alias :versions (green test). From this point forward, any transitive dependency pulled in will get the version in :versions (whether the libraries works with that version is now your problem, but at least now it's explicit). Rinse and repeat and you will have essentially built up a "lockfile" of all your transitive deps in your project. I think everyone would caution this is probably over kill, but I think these are useful tricks to have in your backpocket (and have helped me debug some builds).

Colton Goates 2025-10-06T03:27:23.186599Z

I could use help interpreting this stacktrace in *cider-error*. How would I know which such-that predicate messed up in my code? It doesn't seem to say

p-himik 2025-10-06T08:01:28.156069Z

For future reference, please attach long code listings as snippets. Slack collapses snippets by default, and it makes it much more usable than having to scroll multiple pages even on a large monitor, let alone on a mobile device.

👍 1
2025-10-06T03:39:17.415509Z

If you search for such-that in #clojure-spec or #test-check you should find some discussion. I don't have a way off the top of my head, but any s/and spec without a custom generator has a good chance of causing this

👍 1