This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-11-21
Channels
- # aleph (2)
- # announcements (2)
- # babashka (10)
- # beginners (117)
- # calva (11)
- # cider (19)
- # clj-kondo (27)
- # cljs-dev (24)
- # cljsjs (1)
- # clojure (73)
- # clojure-europe (3)
- # clojure-italy (2)
- # clojure-nl (47)
- # clojure-spec (23)
- # clojure-uk (28)
- # clojurescript (71)
- # cursive (7)
- # data-science (17)
- # datascript (1)
- # datomic (7)
- # duct (23)
- # emacs (23)
- # fulcro (6)
- # graalvm (41)
- # jobs (2)
- # luminus (1)
- # malli (1)
- # off-topic (151)
- # pathom (1)
- # portkey (10)
- # re-frame (12)
- # reitit (17)
- # shadow-cljs (158)
- # spacemacs (14)
- # sql (8)
- # tools-deps (17)
- # xtdb (9)
I seem to still struggle with organizing and naming things when trying to use qualified keyword keys? Does anyone else feel that way?
Maybe I'm wrong trying to outline the hierarchy inside the namespace, but otherwise it gets tricky. Say I also have a :db.group.profile/name
And since I have specs for all these, and specs are in a global namespace, clashes can happen
If I just said :profile/name
it would seem way less heavy handed, but someone somewhere else would overwrite its spec by accident when creating group profile names.
Another issue I sometime face is that maybe I have :db/user
be a spec with a qualified key of say :db.user/name
and maybe I have some API called create-user
and I don't want to tie its spec to the db
spec. So I want a :create-user/user
key spec, but for now that's the same as the db, except if I say: (s/def :create-user/user :db/user)
it means that the API has to take a map of the form: #:db.user{:name "John"}
I advocate something along these lines:
• all specs are ns-qualified (`::foo`)
• these ns-qualifed names are also used as Datomic attribute names
• each ns represents one model
• each ns is an API , solely dedicated to containing specs. That way I know to not alter the ns name
• each model has one "write model" (a keys
spec) which is the sole thing allowed to be persisted, and N optional "read models" that are derived from the write model
• DRY specs (the problem you indicate in Yet I don't want to have to redefine a whole new spec
) are achieved through metaprogramming
I've worked with these to different degrees throughout the last 2 years
I see a user
model and a profile
model. Just like I would in something like Rails (two SQL tables, two ActiveRecord models)
So you'd just rely on aliases to make that pleasant? Like
(-> m ::db/user ::user/profile ::profile/name)
And what about your API specs? This defines your data specs for what goes in your DB. If you have APIs, like Rest APIs, do you have them share specs with the DB ones, or you just create new ones for that?
> So you'd just rely on aliases to make that pleasant?
Yes
Probably I'd code it like this
(-> m ::user/model ::user/profile ::profile/name)
i.e. get rid of the db
prefix. In Datomic I don't use that prefix - I leave it reserved for Datomic internals
Oh, I think that was an accident. I actually don't use Datomic. Was just a coincidence my key is also a datomic key it seems.
Ya, I can try that approach. You kinda have to require a lot of models 😛 to get all those aliases. But its better then what I currently had where I just typed it all out.
I also had all my models in one namespace. And I wasn't using ::, I was creating namespaces by hand as I spec things. So that meant I couldn't rely on aliasing to make the names smaller.
wrt REST, here's an example:
(ns invoices.write-model)
(spec/def ::foo int?)
(spec/def ::bar int?)
(spec/def ::model (spec/keys :req [::foo ::bar]))
(ns invoices.rest-api)
(spec/def ::GET (spec/keys :req-un [:invoices.write-model/foo])) ;; I can skip bar.
my advocated pattern works well at scale, it's thought out for a landscape of multiple apps, modules etc might be overkill for other scenarios
Right, I see, so you define a new keys spec for the API, using unqualfied versions of the write spec. Not bad.
Its kind of an interesting topic. I feel there would be a lot of different strategies out there. Everytime I start something new I feel I change slightly how I spec things 😛
yeah it's part of the beauty of spec - not being too prescriptive, allowing a variety of designs/purposes etc :)
I faced these same issues with my library Iboga, which wraps my stock broker's java api client. Basically I use relflection to turn their method calls into data messages to be passed around. So the method
com.ib.client.EWrapper/historicalData(int id, com.ib.client.Bar bar)
becomes (fully qualified version:)
:iboga.recv/historical-data {:iboga.recv.historical-data/id 123 :iboga.recv.historical-data/bar {:iboga.bar/time 111 :iboga.bar/close 222 ....}]
orginally the user interface I presented eliminated the need to use qualified keywords, and the structure was walked and qualified to be used internally/spec'd
But then I started dog-fooding the library myself and found that increasingly I wanted the verbose fully qualified keys and switched back to just requiring them (in the unpublished current version)
the qualified keys names are generated automatically from java reflection, and there are hundreds of "methods" with 0-10 args (average probably 2-3)
I could probably get away with less qualified keys, like qualifying the method name keys but not the arg name keys, but I think I've grown to accept that it's just going to be somewhat verbose typing these things. Internally they all need to be fully qualified so just forcing them to be input that way means there's less code the library has to maintain
I also kind of feel that I'm using keywords too "hierarchically" when they're not particularly great to use that way
when representing something that's a graph, I don't really get any leverage from structuring my keywords that way. But then when I also want them to be globally unique, I end up having to name them their full graph path anyway
these are just some ramblings about keywords I don't really have a point. But I too have wondered if other people had pain points here
Yet I don't want to have to redefine a whole new spec, since for now they're the same... except for their namespaces
Hi! I’m trying to solve a problem for localization testers of an SPA. I constantly have to create breadcrumbs, so they know how to find the texts that I added or changed. So, I was wondering, If I could use a webcrawler for that. I looked at two of them but the way it looks they just follow links and create an index of the pages they’ve visited. They can collect information from the page but if I want to create an index of breadcrumbs for all texts, the crawler would have to click buttons and write texts and stuff like that. Is this something webcrawlers can do?
I’m struggling to remember the name of a Clojure library that generates data structures for testing databases. I have a vague recollection it used spec? Does anyone have any idea which library this might be?
Ah, found it. I was thinking of: https://github.com/reifyhealth/specmonstah
I'm looking for a style guide or some discussion around using _foo
for unused vars that are kept for the sake of documentation.
It might be in a defmulti
like this:
(defmulti [kind _ctx] kind)
Can't find anything on Googleits just a convention to mark unused locals with a leading underscore
oftentimes that will show up in abstraction methods (interrfaces, multimethods, protocols) b/c you might not need all the params in every method impl
but they are not special in any way, just regular symbols treated exactly the same as any other local symbol
Cool, I do see several tools supporting this convention (Cursive, as well as some linters), so I just thought it might be more than just a convention. It's something that I use myself, but if I'd like to get a whole team to use it, it's always good to have some kind of reference at least 🙂
Hi folks, i’m using @seancorfield’s dot-clojure file, and trying out building an uberjar. It builds succesfully, but upon running, it throws ClassNotFoundException for clojure.pprint.
I run it as clj -A:uberjar:1.10 MyUberJar.jar
you can't run uberjars through clj like that
clj will make a command line like java -cp ... clojure.main ...main-args...
for an uberjar, you want java -cp MyUberJar.jar
or java -jar MyUberJar.jar
depending on how the jar is created and whether it has a manifest with a main
ah just tried adding clojure.pprint in the require of the main’s ns, rather than using (clojure.pprint/pprint {:my :data}
in my code directly … works
https://github.com/seancorfield/dot-clojure/blob/master/deps.edn I used this by the way
Does anyone remember the name of the site where you can put sample input and output for a clojure function and it will tell you what function it might be? I believe it used spec to guess what would work.
Anyone know how to get around recaptcha with selenium?