Fork me on GitHub
#clojure
<
2019-10-20
>
kulminaator06:10:17

if your DI is designed with testing in mind, it makes testing a real breeze

kulminaator06:10:25

i havent designed clojure apps big enough for DI usage though. our company is still a java shop. and the DI is just there to mostly standardize how stuff works on 60+ applications on 200+ production server nodes. all are built the same way, all are deployed the same way.

kulminaator06:10:45

horribly boring (they don't really have a personality in that sense) but efficient

kulminaator06:10:34

would be horrible context switching otherwise for developers if they have to work on several different applications per day

kulminaator06:10:19

for small applications i wouldn't do any of that dependency injection though 🙂 for tiny hobby stuff the service provider model works just as well.

dominicm08:10:35

Do you mean service locator? (Are they the same?)

dominicm08:10:28

How do they make testing simpler?

jsyrjala09:10:06

I think service locator pattern would look like more or less like this. Then you could have e.g mock versions of services in service-locator during the unit testing etc.

👍 4
dominicm09:10:35

But is that the same as a service provider? (Google was kinda unclear to me)

kulminaator09:10:12

yes it's the thing i meant

kulminaator09:10:23

where i stand on the topic - when i buy a new car then the DI assures that the car has fitting wheels when i get it. whereas a pretty common approach with the service locator is that i get into a new car, want to start driving, roll down the window and scream out that i need wheels, now. and whoever is the mechanic nearby runs out with any pair of wheels they have since they couldn't understand who is asking for them.

kulminaator09:10:32

not all of them have this pattern of course, but it is common.

sogaiu09:10:22

what a memorable analogy

kulminaator09:10:14

it gets more tense if you are responsible for the db connector of your application and your teammates request it from service locator before application has loaded it's config or after you have closed down your connection pool 😉

kulminaator09:10:37

overall DI and service locators both help you to sneak in mocks into your tests (for the external resources that you can't possibly pull up even with the help of docker containers).

Arto Kalishian11:10:09

What is the most reliable database engine document based that officially supports clojure integration? MongoDB doesn't guarantee write reliability as far as online reviews claim.

scknkkrer11:10:43

@arto.eg, you can change your operations mode with more reliable mode. AFAIK, this will do the job.

👍 4
Arto Kalishian04:10:00

Good morning, I was searching online about MongoDB reliable mode, but I could not find it. Is there a more accurate term to the feature or it's just some best practice? If so, please share the references. @U3JJH3URY

jumpnbrownweasel03:10:32

@arto.eg I don't use Mongodb but I work on databases and I think you're looking for this: https://docs.mongodb.com/manual/reference/write-concern/ If you set the value 2 then 2 out of 3 nodes will have the data, which is considered reliable.

❤️ 4
Arto Kalishian05:10:27

Thanks a lot for sharing @UBRMX7MT7

Arto Kalishian05:10:33

I bookmarked it.

octahedrion12:10:54

if I have a namespace aa which requires namespace bb :as b, is there a way to make it so that when namespace aa is loaded, its functions resolve the alias b to a namespace other than bb ?

octahedrion12:10:29

or, even better, is there a way to require namepace aa in some other namespace in such a way that aa's b resolves to a namespace other than bb

octahedrion12:10:41

like (require '[aa :as a :resolving {aa/b cc}])

octahedrion12:10:51

or another way of saying it would be (require '[aa :as a :resolving {a/b cc}])

octahedrion12:10:17

so that a's alias b resolves to cc not bb as required in aa, i.e. whereas before b/g in aa would resolve to bb/g, instead it would resolve to cc/g

abdullahibra13:10:21

can i define specs at run time ?

emccue13:10:41

@abdullahibra Yep, you might have to get creative with how you evaluate things though

abdullahibra13:10:17

@emccue can you give example please?

emccue13:10:04

well, assuming you are defining a spec the "easy way"

emccue13:10:24

with (s/def :some-ns/my-spec predicate-fn)

emccue13:10:49

(defn define-name-spec [name]
  (s/def (keyword "name-checker" name) #(= name %)))

emccue13:10:17

that being said - this isnt great practice

abdullahibra13:10:53

the good practice should be defining spec outside function and use them as global vars inside the funcs?

emccue13:10:13

honestly if you are making a predicate, just make a predicate

emccue13:10:32

there isnt all that much reason to tie it into the spec mess

abdullahibra13:10:57

suppose i have application which will give the user space to define their specs to be used within validating their data, what do you think about this?

emccue13:10:40

I think that you should rely on a standardized way of defining a data schema rather than use spec for that

emccue13:10:51

spec is for validating flow through your program

abdullahibra13:10:16

so in my situation will be better to use formal clojure for that ?

emccue13:10:38

well, it depends on what you want to provide to your users

emccue13:10:58

is this a spark kinda situation?

abdullahibra13:10:17

for now No, but maybe later will be streaming service

emccue13:10:18

or an ETL pipeline?

emccue13:10:28

streaming data?

emccue13:10:13

maybe there is a better argument out there - but I personally think that using a schema language that isnt specific to your application is alot better than making one up yourself

emccue13:10:28

in the realm of user facing systems, that is

emccue13:10:58

i know nifi uses avro, which was eh to work with

emccue13:10:43

though that is unrelated to the technical feasibility of spec

abdullahibra13:10:28

that's good to know 🙂

jjttjj14:10:45

If I have an api that exposes a multimethod which somewhat encourages it's methods be overridden as a means of extension/customization, is that a legitimate/good use of multimethods? or getting some degree of code-smelly?

octahedrion14:10:50

that's one use of multimethods

octahedrion14:10:31

if I understand you...expose a defmulti intended to be implemented by defmethods

octahedrion14:10:29

why are you afraid it might be a code-smell ?

jjttjj14:10:57

i think my main concern is that during playing with this I've had a few mishaps involving the ordering of requires becoming important, or otherwise getting into an unclear state of which method implementations I was using at a repl (after some time messing around at a repl)

dominicm15:10:22

I wouldn't be keen on that personally, I wouldn't trust things to work

octahedrion15:10:25

that sounds like a problem with your REPL workflow rather than multimethods

rascio15:10:16

Hi! I'm experiencing a weird error with specs generate and lein repl (clojure 1.10), it seems it doesn't find a file when I invoke the function:

lein repl       
nREPL server started on port 53282 on host 127.0.0.1 - 
REPL-y 0.3.7, nREPL 0.2.13
Clojure 1.10.0
OpenJDK 64-Bit Server VM 11+28
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

user=> (clojure.spec.gen.alpha/generate 1)

Execution error (FileNotFoundException) at user/eval4978 (form-init10909052932822487799.clj:1).
Could not locate clojure/test/check/generators__init.class, clojure/test/check/generators.clj or clojure/test/check/generators.cljc on classpath.
Does anyone have any hint on why is this happening?

andy.fingerhut15:10:08

@manuelrascioni my first guess would be that you are missing a dependency in your Leiningen project.clj file, needed for that namespace to exist.

rascio15:10:15

generator is part of the spec, it should be included with clojure core 1.10 😕

dpsutton15:10:43

https://clojure.org/guides/spec#_project_setup > spec generators rely on the Clojure property testing library test.check.

rascio15:10:48

ah so the lib is mandatory if I want to use the functions included in the main clojure dependency

dpsutton16:10:39

that's a bit broad. its needed if you want to generate data with spec

rascio07:10:14

yep, I said it wrong. But it seems very weird that you have to imort a lib to use a function included in the core 😕

dpsutton15:10:01

{:dependencies [[org.clojure/test.check "0.9.0"]]}

andy.fingerhut16:10:52

I am pretty sure that test.check is not needed for all possible uses of Clojure spec -- I believe it is primarily for the uses that involve generating random data.

borkdude16:10:13

that's right, same in clojurescript where it's also an optional dep

emccue17:10:29

@jjttjj I personally like apis like that so long as you provide every impl that your library provides through a single namespace

emccue17:10:51

clojure.java.data is a good example

emccue17:10:15

though more info about what you are doing is always helpful in barfing up opinions

jjttjj17:10:11

Thanks! It's for my library https://github.com/jjttjj/iboga which is an api client which wraps a stock broker's java api. Basically I turn a big data structure which represents a request into the java classes needed. And then do a similar thing to turn the java response into a data structure. at some point I tag everything in this data structure with a unique qualified keyword. Then the key/value pair is translated to or from the value the java api expects via a to-ib/`from-ib` multimethod which just dispatches on the qualified keyword. For example the java api returns dates as strings. My default implementation turns these strings into LocalDates. But I want to be able to allow users to use another date representation if they wish. Previously I rolled my own multimethod approach by just putting functions in a map. But I'm starting to get the sense that it would be better to stick with multimethods because they're "standard clojure". Here are the two approaches I'm considering: https://gist.github.com/jjttjj/a431675c7e9338578273c777299a3052#file-convert1-clj-L45 https://gist.github.com/jjttjj/d095b3a2bea6cbda6adad1d1e206810c#file-convert2-clj-L150

jjttjj17:10:13

Oh wow, clojure.java.data is surprisingly relevant here

emccue17:10:39

yeah - you might want to just extend that lib

emccue17:10:08

like, include from-java and to-java then customize them however you need to

emccue17:10:02

alot less stuff to roll yourself, and your impl for conversion is totally open

emccue17:10:07

so if you don't keep up to date and they add a new field or something, someone using your library can replace relevant from/to pairs to keep their code working in the interim

seancorfield17:10:14

And clojure.java.data is actively maintained now (by me) so if you have questions or need enhancements, just reach out!

jjttjj17:10:42

Yeah interesting stuff, thanks! I wish I heard of this sooner 🙂 Sill have to explore clojure.java.data a bit

jjttjj17:10:05

One distinction with my library is it also represents method invocations on a single api client class as data that looks and feels the same as the "beanlike" classes

jjttjj17:10:59

so like

(ib/req client [:historical-data {:contract {:sec-type "STK"}]
would be translated to something sort of like
client.reqHistoricalData(contract)
where Contract is its own class with a "secType" getter/setter

jjttjj17:10:30

[But it might be good to separate the stuff that could be handled by clojure.java.data and this more magical stuff]

pbaille17:10:45

Hello, I’m using clojure.java.shell to launch a shell program that does not terminate, I would like to forward its output to the repl printer. Any ideas on how to do that? thank you

vlaaad17:10:09

don't use clojure.java.shell 🙂

vlaaad17:10:26

instead just start process and redirect it's input stream to repl

vlaaad17:10:52

redirect like that:

(future
  (with-open [reader (io/reader input-stream)]
    (doseq [line (line-seq reader)]
      (println line))))

vlaaad17:10:21

start process as in clojure.java.shell, but without (.waitFor proc), which blocks until process exits

hiredman18:10:51

Use processbuilder call inheritio

manutter5118:10:48

Hmm, this is unexpected.

(require '[java-time :as jt])
(require '[java-time.format :as jf])
(def ymd-format (jf/formatter "YYYY-MM-dd"))
=> #'user/ymd-format
(jf/format ymd-format (jt/local-date "2019-12-29"))
=> "2020-12-29"

manutter5118:10:35

Am I doing something wrong?

seancorfield18:10:49

@manutter51 Looks like it needs to be yyyy in the format, not YYYY.

manutter5118:10:36

Ah, ok thanks much Sean!

lilactown18:10:47

is there a way to test macros that use &env using macroexpand?

didibus20:10:50

What's the default value of assert

andy.fingerhut20:10:49

nil . The implementation of assert in Clojure/JVM is based on when, which returns nil when its condition is logical false, and when-not, which returns nil when its condition is logical true.

andy.fingerhut20:10:32

That is not promised in the doc strings, and I think the typical use of assert is for its side effect, and ignore its return value. Why would you want to rely on its return value?

didibus20:10:40

Sorry, it was a slack mistyped, I typed *assert*

didibus20:10:01

It just slack bolded it

didibus20:10:47

I can't seem to find if *assert* defaults to true or false

didibus20:10:47

It seems it defaults to true, but I'm having a hard time knowin if that's only true from a lein bootstrapped repl, etc.

andy.fingerhut20:10:58

Probably difficult to find because it is implemented in Java, here: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L200 . Looks like true (`T`)

didibus20:10:17

Oh, I was looking at that line, and missed the T

andy.fingerhut20:10:31

Leiningen could do who-knows-what with that in its own code when you run lein test.

didibus20:10:34

Wow, is that... hum interesting the use of T and not true in the source

didibus20:10:47

Alright thanks. I had looked at that line, but I think the T meant I overlooked that it was being set to somethin

andy.fingerhut20:10:06

Sure. Single letter symbols can be invisible that way sometimes.

andy.fingerhut20:10:56

I don't know full reason for use of T there, but it is a Java Object, rather than a primitive, which might be part of the reason.

didibus20:10:00

Ya, and Clojure's Java style is a bit esoteric, so I'm always extra confused 😛

didibus20:10:36

Ya, it just seems someone didn't want to type Boolean.TRUE over and over

didibus20:10:41

All these asserts defaults are a bit confusing, sine the spec assert defaults to false, but oh well

Alex Miller (Clojure team)20:10:41

I think it actually used to be a symbol originally like scheme, etc

didibus20:10:55

Oh, that would make sense

didibus20:10:41

Hum... no wait.. > If compile-asserts is false at compile time, compiles to x. Defaults to value of 'clojure.spec.compile-asserts' system property, or true if not set. > If (check-asserts?) is false at runtime, always returns x. Defaults to value of 'clojure.spec.check-asserts' system property, or false if not set. You can toggle check-asserts? with (check-asserts bool).

didibus20:10:09

So compile-asserts default to true, but check-asserts? defaults to false?

didibus20:10:28

So effectively, spec assert is disabled by default. Do I get that right ?

andy.fingerhut21:10:13

I believe that *compile-asserts* and *assert* are independent in Clojure, i.e. I don't think the value of one directly affects the other, but perhaps you were not expecting them to.

didibus21:10:58

Ya, I don't expect them too, and they don't. though, I also feel like logically the could have. I'm more confused why the runtime check of spec defaults to false, but the compile time one defaults to true. Seems you'd set them both to default to the same