Fork me on GitHub
#clojure
<
2020-06-11
>
athomasoriginal00:06:53

I have noticed a convention of using user.clj which requires in a dev.clj ns like https://github.com/pedestal/pedestal/blob/239d2c7899ac3466a32ab124ab3850e56abeb0c5/app-template/src/leiningen/new/pedestal_app/annotated/dev/user.clj. Does anyone know why this is done vs. keeping everything in user.clj?

noisesmith00:06:28

user.clj is auto-loaded by clojure if it's on the classpath

noisesmith00:06:54

dev.clj isn't "magic" in that way, so you have more direct control of when / whether it is loaded

seancorfield00:06:47

It means you can avoid any/all dependencies that dev.clj needs (as long as you don't call (dev)). So you can isolate dev dependencies from "regular" dependencies.

seancorfield00:06:21

I think the only thing I've ever used user.clj for is auto-compiling a namespace that uses :gen-class to generate a Java class from Clojure code, which the rest of the project relies on.

noisesmith00:06:21

and as an aside, the idiom I've learned for (require 'foo) (in-ns 'foo) is (doto 'foo require in-ns)

metal 11
seancorfield00:06:38

Ah, yes, nice.

noisesmith00:06:50

easily augmented to (doto 'foo-test (require 'foo :reload) (clojure.test/run-tests)) when iterating on tests - it's still one line which is nice when using repl history

athomasoriginal00:06:46

Ahhh, makes sense.

athomasoriginal00:06:27

@seancorfield You mentioned you only use user.clj for the :gen-class use case. Does this mean that for your projects, you don’t setup a user -> dev reloaded workflow?

seancorfield01:06:28

I never use any sort of automated reload/refresh workflow.

seancorfield01:06:06

I eval every change, as I make it, directly into my running REPL and I run a REPL for many days, sometimes even weeks.

6
lilactown01:06:52

nirvana 😄

Alex Miller (Clojure team)03:06:49

+1 to seancorfield - I do the same thing as Sean and have never used the reload/refresh workflow either. I understand how that came to be a thing but I think you can get many of the same benefits in other ways that don't need that.

Alex Miller (Clojure team)03:06:17

if you spend some time in the clojure code base, user.clj is deeply weird and different than how every other thing is loaded in Clojure. I prefer to write dumb boring code that does obvious things and invoke it when I want to run it.

andy.fingerhut03:06:23

I have not asked, but I suppose that one property of Sean's approach is that if you ever forget to re-eval a modified function, then the JVM state and source file state now differs, so it does require some pretty tight discipline. Perhaps an attractiveness of a reloaded workflow style for some developers is the belief/hope/often-true aspect that it keeps these things in sync automatically?

Alex Miller (Clojure team)03:06:29

I frequently reload the particular namespace I'm in

Alex Miller (Clojure team)03:06:19

you can still get out of sync if you've removed things in the code but they're loaded in memory. I rarely find that to be an issue and since I'm constantly evaluating things.

solf03:06:31

Where can I read more about this "automated reload/refresh workflow"? Is it what's described here? https://lambdaisland.com/blog/2018-02-09-reloading-woes

seancorfield03:06:33

To Alex's point about things remaining in memory after you've removed them from code, even if you reload the namespace, I have ctrl-; r bound to remove-ns but I only use it very occasionally because you can still have references to that code compiled elsewhere so it's sort of the "nuclear option" (and it's part way toward those refresh/reloaded workflows I try very hard to avoid).

seancorfield03:06:52

I also have ctrl-; R bound to require ,,, :reload-all for the current namespace. Again, it's a bit of a "nuclear option" that I try to only use as a last resort. Both remove-ns and :reload-all can cause a ripple effect, depending on how much code you have in memory.

seancorfield03:06:28

I tend to edit, ctrl-; B (evaluate top-level block/form), repeatedly as I'm working -- without even saving a file -- trying stuff out with expressions inside comment forms ("Rich Comment Forms" per Stu H), switching between files as I work, developing and testing code, developing and testing tests, etc. Once I have a "feature" working in memory, in the REPL, I'll pop into a terminal window and run a subset of the test suite to just verify I don't have passing tests in memory due to leftover "cruft". If that small feature works, then it's git add/commit/push to branch. Rinse and repeat.

seancorfield03:06:32

I also make heavy use of Cognitect's REBL while I'm working, both to visualize data and to "visualize code" -- I have a bunch of keys bound to commands that submit various things to REBL so I can browse namespaces, Var uses, even ClojureDocs and Java API docs directly in REBL (since it renders .URL objects as HTML web pages -- and then you can navigate around with your current and previous pages showing, side-by-side).

orestis05:06:47

I work in the REPL but have setup a namespace to invoke tools...refresh (can’t remember the exact namespace) to remove everything and go back to source files. Useful if you mess something up real good, when switching branches, to just sanity check if something appears off.

seancorfield05:06:56

@orestis So you consider it a "last resort"? (I hope)

orestis06:06:45

