I'm working on a tool and considering using spec to validate its arguments at runtime - anyone doing that? are you using (s/valid? spec data) pre/post, something else?
instrumentation?
stest/instrument? It's meant for testing but sure why not I can use it
at least in a couple of projects I recall using s/valid? as a "always check, even in prod" and instrumentation as a "check when developing locally or running tests".
It's used very extensively in https://github.com/bob-cd/bob a large ish mono repo, look for spec/valid? calls. The idea is to check every IO call with a spec and since this is a monorepo, that serves a nice way to do integration, regression checks apart from unit tests too with a central spec registry: https://github.com/bob-cd/bob/blob/main/common/src/common/schemas.clj
It does have a perf tradeoff when it comes to latency but saves more dev/test time
This is for a CLI tool, less concerned about this degree of performance
It's also going to launch a long ish running process
then id say using specs at the edges like i do in bob is quite nice
I use spec for this kind of validation checking in tools.build. Built on s/valid? but I created some scaffolding around it
Doing args parsing with spec immediately made me feel the need for the behavior in spec2 for specifying a set of keys and orthogonally specifying optionality
well, with Clojure 1.13 you can get that with :keys!
Requiring users upgrade Clojure to use my tool seems rude, or is the clojure version a tool runs with separate from the invoking version?
"tool" .... like with the Clojure CLI? or something else
like with the Clojure cli, yes
I want users to be able to install and invoke using -T
for all dependencies except Clojure itself, that is up to the tool and is independent from the project classpath. Currently, tools will always use the Clojure version of the installed CLI (so Clojure 1.12.5 for CLI version 1.12.5.x). That is actually not by intention but the reasons and fix is tedious, at some point I will get it taken care of.
> I use spec for this kind of validation checking in tools.build. I did an experiment to include tools.build in bb with a few approaches. One approach was to just compile it into the image. It works, but the spec validation gets in the way of image size optimizations. bb grew from 70 -> 100mb, instead of just the 75 that you get when spec validation is removed. It has to do with a runtime resolve that native-image doesn't like (when it comes to image size): https://github.com/clojure/spec.alpha/blob/6b698eed1787c14907082c86de3410dd51e816b4/src/main/clojure/clojure/spec/alpha.clj#L323
I'm still continuing the experiment btw by including tools.deps as source (loaded on demand) and stubbing in only the mvn stuff. That didn't shrink the 5mb a lot. If i replace the mvn stuff itself by a re-implementation (vibed...), it does help a lot, so that seems like a path forward, maybe one day. Anyway, a side remark.
The core issue with the image size is that anything that reads the ns mappings at runtime will make native-image think that it should hold on to everything loaded at build time.
The only thing I would watch out for at runtime is function specs since checking those involves generating args and calling the function. Otherwise using spec for validation and even parsing at runtime works well. At my last job we used it for web request data(https://github.com/worldsingles/web-specs) and some internal validation of key data structures(although I bet that has all been replaced with the keys! stuff by now) and then conform for parsing (taking a seq of a mix of different kinds of maps and transforming it into something more structured)
I think with the new stuff coming in 1.13 destructuring I may move tools.build validation to that
To be released still is the new :missing directive, coming in the next alpha
That covers what I need for map key checking. Not sure the predicative parts are worth the spec validation, could be simpler