Fork me on GitHub
#clojure
<
2019-02-05
>
caleb.macdonaldblack02:02:06

What strategies, if any, do people use to decouple sub systems within an application. For example decoupling a database access layer. I've been using protocols to group common functions and passing the instances down into subsystems using stuartsierra/component. I can also see people using weavejester/integrant and mapping single functions. I can also see directly coupling/referencing subsystems and segregating them in separate namespaces.

vemv04:02:59

Protocols are a must for (clean) testability IMO. Also nice being able to change libraries in a future (e.g. Bidi -> ataraxy) At work we use separate directories for protocols and impls. At first I agreed but I came to realise this creates an awkward indirection. 90% of times there's just 1 relevant implementation for a protocol. So one's IDE's jump-to-def will take you to the protocol ns, not the impl ns. That's the awkward point, and a good reason to place protocols close to impls bad:

protocols/
 foo.clj
 ...
impls/
 foo.clj
  ...
better:
components/
  foo/
    protocol.clj
    impl.clj
  bar/
  baz/
  ...
This becomes evident as the app size scales I wouln't create proto and impl in the same ns, it forces you to choose different fn names to avoid clashes. Better to have it uniform

vemv04:02:02

As for Component vs Int, Int has "suspend" capabilities which I believe can make the restart process more graceful and/or performant. Haven't tried it though. https://github.com/weavejester/suspendable might work as well for Component I like Component. With https://github.com/stuartsierra/component/pull/62 now it's as lightweight and data-driven as Integrant (or even more so)

vemv04:02:32

Answering to your question... at least 1 protocol (and 1 component) per sub-system. Each subsystem only talks to each other via protos

caleb.macdonaldblack04:02:40

@U45T93RA6 Thanks for your input. It's great to see how other people solve these problems. We are definitely on the same page with this. When using protocols, I've also grouped up the implementation with the protocol in the same directory. I use cursive so when I jump-to-def to the protocol, I can do another jump-to-def on the protocol name which takes me directly to the implementation. So using that it wouldn't matter if they're in the same directory or not. However, I do prefer them in the same directory.

mfikes03:02:09

I have a project where starting a REPL with Java 1.8.0_192 takes 11 seconds and with Java 1.8.0_201 takes 44 seconds. I'm wondering if this is a known issue or something idiosyncratic to my project.

mfikes03:02:22

Looks like the Clojure portion ^ is easy to repro with a fresh React Native project; will check in #cljsrn

gcloj09:02:33

Looking for jdbc that uses threadpool

Adrian11:02:24

Hi all, I'm new to Clojure I'm new to Java. 🙂 Can anyone point me to the right direction? I'm trying to serialize an https://github.com/thi-ng/ndarray

witek13:02:20

How do I apply a function (defn myfn [& {:keys [a b]}] ...) to a map m (`{:a 1 :b 2}`)?

borkdude13:02:31

$ clj
Clojure 1.10.0
user=> (def m {:a 1 :b 2})
#'user/m
user=> (defn myfn [{:keys [a b]}] [a b])
#'user/myfn
user=> (myfn m)
[1 2]

witek13:02:58

Sorry, I meant: (defn myfn [& {:keys [a b]}] ...)

borkdude13:02:42

then you probably need mapply

borkdude13:02:57

it’s a function that’s not in clojure, but in several helper libs:

(defn mapply
  "Applies a function f to the argument list formed by concatenating
  everything but the last element of args with the last element of
  args.  This is useful for applying a function that accepts keyword
  arguments to a map."
  [f & args]
  (apply f (apply concat (butlast args) (last args))))

🙏 5
tim17:02:37

noticed functions like assoc and contains? operate on vectors (by position), but dissoc throws an error. Seems like this should work as a complement to the aforementioned functions - no? Or is this an intentional omission for performance reasons?

dpsutton17:02:36

what would (dissoc [:a :b] 0) mean?

noisesmith17:02:51

removing something from the middle of a vector isn't a simple operation, so it isn't built in

tim17:02:58

remove item at position 0?

noisesmith17:02:08

also if you find yourself wanting to do that, you should probably use a different datatype (eg. finger tree)

dpsutton17:02:10

the result would have an item at position 0

dpsutton17:02:23

(contains? (dissoc [:a :b] 0) 0) would be true

tim17:02:41

good points 🙂

dpsutton17:02:45

along with the non-constant performance of dissoc there

dpsutton17:02:06

i hadn't realized that until you asked it so i like your question 🙂

tim17:02:52

yeah I figured the performance would make it bad, just curious on the reasoning.- thx

joelsanchez17:02:14

you have keep-indexed tho (keep-indexed (fn [k v] (when (not= k 0) v)) [:a :b :c :d])

noisesmith17:02:32

see also the inability to check something sequential for a specific value (what people often naively think contains? would do) - it's possible, but there's no simple built in because doing so often indicates you should be using a different datatype

tim17:02:23

for what it’s worth I was building a custom version of assoc that wouldn’t add nil values in order to reduce gc overhead (relative to pruning). it works as I expected, but in doing so I stumbled upon the issue. edit: note that I’m not even using vectors, but I was attempting to achieve feature parity… so it was really just a question.

johnj17:02:06

@noisesmith wouldn't something like some count as a built in for that?

tim17:02:15

so it’s not a data type issue

dpsutton17:02:03

i think he means without doing a linear scan

noisesmith17:02:41

@lockdown- yes we have functions that do linear scans of collections, but nothing that specifically checks membership of a given value

jdkealy19:02:22

Hi, does anyone have recommendations on how to get the length of a video in clojure... Sadly I must use windows.

jdkealy19:02:19

i was using ffmpeg on a mac, and calling it with processBuilder, however I'm running into issues getting any output at all while using CMD instead of bash

jdkealy19:02:36

I tried loading the file as a media object using ffmpeg, but ffmpeg doesn't support MOV files .

noisesmith19:02:40

@jdkealy you should be able to pipe output between processes via InputStream and OutputStream, if all the executables are present

noisesmith19:02:07

java does have multimedia libraries, that's the next thing I would look for

noisesmith19:02:34

even if there was a clojure binding, using the lib via interop is likely a better choice

jdkealy19:02:49

right! https://gist.github.com/jdkealy/65edec6c28a89f378c27803fb78be6d8 so this calls bash, would you know how to do this in windows ? I know you can call bash via CMD, eg. "CMD" "C/" "bash" but the stream just returns ""

taylor19:02:35

could stuff be going to stderr that's not showing up? I remember from some old C#/.NET work there were some Process options for redirecting stderr to stdout, not sure if that'd be exposed via Java classes though

noisesmith20:02:53

Process allows accessing stderr

noisesmith20:02:03

in ProcessBuilder you have the option to join the out/err into one stream also

👍 5
jdkealy19:02:26

or... if slurp is returning "", is there a silent error somewhere?

bowie 5
dtsiedel20:02:14

I would look for a specific library in Java/Clojure before piping stuff to bash/cmd

isak20:02:38

ffmpeg writes a lot of things to stderr rather than stdout, afaik @jdkealy

👍 5