Fork me on GitHub
#clojure
<
2017-03-01
>
dpsutton00:03:24

saw someone running into this on the latest osx (sierra?) when trying to install packages from melpa. The issue seemed to be that osx put that cert inside of a cert store that it was unwilling to share with emacs in the normal way

dpsutton00:03:04

I don't believe it is really emacs specific though so if you wanted to look into that

attentive05:03:16

Hey all, anyone have any suggestions on an existing web-based CMS (with end user content editing features) that's a good fit for clj / cljs website development? I'm more interested in the fit with Clojure, ring, friend etc, and the UX for content administrators than that the CMS itself be written in Clojure.

zea06:03:45

Hi all! Anyone care to share their fave book/screencast for clojure newbie like me? 🙂

qqq06:03:26

also, it's not hard to watch all the videos in < 1 month, so its' really$3.99 total

zea06:03:25

not available in my country 😞

qqq06:03:36

====== in core.match, is there a way to say : if a variable is arleady bound, BIND IT AS NEW VAR, instead of expecting it to match up with old value? for example

(let [x 3
  point [:vec2 23 34]]
  (match [point]
    [[:vec2 x y]] --> fails since instead of binding x=23, it expects 3 = 23
now, I could prefix my vars with ?x ?y or x y ... but then I'd also ahve to use ?x ?y or x y on the rhs is there some way where: I use ?x ?y on lhs, and x y on rhs or I use x y on lhs and x y on rhs ?

qqq06:03:38

http://www.parens-of-the-dead.com/ <-- also good if you want to see a pro at work

zea06:03:40

anyway, I just using Tor, and now I can open it! Thanks @qqq

qqq06:03:26

@zea: wait, so youtube blocks your country based on IP, but doesn't block your country based on credit card ?

zea06:03:08

Umm... Some of his videos is free... 😕

hit02307:03:07

Hello, developers! Can someone guide me on how to get started with Contribution to Clojure; in terms of the mode of communication preferred (which channel on Slack? ) and tools ?

zea07:03:29

What is the difference between def and defn? 😕 thanks!

residentsummer08:03:28

@zea (def name 1) - defines a var, defn is a kind of shorthand for (def name (fn …))

residentsummer08:03:30

iow, it defines a function

zea08:03:07

so, def is assign variable and defn is create function?

curlyfry08:03:30

@zea In the future I think questions of that nature are more suitable for #beginners

residentsummer08:03:50

def binds a name to a value, yes

residentsummer08:03:10

I recommend clojure koans to get initial skills

zea08:03:54

Okay @curlyfry I just join the channel, thanks!

jellea09:03:41

Morning! core.match Q: I need to store some patterns outside of a match function and I have troubles with apply (because core.match is a macro? and because I'm on cljs?) What is the normal way of doing this?

val_waeselynck09:03:56

@jellea I don't think core.match has dynamic matching, so the only way to use core.match with runtime-resolved patterns would be to use eval ...

jellea09:03:18

@val_waeselynck hmmm that might be an option!

residentsummer10:03:42

@jellea do those patterns just stored in the different place?

residentsummer10:03:27

or they ain’t known at compile-time?

residentsummer10:03:21

in the first case it’s possible to write a macro that will produce required match form with your patterns resolved at compile-time

jellea10:03:22

just in a different place, known at compile time

pesterhazy10:03:42

permacode, a library for content-addressable clojure code, looks interesting: https://brosenan.github.io/permacode/core.html

pesterhazy10:03:11

could this be used to build up a spec registry of community-tested functions?

pesterhazy10:03:20

that way generative tests for specced functions would only have to be run once globally

wottis10:03:38

It throws the following exception IllegalArgumentException No matching method found: setCapability for class org.openqa.selenium.remote.DesiredCapabilities clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:80)

wottis10:03:29

though setCapability is a instance method

pesterhazy10:03:23

are you sure both arguments are Strings?

pesterhazy10:03:32

try wrapping them in (str)

wottis10:03:48

pesterhazy thank you

pesterhazy10:03:58

I suspect the first one may still be a keyword

wottis10:03:37

you're right

kepinpin11:03:51

Hi guys, I have a question about leiningen. Is it okay to ask about it here, or is there a lein channel?

pesterhazy11:03:06

here's fine I think

pesterhazy11:03:24

there's #leiningen too

qqq11:03:21

when you want something imperative instead of declarative, there's also #boot 🙂

qqq11:03:40

in retrospect, Makefiles were really smart

kepinpin11:03:27

@pesterhazy thanks, I'm going to ask there first

kepinpin11:03:19

@qqq boot is nicee

qqq11:03:20

@kepinpin : boot is amazing; I always found lein unapproachable where I could configure existing plugins but never write my own; boot on the other hand, is pretty straight forward in comparison

kepinpin11:03:46

by the way, the lein channel seems to be pretty quiet, so I'm asking here too: I tried this :jvm-opts ["-Xbootclasspath/a:/usr/lib64/libreoffice/program/classes"] but when I connect to the repl and print the classpath, the path is not there

pesterhazy11:03:29

looks like there's a typo there?

kepinpin11:03:39

reformatting, my question is: I input the option :jvm-opts ["-Xbootclasspath/a:/usr/lib64/libreoffice/program/classes"] to my project.clj. But when I connect to the repl and print the classpath, the path is not there

pesterhazy11:03:14

hmm maybe not, hadn't heard of -Xbootclasspath

pesterhazy11:03:53

have you tried export JVM_OPTS=... ?

pesterhazy11:03:37

or is it JAVA_OPTS?

kepinpin11:03:30

@pesterhazy not yet, I'm going to try that thanks

bigkahuna11:03:43

I think JVM_OPTS i.e. export JVM_OPTS=-Xms4G ...

bigkahuna11:03:11

@kepinpin I think JVM_OPTS i.e. export JVM_OPTS=-Xms4G ...

rauh11:03:31

What does (.getInputArguments (ManagementFactory/getRuntimeMXBean)) give?

kepinpin11:03:24

@rauh (.getInputArguments (java.lang.management.ManagementFactory/getRuntimeMXBean)) ["-Dfile.encoding=UTF-8" "-Xbootclasspath/a:/usr/lib64/libreoffice/program/classes" "-Dclojure.compile.path=/home/target/base+system+user+dev/classes" "-Dcljlop.version=0.1.0-SNAPSHOT" "-Dclojure.debug=false"] there it is!

rauh11:03:44

So that problem is something else 🙂

rauh11:03:56

Well I'm guessing bootcp not= cp.

kepinpin11:03:27

yep, I'm trying out different options now

kepinpin11:03:48

@bigkahuna in script start.sh: export JAVA_OPTS=-Xbootclasspath/a:/usr/lib64/libreoffice/program/classes/* lein run -- still no luck 😞

kepinpin11:03:28

anyway, what I wanted to do is to include another dir into my clojure app's classpath. What's the best way to do this anyway?

jaymartin12:03:36

Our open source learning group is hosting the free online webinar Essential Klipse this Saturday at 7 pm UTC. Everyone is welcome! http://discuss.thevalueoflearning.org/t/webinar-discussion-2-essential-klipse/39?u=jay

rauh12:03:40

@kepinpin Just add that dir to :src

kepinpin12:03:46

:src ["/usr/lib64/libreoffice/program/classes/*"] like that?

rauh12:03:03

No, without the star

kepinpin12:03:39

I added into the project.clj :src ["/usr/lib64/libreoffice/program/classes/"] but still can't access the classes in the jars

danielgrosse13:03:04

Can I write a commandline programm with clojure? I found the cli.tools but didn't find a info, how to run such a programm on the command line

pesterhazy14:03:30

the most basic thing you can do it to just call the clojure jar directly: https://clojure.org/guides/getting_started

pesterhazy14:03:12

another option is to use boot (which has great support for command line argument parsing), or lein run: https://github.com/clojure-cookbook/clojure-cookbook/blob/master/03_general-computing/3-06_running-programs-from-the-command-line.asciidoc

gcornut14:03:01

@danielgrosse for a shorter script startup time, you could use Clojurescript with planck (https://github.com/mfikes/planck) or lumo (https://github.com/anmonteiro/lumo). But it's Clojurescript so you can't always use the same dependencies (tools.cli should work). Here is a guide for planck scripting: http://planck-repl.org/scripts.html Lumo is very similar to planck but has node.js integration and is more cross-platform

slipset14:03:50

and planck has its own channel #planck, where @mfikes normally hangs around ready to help

danielgrosse15:03:06

Thank you both. I wrote the whole in Clojure, so change to CLJS isn't neccessary.

danielgrosse15:03:41

One question out of curiosity. How could I reduce the size of the final jar file?

pesterhazy15:03:51

@cgrand saw your gist on an edn-based a repl. I think that's an excellent idea

danielgrosse15:03:45

Okay I removed some unused dependencies and it shrunk from 90 to 2MB :thumbsup:

pesterhazy15:03:03

I was thinking about this topic before. My sense is that the fact that nREPL is (too?) complex has held back progress. In combination with socket server a solution like the one you propose could be very helpful

pesterhazy15:03:23

to build simple tooling that can be consumed from emacs etc.

pesterhazy15:03:50

Not just for clojure but for clojurescript also

cgrand15:03:08

@pesterhazy I agree but I have to run, let’s talk later

pesterhazy15:03:32

ping me whenever

tbaldridge16:03:09

@pesterhazy I agree...there's a lot that could be done with socketrepl, even "EDN Repls" are simply a socket repl + some setup inside the connected JVM instance

tbaldridge16:03:59

I'd love to see a "nrepl" that doesn't polute the remote end with extra libraries. Just the JVM + Clojure + a TCP socket, everything else can be setup from a remote process via sending code through the socket.

Lambda/Sierra16:03:05

I've been using socket REPL with inf-clojure-mode lately. Works quite well: Emacs comint mode can connect directly to a socket, no "client" process needed.

tbaldridge16:03:31

Right and if your editor did need to get more information about the process (a docstring for example) it could easily create another socket repl connection, a "scratch" namespace and run whatever code it needs to get at that data.

leov17:03:06

hi. I remember there was a library for clojure that allows to build reagent-like reactive data chains of atoms with just clojure. I can't find it in google for some reason. anyone remembers its name?

leov17:03:49

maybe I'm wrong, but it wasn't for the front-end

triss17:03:15

In fact more specifacally Javelin? https://github.com/hoplon/javelin

nathanmarz17:03:07

Released Specter 1.0 and wrote a post about why I consider it Clojure's missing piece http://nathanmarz.com/blog/clojures-missing-piece.html

bja17:03:16

am I understanding it correctly that if I want to use derive/isa? on a custom hierarchy, I have to reassign the results of derive myself?

bja17:03:48

i.e. (alter-var-root #'my-hierarchy #(derive % :foo ::metasyntactic))

rauh18:03:05

@bja Yes, but why not use an atom?

timgilbert18:03:39

I'm used to using (map-indexed) to keep an iteration index when I'm looping over stuff with (for):

(let [stuff [:a :b :c]]
  (for [[idx thing] (map-indexed vector stuff)] {thing idx}))
=> ({:a 0} {:b 1} {:c 2})
Does anyone have a good trick for doing this in a nested loop?
(let [stuff {:a #{:x :y} :b #{:y :z}}]
  (for [[outer-idx [k v]] (map-indexed vector stuff)]
    (for [[inner-idx leaf] (map-indexed vector v)]
      [outer-idx inner-idx k leaf])))
=> (([0 0 :a :y] [0 1 :a :x]) ([1 0 :b :y] [1 1 :b :z]))

timgilbert18:03:13

...I can do this with loop/recur or a reduce with an accumulator, just think I'm missing a more obvious way to do it

timgilbert18:03:56

What I'd like to wind up with is more like ([0 :a :y] [1 :a :x] [2 :b :y] [3 :b :z])

timgilbert18:03:27

(I can deal with the list-nesting stuff, I'm more interested in the indices)

bja18:03:07

@rauh doesn't defmulti require a var?

bja18:03:27

@rauh nvm just reread the docs. apparently defmulti will take any reference type

timgilbert18:03:45

FWIW, I solved my problem by having the nested loop produce [k leaf] paris and then (map-indexed)ing over that separately:

(let [stuff {:a #{:x :y} :b #{:y :z}}
      pairs (apply concat
                   (for [[k v] stuff]
                     (for [leaf v]
                       [k leaf])))]
  (for [[idx [k leaf]] (map-indexed vector pairs)]
    [idx k leaf]))
;;=> ([0 :a :y] [1 :a :x] [2 :b :y] [3 :b :z])

timgilbert18:03:51

Not super-enthused about the extra iteration, but the code itself is readable

pesterhazy18:03:56

@nathanmarz congratulations for specter's 1.0 release

spei18:03:25

@timgluz you could try

(map-indexed #(vec (cons %1 %2)) pairs)
instead of the last for loop. dunno if thats better though

hiredman18:03:52

concat + for + for = for

hiredman19:03:26

(apply concat (for [i ...] (for [ii i] ...))) = (for [i ... ii i] ...)

timgilbert19:03:25

Oh, hmm, yeah, I'd forgotten about the multiple-seq version of for

timgilbert19:03:55

Well, that does make it a god deal tidier:

(let [stuff {:a #{:x :y} :b #{:y :z}}
      pairs (for [[k v] stuff
                  leaf  v]
              [k leaf])]
  (for [[idx [k leaf]] (map-indexed vector pairs)]
    [idx k leaf]))
;;=> ([0 :a :y] [1 :a :x] [2 :b :y] [3 :b :z])

hiredman19:03:32

(transduce
 (comp
  (fn [f]
    (fn
      ([accum] accum)
      ([accum [k v]]
         (reduce
          ((map #(list k %)) f)
          accum
          v))))
  (map-indexed (fn [i thing] (vec (cons i thing)))))
 conj
 []
 {:a #{:x :y}
  :b #{:y :z}})

timgilbert19:03:42

Or with @spei's suggestion

(let [stuff {:a #{:x :y} :b #{:y :z}}]
  (->> (for [[k v] stuff
                  leaf  v]
              [k leaf])
       (map-indexed #(vec (cons %1 %2)))))
;;=> ([0 :a :y] [1 :a :x] [2 :b :y] [3 :b :z])

hiredman19:03:49

(transduce
 (comp
  (map (fn [[k v]] (into [] (map #(list k %)) v)))
  cat
  (map-indexed (fn [i thing] (vec (cons i thing)))))
 conj
 []
 {:a #{:x :y}
  :b #{:y :z}})

hiredman19:03:02

(transduce
 (comp
  (map (fn [[k v]] (eduction (map #(list k %)) v)))
  cat
  (map-indexed (fn [i thing] (vec (cons i thing)))))
 conj
 []
 {:a #{:x :y}
  :b #{:y :z}})

cristobal.garcia20:03:58

Hi I am thinking of using mount as an indirection layer to an http client. Something like

(defstate get :start http/get)
With the purpose of being able to “mock" it while avoid using with-redefs - which I don’t like too much. I do not know if this is a good idea of it is me missing something fundamental. Any thoughts about it? Thanks in advance

hiredman20:03:04

mount is the worst thing for modularity, it keeps everything in a global atom

hiredman20:03:06

I am forever shocked that anyone thinks it is a good idea to require you to do that

cristobal.garcia20:03:30

uhm could you elaborate on that, please?

hiredman20:03:11

there, thoughts 🙂

hiredman20:03:31

mount literally keeps the state of everything in a global atom

timgilbert20:03:08

There's a #mount channel you could ask about that in. Personally I like mount, but I'm not sure if makes sense for things that are essentially stateless like http/get

hiredman20:03:09

actually multiple global atoms

hiredman20:03:07

I bet there are race conditions in there somewhere

cristobal.garcia20:03:17

Thanks @timgilbert . The point is about to use start-with-states to replace the implementations

hiredman20:03:10

I like component, which is an opinion, "component is good"; mount being terrible is a fact

cristobal.garcia20:03:37

My english is far from being perfect. Probably I am not clear about the meaning of fact and opinion

tolitius20:03:07

@cristobal.garcia you could use just start-with to provide a value vs. a state:

(mount/start-with {#'app/foo (http/get ...)})
more about it: https://www.dotkam.com/2016/01/17/swapping-alternate-implementations-with-mount/

hiredman20:03:30

mount turns your application in to a mutable global singleton

cristobal.garcia20:03:22

@tolitius Thanks. That was exactly the plan. But not for alternate viable implementations, just for mocking

tolitius20:03:01

@cristobal.garcia right start-with is usually used for stubbing / mocking in tests

cristobal.garcia20:03:09

@hiredman. I am not exactly sure I agree with you. mount turns some state into someting I don’t care too much if if works as states

tolitius20:03:30

start-with-states is a convenience (another option)

hiredman20:03:24

clojure defs are global singletons, atoms are mutable, mount stores state in global atoms, mount turns your system in to a mutable singleton

cristobal.garcia20:03:33

That is brilliant @tolitius . My mind is at peace now knowing the idea I had in mind make sense. I will have a look at start-with

cristobal.garcia20:03:06

@hiredman The server the code runs on is a global singleton as well and I am not going to be able to live without it.

istvan20:03:52

have you noticed the new design of github? the new blue is burning my eyes, is it only me?

bostonaholic20:03:44

istvan: the blues are bluer, greens are greener, and the purples are purplyier

istvan20:03:24

I am not sure if this is what I want for Gihub though 🙂

dpsutton20:03:20

the top navbar? i assumed it was black

hiredman20:03:28

well, you will have to live with it. I worked on a clojure project that had a runtime system similar to mount that kept everything in global atoms for five years, and it is not the way to structure software

cristobal.garcia20:03:22

@hiredman Thanks for your opinions, they are very much appreciated. I will consider them carefully.

cristobal.garcia20:03:31

@tolitius Thanks again! I am taking my hat off 🙇

tbaldridge20:03:35

@cristobal.garcia from my side of things I don't care if people use one library or another. It's just global mutable state is bad...really, really bad. That's what this whole Functional Programming thing is about. And yet for some reason it's now considered a good idea to go and structure our entire apps around global mutable state. There's no reason for it at all. Functions have parameters, pass in everything the function needs via a parameter. That keeps your code thread-safe (one function doesn't muck with the global state of another function), clean (I always know what state a function needs to run), and extensible (I can pass new impls to a old function). This is basic FP stuff...I'm not sure why it's suddenly hip to have global mutable state.

tbaldridge20:03:56

I find the whole thing rather confusing. People can disagree, but if you want global state...why are you using Clojure?

hiredman20:03:32

that is my thing, component is not built around global state

cristobal.garcia20:03:33

@tbaldridge I am a little bit surprised. Do I need to pass every function another function uses as a parameter?

tbaldridge20:03:58

you don't (or shouldn't) mutate global functions while your app is running

tbaldridge20:03:29

at least not in production. If you're mutating vars at runtime that's a big red flag. You should be able to "freeze" every var in your app at compile time and things should "just work"

dominicm20:03:30

@tbaldridge I believe in previous discussions, mount users have said they do this. (Passing round db as an argument)

istvan20:03:39

@tbaldridge i guess the doom of javascript devs reached clojure, time to evacuate! 🙂

cristobal.garcia20:03:22

I am not planning to. But I do need to unit-test my code. Is there any way I can replace a dependency in a test without adding it as a parameter to the function-under-test?

tbaldridge20:03:26

@dominicm that may be the case, but the framework doesn't work that way, go read the source, everytime you start the system it goes and throws a bunch of state in a global atom. Every "defstate" just does a get-in in that atom

dominicm20:03:27

@tbaldridge ah, I thought it as the api you disliked, vs the impl

hiredman20:03:36

because component is using values and is not global, it is entirely possible to do things like spin up multiple copies of a system in the same jvm (baring other constraints) and doing things like running tests in parallel, or testing communication between multiple systems

tbaldridge20:03:58

@cristobal.garcia yes! thanks for asking! Two good ways is to a) add the parameter...there's nothing wrong with that. b) test the output of your function. Don't have (get-user ..) make an HTTP call and try to test that, have (make-get-user-request ...) and test the output of that function

dominicm20:03:10

@hiredman obligatory: you can do that in mount

tbaldridge20:03:29

@hiredman agreed, I've tested entire distributed systems where we replaced Tibco with Hornet, Datomic with a atom, etc.

tbaldridge20:03:39

@dominicm you really cant....

tbaldridge20:03:11

@dominicm at least not with an explosion of namespaces for each new DB connection your app needs, mount doesn't compose the way other DI systems do.

cristobal.garcia20:03:14

@tbaldridge a) agreed for some cases. Wide signatures go against code being understandable and this is paramount. b) I am not sure I am getting you

dominicm20:03:19

It's perhaps worth noting that mount doesn't claim to be a DI framework afaik. DI is for users to use.

hiredman21:03:05

whatever mount claims to be, it is a pile of uncoordinated (multiple atoms) global state inside

hiredman21:03:40

these 30 lines are enough https://gist.github.com/hiredman/075b45eaeb01e4b526ce6f8854685487 you can build great systems with great properties and the ability to rewrite and swap out parts at will for testing or whatever else you need to do

tbaldridge21:03:42

@cristobal.garcia that's the power of stuff like Component, you add one argument, and all your deps are in that

hiredman21:03:20

if you want all that and slightly better error messages if things go wrong, use component

tbaldridge21:03:07

@cristobal.garcia so your functions look like this:

(defn get-user [{:keys [db] :as di-state} user-id]
   ...)

dominicm21:03:35

https://www.dotkam.com/2016/01/31/yurt-mounts-local-real-estate/ yurt is the way to do it. I had thought that it let you do binding style stuff to mock things, but apparently not.

mobileink21:03:18

dominicm: i'll give yurt credit for not picking a generic name like "component" or "system". do we call our dog "dog"?

tbaldridge21:03:43

@cristobal.garcia in this case though, what are you trying to test?

cristobal.garcia21:03:18

@tbaldridge functions that get some data from a REST-like interface

dominicm21:03:05

@tbaldridge I've always found that vars like di-state get abused and quickly become incomprehensible as to their actual contained state.

cristobal.garcia21:03:50

I would rather prefer not to use a mock/stub http server

hiredman21:03:23

to be clear, component doesn't pass around a single di-state, what you get for di-state is only the stuff you have told component you depend on

tbaldridge21:03:19

@cristobal.garcia so in that case . There isn't much of a reason to test the HTTP lib, right? Chances are someone else wrote that, what you really want to be testing is that given certain parameters, the correct HTTP request is generated

tbaldridge21:03:42

So make a function that generates HTTP requests (HTTP requests are maps after all), and test the output of that function.

tbaldridge21:03:35

Combine that with something like Component for integration tests, and you've got a nice system setup.

cristobal.garcia21:03:38

@tbaldridge please correct me if I am wrong but HTTP requests will be whatever the library I need to use asks me for. Maps or maybe something else.

cristobal.garcia21:03:32

If I need to write a layer to transform maps into clj-http calls, how do I test that layer?

tbaldridge21:03:08

That you'd hit in integration tests. At least that's how I write my code. Business logic can be exercised with unit tests. Side effecting code should be parameterized by components I can swap out with other components.

hiredman21:03:14

so you could just write a map -> map function and then pass that map to request*

cristobal.garcia21:03:32

@tbaldridge agreed about unit-testing business logic. I need to think about your approach for the side-affecting code. Thanks for your time

tbaldridge21:03:51

np, stick around, I'm sure we'll all argue this again next week 🙂

jstokes21:03:52

maybe at this point we could have a #mount-vs-component-vs-integrant-vs-...

tbaldridge21:03:19

I'd like to find an excuse to use Integrant soon.

cristobal.garcia21:03:02

@tbaldridge may I ask you a final question?

cristobal.garcia21:03:40

thanks! Let’s imagine I have decomposed my business logic and everything lives in pure functions. Now I need a final layer of the cake. A very simple function which takes a map and makes a POST to a web server. Everything else is pure. How do suggest I do test this one?

hiredman21:03:39

the 30 line gist above can just be pasted in to your app, and you get all the benefits of component without having the worry about the name or include any library

hiredman21:03:14

@cristobal.garcia I have tested things like by starting up a jetty server(in process) and making requests to it

hiredman21:03:16

the ring jetty adapter has a handy run-jetty function

cristobal.garcia21:03:33

Start a web server? I would have expected something lighter

hiredman21:03:33

if I recall it returns some kind of object you can call stop on to stop the server

hiredman21:03:53

if you really want to test the request io

cristobal.garcia21:03:26

Or I may want to test I do the right call and correctly process the returned results

hiredman21:03:53

there are libraries that do things like record http requests and response, and then you can play those back

dominicm21:03:58

Processing the results could be it's own function too

hiredman21:03:23

I am not a huge fan of that, but it exists and people do it, presumably because they are worried about the overhead of firing up a webserver

cristobal.garcia21:03:28

@dominic you are right but I am interested on the impure code

hiredman21:03:54

the way to test the io of a http client is with an http server

cristobal.garcia21:03:19

@hiredman well yes but I could approach the problem having more unit tests and less integration tests

sveri21:03:27

@cristobal.garcia At work we have system / integration tests that take like 2 - 3 hours to setup before the tests start at all. So, from my point of view, starting a web server for integration tests is nothing I would be afraid of 😄

hiredman21:03:50

jetty is really easy to start, it doesn't take that much to run

hiredman21:03:57

it runs in process

hiredman21:03:40

I might prefer to re-use a jetty instance of a few tests, instead of a new one per test, and there are all kinds of ways of doing that depending on your testing library

cristobal.garcia21:03:45

@sveri agreed but it is not about this. I have needed to try an snmp client. Should I start an snmp server too? Well good for integration tests but I want to have more (and fast) unit tests

larhat21:03:11

@cristobal.garcia we use component to manage deps, and we have http-client component (initialised with endpoint and other stuff). to test interaction with other services we use smth like https://gist.github.com/little-arhat/c4da3415b88a0ddf8214f09dc44fff9a — mocked client essentially

hiredman21:03:25

if what you want to test is the io between a client and a server, then yeah, you need a client and a server

bradford21:03:44

Hey fam, java-ish question. Does future.get() not always block? What if I have a Thread.sleep() within the .call() method? I'm having weird concurrency issues with a program that uses 4 Future.get()s in a row (for timeout purposes), they don't seem to always execute sequentially.

hiredman21:03:06

.get doesn't cause a future to start

hiredman21:03:30

Future is an interface, and it will depend on the implementation, but clojure futures start as soon as they are created

cristobal.garcia21:03:33

@larhat thanks. That is interesting

larhat21:03:19

@cristobal.garcia so, for the test, we can change dependency of our final system (real client to mocked one) and test system’s lifecycle, without hitting real world

cristobal.garcia21:03:28

@hiredman Yes, on an end-to-end test I want. Do I want to test everything on end-to-end tests? Absolutely not

hiredman21:03:44

so what do you want to test?

hiredman21:03:13

are you just trying to check that clj-http is called with the arguments you pass it?

cristobal.garcia21:03:24

@hiredman I want to test I call clj-http with the right arguments

cristobal.garcia21:03:49

That is why I understand a unit test is

hiredman21:03:15

I don't think I would bother, there are things you could do (using with-redefs, which is usually a bad idea, but can't always be avoided) , but if you have your map -> map function, and clj-http is only ever called on that map

cristobal.garcia21:03:31

@larhat probably you aren’t testing the replaceable implementations since they have the same problem

hiredman21:03:28

for example, if your whole system took as a parameter a function like (fn [m] ...) and used that passed in function to make http requests, in your test to ensure that function is called you could swap it out with any function, something that recorded the arguments passed

hiredman21:03:24

and everywhere else you migh just pass the plain clj-http.client/request* function to your system

hiredman21:03:42

which is the more structured approach to the with-var-root thing

cristobal.garcia21:03:05

I see. I think I now have understood. I am a little disappointed, though

hiredman21:03:41

there is no magic

bradford21:03:45

@hiredman My mistake, I meant executorservice.submit(Future) and future.get()

cristobal.garcia21:03:46

I do like to use test-first approaches. Finding places where this is more difficult to approach than I expected (traditional stubs) is something I still need to process

cristobal.garcia21:03:45

I do not need magic. A simple mocking solution would work for me. There are places where purity is not possible and, for then, I do not see why I need to rely on doing everything with costly integration tests

cristobal.garcia21:03:24

but other than this, I do love clojure

sveri21:03:06

In the system you can write your outside reaching components the way you want. Mix and match whatever you need. I dont really understand the problem, tbh.

sveri21:03:26

But then, it took me months to finally grasp it all 😄

hiredman21:03:46

bradford: get is blocking, but the order of the gets doesn't effect the order of execution, it is going to depend on the executor. if the execute has more than one thread you could get some interesting race conditions of any logging

hiredman21:03:08

(not sure how you are determining what order they run in)

cristobal.garcia21:03:29

@sveri, Yes I am probably needing some months as well 🙂

sveri21:03:40

@cristobal.garcia Yea, coming from a state dominated java world, in my case, I had to rewire my brain several times, but, it was totally worth it.

bradford21:03:51

Yeah. (this is a webcrawler with Selenium, so I have lots of timeouts because Web browsers are freezy and crashy. I've got an Executors.fixedThreadPool of size 40, and then Futures that DownloadURL, TakeScreenshot, ParseResults, and UploadResultsToS3, each with a timeout. What I'm seeing is that sometimes, it'll try to ParseResults when TakeScreenshot isn't done, even if TakeScreenshot times out. It's...odd. I'll turn it down to 1 thread and see if life gets more sane.

bradford21:03:03

I must have an incorrect assumption in my mental model

hiredman21:03:14

if you through all those futures on the workqueue at the same time, some of thsoe threads will be pinned for a long time doing long running tasks

hiredman21:03:26

while other threads burn through the short running tasks

andrea.crotti21:03:42

to document APIs what do Clojure people prefer? Swagger/RAML/other?

andrea.crotti21:03:00

maybe spec will be used for that as well?

andrea.crotti21:03:10

or could be used

bradford21:03:21

@hiredman Ohhhh. Got it. Thanks!