Yes, a last resort for unusual circumstances

4
dominicm07:06:25

I use it all the time, fight me :)

4
dominicm07:06:41

I work with a lot of web handlers though, which close over state and are difficult.

p-himik07:06:57

Despite reading all that I saw from time to time on the topic, I still fail to see the appeal of manual reloading. To me, it's like driving a stick. Needless to say, I got a driving license only for an automatic. :)

seancorfield07:06:03

"fail to see the appeal of manual reloading" -- control and simplicity.

seancorfield07:06:18

(I'd much rather drive a stick shift!)

seancorfield07:06:42

(esp. when that was a 5L Mustang Cobra 🙂 )

p-himik07:06:51

Sorry, a correction: "... of manual reloading at all times". I understand the occasional need, and even I do use that (but only if the automatic reload didn't get those pesky defrecords). But all of the time? Nooo, let the system take the wheel.

kwladyka11:06:18

I think this is not directly connected to Clojure, but I stuck with this. I was trying to get help in more cloud specified community, but without success. Maybe somebody here know solution:

curl -H "Content-Type: application/json" -d '{"foo":"bar"}' -X GET 
curl: (92) HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
http-kit logs
Thu Jun 11 13:23:15 CEST 2020 [client-loop] ERROR - select exception, should not happen
java.lang.IllegalStateException: Client/Server mode has not yet been set.
	at java.base/sun.security.ssl.SSLEngineImpl.beginHandshake(SSLEngineImpl.java:102)
	at org.httpkit.client.HttpClient.finishConnect(HttpClient.java:395)
	at org.httpkit.client.HttpClient.run(HttpClient.java:472)
	at java.base/java.lang.Thread.run(Thread.java:832)
Thu Jun 11 13:23:15 CEST 2020 [client-loop] ERROR - select exception, should not happen
java.lang.IllegalStateException: Client/Server mode has not yet been set.
	at java.base/sun.security.ssl.SSLEngineImpl.beginHandshake(SSLEngineImpl.java:102)
	at org.httpkit.client.HttpClient.finishConnect(HttpClient.java:395)
	at org.httpkit.client.HttpClient.run(HttpClient.java:472)
	at java.base/java.lang.Thread.run(Thread.java:832)
but exactly the same code in the same docker image works in my local environment. The issue is about -d '{"foo":"bar"}'. Without this:
curl -H "Content-Type: application/json" -X GET 
not found⏎
^ expected result AFAIK google cloud run use HTTP/2. Does it change anything? Any hints what I can do wrong? In metric and logs I see google cloud run break this connection before it goes to the docker container. This is something about network protocol probably. But it doesn’t work for me in http-kit client and in curl. hmm. No idea what to do with this.

kwladyka11:06:39

I also found this works with POST, but not with GET

kwladyka12:06:44

well I have no idea, but it looks HTTP/2 send request GET with body is not something valid. At least in google cloud.

valerauko12:06:08

can you send the request without body?

valerauko12:06:38

get with body really isn't something you should be doing

kwladyka12:06:08

I need to send a data, I will switch to POST

kwladyka12:06:24

but this doesn’t effect any state

Prakash13:06:52

GET request is not expected to have body according to HTTP spec

kwladyka13:06:39

still very strange error from server, I see this first time

Prakash13:06:31

yes, that is pretty cryptic

roklenarcic13:06:20

what’s the easiest, tersest way to update a map with default values for keys that are nil?

Alex Miller (Clojure team)14:06:38

well I'd put my effort into not putting nils in the map in the first place then (merge defaults the-map)

Ben Grabow14:06:22

If for some reason you really need the nils, you can do (merge-with defaults the-map (fn [default-val val] (if (some? val) val default-val)))

Ari16:06:45

Is there a way to use into along with a transducer that has two input sequences? For example:

(into [] (mapcat vector) [:x :y :z] [1 2 3])

Alex Miller (Clojure team)16:06:14

the only transducing context that takes multiple inputs is sequence

Alex Miller (Clojure team)16:06:59

conceptually, there is no reason this couldn't exist (and the guts are already there, as used by sequence) - but the arities collide in all the existing sequence functions like map and mapcat

Alex Miller (Clojure team)16:06:19

the existing map transducer (and thus also mapcat, as it's just a composition of map and cat) does support multiple inputs, that's just not exposed through into etc

Ari16:06:58

Ok, thanks for explaining 👍

Drew Verlee18:06:38

whats the ideal way to write a clojure data stucture to an .edn file? it seems like i should use pr-str then spit. but i dont see anything definitive on the subject. just trying to avoid any gotchas. bonus points if there is a way to save it in a formatted way...

noisesmith18:06:30

pprint takes a writer arg

Alex Miller (Clojure team)18:06:46

Or re-bind *out* around pprint

Eduardo Mata20:06:27

I am using boot instead of lein. I was used to doing lein ancient to check outdated dependencies. What could I use to get the same result in boot?

Derek20:06:39

boot show --updates i believe

✔️ 3