Fork me on GitHub
#beginners
<
2018-11-19
>
iobuhov09:11:59

Hello, I need some help with code structuring. I'm trying to implement API abstraction for my client app. And my question is: what should I use to generate groups of functions? For now, I consider Protocols and macros. But I'm not confident in that, so your advice is welcome. Above is my current implementation using maps.

joelsanchez09:11:44

you can just create a namespace with those functions and define a function that gives you an api client

joelsanchez09:11:49

(ns client.api.core) (defn api-client [base-url] {:url base-url}) ;; or whatever you want (defn create [client] ...)

joelsanchez09:11:16

which is kind of like defining a protocol and implementing it with a record, only with less clutter

joelsanchez09:11:39

you get a Connection, and then the functions have that arg

iobuhov10:11:47

Thanks, interesting idea. But there one more question: in case of HOF how to return multiple functions?

Alex Miller (Clojure team)14:11:08

a protocol is mostly implemented as a map of functions

iobuhov15:11:01

ok, I'll look at protocols closer

brollypop11:11:27

Hi, I'm using clj-memory-meter lib in my app and it works fine until I deploy my uberjar on openjdk:8-jre-alpine image. I then run into class not found errors for that lib. It appears to require some jdk agent tool. My question: is there an alternative for measuring object size that would work with simple jre image?

schmee12:11:28

have you tried jvisualvm?

jaihindhreddy-duplicate11:11:33

Which library do you guys use to read Excel files? Nothing other than docjure seems to be actively maintained.

bridget16:11:15

I have used docjure with success.

👍 4
dfcarpenter18:11:35

Can anyone point me to a tutorial for setting up a clojure project from scratch using deps.edn? I want to start a basic api project using compojure and use deps.edn. Looking at more advanced setups like juxt/edge is quite overwhelming and i'm looking for something simpler to learn from.

tavistock18:11:32

how far along are you? have you seen this? https://clojure.org/guides/deps_and_cli

noisesmith18:11:41

if you want something simple, what's the motivation specifically for using deps.edn?

dfcarpenter18:11:25

@tapegram I did see that but didn't find it too helpful. Thanks though.

dfcarpenter18:11:36

@hiredman That looks great. Thanks

Mario C.19:11:40

Do println's cause performance issues?

Mario C.19:11:14

or are they negligible? or does it depends on the size of the content that you are printing out?

andy.fingerhut20:11:53

It costs non-0 time to perform one. How much depends on what is being printed, really. Whether it causes an issue, only you can say, based on your performance target.

andy.fingerhut20:11:43

It typically takes longer to print out 100 characters than 1, but even for the same number of characters, some "to string" converters for some types may be more compute-intensive than others.

andy.fingerhut20:11:15

Are you familiar with JVM and/or Clojure run-time profiling tools like Criterium? https://github.com/hugoduncan/criterium It can help you get some measurements for such things, if you are curious.

👍 4
Mario C.20:11:10

How can I differentiate from two different postgres exceptions? By getting the message and comparing the string values?

hiredman21:11:05

maybe, the exception types are likely different as well

Mario C.21:11:07

They are both of type org.postgresql.util.PSQLException

Mario C.21:11:41

One is duplicate key value violates... and the other is null value in column 'id' violates

noisesmith21:11:57

do they have nested exceptions?

noisesmith21:11:12

(one can check with .getCause)

hiredman21:11:22

hilariously, java.sql.SQLException introduces .getNextException

hiredman21:11:34

which is likely to be what you want in that case instead of .getCause

😒 4
noisesmith21:11:41

oh, good catch

Mario C.21:11:43

I get nil value on .getCause and .getNextException

Mario C.21:11:59

I think just comparing the cause is really the only way

Mario C.21:11:24

wish the exception would have a unique code. That way I would compare that instead of a string

noisesmith21:11:36

I don't know if they are useful in practice, but there are getErrorCode getServerErrorMessage and another one called getSQLState https://jdbc.postgresql.org/development/privateapi/org/postgresql/util/PSQLException.html

noisesmith21:11:11

with any luck the int ErrorCode is different for each case

noisesmith21:11:02

ServerErrorMessage seems to hold a lot of data, potentially

Mario C.22:11:09

Thanks guys!

noisesmith23:11:34

and based on something I just saw in my email I now wonder if we are coworkers, haha

Mario C.23:11:04

lol highly doubt it unless you work for a loan servicing company

noisesmith23:11:30

lending platform

Mario C.23:11:40

oof close! was the email about postgresql exceptions?

noisesmith00:11:55

yeah -honeybadger alerts from a runtime error in prod

jaide22:11:49

How do I compose multiple routes? Currently we supply a vector of (home-routes) but how do I compose the router with both home-routes and a similar function called api-routes in reitit?

noisesmith22:11:26

@jayzawrotny since it's returning a vector to represent the routes, couldn't you use into to pull one set of routes in after the other?

jaide22:11:52

Like (into (home-routes) (api-routes))? I’ll try it! I got some success using (conj (home-routes) (api-routes)) but I’m not sure what I would do if I had another file of routes.

noisesmith22:11:18

conj would make the new routes a vector inside the other vector, instead of combining the vectors

noisesmith22:11:39

I'm not sure how your routing library handles this

jaide22:11:58

Interestingly into didn’t work

jaide22:11:39

This is the output of calling (conj (home-routes) (api-routes)) which is working

noisesmith22:11:41

ahh, so api-routes returns a single subtree, conj makes sense in that case

jaide23:11:05

ok cool, what should I do if I had multiple route files like api-routes or home-routes?

(reduce conj [] [(home-routes) (api-routes)])
is what comes to my mind first

noisesmith23:11:30

conj is already varargs

noisesmith23:11:05

also that doesn't give you the structure you had before - you end up with extra [] around the whole thing (that may or not matter)

noisesmith23:11:59

but really If home-routes is the "top" and everythig else is a child, why not (conj (home-routes) (api-routes) (foo-routes) (bar-routes))

jaide23:11:39

Oh, way more simple! Thanks.

jaide23:11:27

In general is one preferred over the other? (:id data) and (data :id)?

dpsutton23:11:59

they behave differently if data can be nil

noisesmith23:11:08

if either the map or the key is defined as a literal, I prefer to put that one first

noisesmith23:11:39

otherwise get, unless it's well understood the type of the thing doing lookup

jaide23:11:20

That’s a good point, will switch to get.