my first inclination would be to represent the diff as plain old data, like what clojure.data/diff
produces
They asked for both the diff and the āminimal transactionsā, but if that is your instinct, thatās informative, because maybe it means that the data is whatās important, and executing it is a minor variation.
I don't like the way he put it, but Linus Torvalds' quote has always stuck with me:
Bad programmers worry about the code. Good programmers worry about data structures and their relationships.
Does that
Iām messing around with clojure.java.classpath
. If I require it in a lein repl
and call the clojure.java.classpath/classpath
fn, I get an empty list. I would expect to see something at leastā¦
make sure you have a version that actually supports JDK9+, older versions only work up to JDK8
the documentation says:
"Returns a sequence of File objects of the elements on the
classpath. Defaults to searching for instances of
java.net.URLClassLoader in the classloader hierarchy above
clojure.lang.RT/baseLoader or the given classloader. If no
URLClassloader can be found, as on Java 9, falls back to the
'java.class'path' system property."
In Joy of Clojure, 2nd ed p. 450 they say: > UsingĀ dynamic bindingĀ is the preferred way to handleĀ recoverable errorsĀ in aĀ context-sensitive manner. They also say on p. 447 that > In its purest form, dynamic binding is a structured form of a side effect. The example they show is something like this: https://github.com/jumarko/clojure-experiments/blob/master/src/clojure_experiments/books/joy_of_clojure/ch17_clojure_way_of_thinking.clj#L474-L517
(defn ^:dynamic handle-weird-animal
[{[name] :content}]
(throw (Exception. (str name " must be 'dealt with'"))))
...
(defmethod visit :animal [{[name] :content :as animal}]
(case name
;; Note: could be `cond` and use `#{"Spot" "Lopshire"}
"Spot" (handle-weird-animal animal)
"Lopshire" (handle-weird-animal animal)
(println name)))
;; the default error handling
(traverse DB visit)
;; 1. Unhandled java.lang.Exception
;; Spot must be 'dealt with'
;; custom error handling
(binding [handle-weird-animal (fn [{[name] :content}] (println name "is harmless"))]
(traverse DB visit))
Is this something that people actually use as a standard practice?
I tend to frown at dynamic binding because it's implicit rather than explicit and can lead to unpleasant surprises.Yeah a defn that throws exeptions unconditionally by default sounds like a defprotocol/defmulti in disguise
That is an idiom you can use to emulate Common Lisp -style conditions and restarts but I haven't seen it actually used
And I avoid dynamic binding in general because it is bound to the low-level thread abstraction so it breaks in the presence of fancy thread pooling like core.async
and even just lazy seqs
If you're looking for an actual implementation of Common Lisp's condition system, check out https://github.com/IGJoshua/farolero, which uses dynamic bindings
@nilern point is just right! Iām working with dynamic binding (async context) in conjuction with core async on daily basis and itās one big hack which I wish to get rid of someday.
Stupid question: is Pedestal still the go-to choice for web applications? I had a good experience with it so far but wondering if people are using something different nowadays
Same as @markbastian except with Mount instead of Integrant.
Pedestal is pretty great and I like how the server part is integrated (if you use jetty).
Regardless Jetty seems to be the real go to
@emccue Honestly, any server that doesnāt require being independently set up is my goto when writing code. Iām gonna proxy it behind nginx anyway.
I wouldn't say that there even is the go-to choice for web applications. There are many choices.
FWIW, I'm using Yada.
I guess a better question would be ā what are the alternatives today?
@vincenz.chianese Are you asking about full stack apps or just backend web apps?
Iām mostly interested in developing backend ā pure API apps
At Metosin the go-to stack was Ring + Reitit and it is in the new Web Development with Clojure book too
I think most folks just go for compojure-api for backend API apps?
At work we donāt even use compojure-api ā just plain olā Ring + Compojure, although we also have a GraphQL app. And one app uses Bidi instead of Compojure.
Nobody wants to maintain compojure-api, definitely prefer Reitit for new apps
Pedestal always felt like overkill to me.
@nilern Yeah, thatās def. the impression Iāve been getting too. I think I would try Reitit for any new web apps I wrote at this point. But compojure-api is def. āpopularā still š
I like pedestal - its docs could use some love and probably some parts of it could use a decoupling, but the interceptor thing is overhead i like the moment i want to do websockets
Reitit has interceptors too š
You can use any interceptor lib with plain ring
I still like yada but it's not very actively maintained. Still, it has what I need, including swagger and async
What I do not like about Pedestal so far (I know thatās stupid) is the fact they ask for a :route-name
that really feels useless
Other than that, I do not have any particular complains ā I was mostly interested in alternatives
It's useful for reverse routing in theory, like from templates
But maybe nowadays it's less of a thing
Not something that iām particularly interested but I see the point
On frontend reverse routing is more often useful but also on the backend good to have for redirections at least
Of course if you don't make a SPA then all that link generation moves to the backend as well
Reitit, ring-jetty
we use pedestal at Nubank & Cognitect
The main lib combo I use for webapps these days is integrant (system composition) + http-kit (server) +ring (server abstraction) +reitit (routing). Iām very happy with it.