Fork me on GitHub
#beginners
<
2019-02-25
>
rahx1t00:02:04

Has anyone used a Clojure Sendgrid library they'd recommend?

alice03:02:55

Hey, I haven't been using clojure the last few months and I'm finally back to it, would anyone mind looking at some code I'm working on for a project and telling me what I do good/bad? I want to brush up my skills as best I can

alice03:02:26

https://github.com/fp-alice/cljmcs Here's the git repo the project I'm working on atm is in, I just started and haven't moved too much code outside of the core file yet, but there are 2 short-medium length files to look at in src/

jaihindh.reddy03:02:29

@alice you may also want to post in #code-reviews

seancorfield04:02:25

@alice My first two reactions are: 1) get into the habit of writing docstrings for ns and all functions 2) think about function names some more.

alice09:02:47

Very good criticism, thanks

seancorfield04:02:16

(because you can almost never think too much about naming things)

lepistane08:02:39

Hi, i am not very experienced with deployments and server management i know that heroku is used a lot for clojure apps as hobby projects but after some reading it seems that heroku is really expensive! (for example basic dyno gives you 10k sql rows GLOBAL - that's nothing and anything more you have to pay) Are there any alternatives to heroku ? or should i buckle up and look into digital ocean/aws instances?

jr0cket16:02:37

Cost of the cloud really depends on what you are doing. There are no 'cheap' solutions. You get a lot free with Heroku, so you can have non-production environments that do not cost anything, especially if you switch them off when not using them. If you go to other providers, then everything costs and usually requires more work on your part, so less time writing application code. All the big cloud vendors charge for everything. So even though some individual services may seem 'cheap' if you don't put them together well then they can cost you greatly and can still require you to do capacity planning.

alice10:02:14

If you need cloud-cloud, yeah, but if you just want a vps or something I'd recc OVH or vultr just because they're cheaper. They require you to do the setup, but it's not too difficult if you're familiar with the tools.

alice10:02:39

I've been hosting a Clojure app on a vultr instance for like 2 years at 2.50/mo with sql and stuff

masta10:02:51

what if to use Spec with regular (non namespaced) keywords? should it work ok?

andrea.titton11:02:24

Hello everybody, I have a really basic clojure server (https://github.com/NoFishLikeIan/skincare-server) built with compojure and ring for the middleware. When I run it with simply lein run everything works fine but when I lein uberjar it and run it with java -jar ... I get error in the snippet below. Does anybody have some idea of what the issue could be? Thank you and apologies if it trivial.

manutter5112:02:56

Hi @andrea.titton I might be able to help. Since this is #beginners I’m going to talk through the steps I use to try and debug this. The first thing I look for in a stack trace is to see if any of my classes show up near the top as being the place where the exception occurred. In this case that’s skincare_server.core__init.load, which isn’t very helpful, so on to the next thing. I look next for the Caused by: line, which in this case is a ClassNotFoundException. Java is trying to load a class named javax.xml.bind.DatatypeConverter, and can’t find it. From hanging out in the Clojure slack, I remember hearing about issues with javax.xml.bind, so I did a quick Google search for javax xml bind datatypeconverter not found clojure. The second search result is an issue at the http-kit github repo, and I remember seeing org.httpkit.server in the stack dump you posed, so I clicked on that link (https://github.com/http-kit/http-kit/issues/356). Reading through the comments, I see that this issue was closed by the author as being fixed as of httpkit 2.3.0-beta2. The current version is 2.3.0 (Stable), so I would say you should make sure that your project.clj file includes [http-kit "2.3.0"] in your dependencies. We happen to have luminus-http-kit in a project I’m working on right now, and if you started from luminus you may have the same thing, but if so it won’t hurt to explicitly add [http-kit "2.3.0"].

andrea.titton13:02:16

Thank you very much for your help and the time you spent. I am going to look into this and get back to you with the outcomes. This was truly amazing, and I would have never gone through that process myself. Coming from Python/Rust I have a really hard time debugging Java error logs.

manutter5113:02:10

Java stack traces are intimidating to look at, but most of the information is irrelevant, so once you learn where to look and what to ignore, it gets easier. There's still a lot there, and sometimes you have to know a bit about Java to really understand what it's saying, so feel free to post here any time you have questions about it.

andrea.titton13:02:53

@ this worked! Going from [http-kit "2.2.0"] -> [http-kit "2.3.0"] did the trick

manutter5113:02:23

Awesome! 👍

nicholas.jaunsen14:02:48

How does one decide which functions in your software should have specs?

nicholas.jaunsen14:02:17

or should you be writing specs for everything?

joelsanchez14:02:00

I write them when the function is doing something critical or when the function takes many arguments or maps with many keys

joelsanchez14:02:20

obviously not gonna spec (defn plus [a b] (+ a b))

mattmorten15:02:27

I love spec because it is purely "opt-in". I can write them as I need them, and I don't have to use them everywhere. So I take a utilitarian approach. The first specs I write are usually entry points and functions that are in the critical path, that are hit often in my unit tests

jr0cket15:02:13

@nicholas.jaunsen yes, spec or schema to define system boundaries for behaviour and data is always important. So an obvious place is around the API's you write, or data stores you read/write to. It also can include the boundaries between components of your system, especially were you are using collections of data.

jaihindh.reddy17:02:57

@nicholas.jaunsen Programming is mostly an exploratory process, and often times I don't have input data for the function I'm writing. So I tend to write a spec and generate the input data. I tend to throw it in an fdef right next to the function. I write the :ret and :fn specs when I'm finding it hard to convince myself of the correctness of my function. That said, I don't use Clojure at work. So take this with a pinch of salt 🙂

raymond.w.ko17:02:17

Hello, for users of shadow-cljs + reagent, I am working on a long form and was wondering if there was a way to preserve scroll position of the web page on live reload?

jaihindh.reddy17:02:33

Posting in #clojurescript might work out better considering this is about ClojureScript.

mrevelle18:02:12

re: spec. I tend to spec everything because specs capture assumptions. specs (or types…) are great for documenting context that is often forgotten

mrevelle18:02:29

I’d also encourage people to look at orchestra’s defn-spec. we also use a defrecord-spec that makes spec’ing records with spec1 much more sane. removes need to write boilerplate code

rodrigo75919:02:28

Guys, I think I am doing something wrong using transient/persistent. Take a look on my problem:

rodrigo75919:02:22

The code in txt: (defn propagate [cenario produto] (let [array (transient []) ] (loop [i 0 fd-1 0] (cond (>= i (cenario :ndias)) (persistent! array) :else (let [setOps (get-in cenario [:mapaDeCalculoDeEstoque i])] (let [fd (+ fd-1 (reduce + (for [ops setOps] ((op-fn (:op ops)) 0 (:qtd ops)))))] (conj! array fd) (recur (inc i) fd))))) (assoc-in cenario [:mapaDeArrayDeAbertura produto] array)))

rodrigo75919:02:50

I do not understant why it shows " #object[clojure.lang.PersistentVector$TransientVector 0x4d02cecc"

noisesmith19:02:51

you can't use conj! for side effects

noisesmith19:02:59

you need to use the return value

noisesmith19:02:20

that might not be your only problem, but it's a big problem

rodrigo75919:02:39

How can I reassign the return value to array again? swap! ?

noisesmith19:02:56

by passing the return value of conj! as an arg to recur

noisesmith19:02:02

which means it starts as a loop arg

rodrigo75919:02:40

would swap! work too?

noisesmith19:02:45

no, not at all

rodrigo75919:02:53

the same would happen with assoc!, dissoc!, correct?

noisesmith19:02:28

yes - you need to use the return value of that fn instead of the input - it's allowed to modify the original, but is not guaranteed to

noisesmith19:02:43

so you get the tricky situation where it works with small inputs but breaks with larger ones

noisesmith19:02:31

you could use and atom holding the transient, and use swap! or reset!, but using the transient directly is more direct better

rodrigo75919:02:34

I see. Shit. I made the same mistake dozens of time on my code. I did misuse assoc! everywhere and it worked. But it is not guaranteed... I have to refactor.

rodrigo75919:02:01

Thank you for your assistance!

mrevelle19:02:35

transients are useful for performance. they work by mutation but that’s an implementation detail and you should treat the transient structure as if it were immutable. i.e., do what @noisesmith suggests and include it as a loop parameter

noisesmith19:02:08

precisely - and the reason to use it directly instead of using an atom is to preserve that performance

rodrigo75919:02:16

yes. Go it. Thanks!

gr.evocatus19:02:30

I need to write a simple parser for a small DSL which has only repeat-n-times loops and an analog of include/import directive. Trying to find a way to do it I started studying flex/bison. But as much as I like BNF I don't like these tools. I'm sure it can be done in Clojure but how? Are there any libraries? BNF to AST converters? Maybe I can reuse Clojure reader code? I'm a newbie in Clojure who only wrote hello-world and some project-euler programs.

gr.evocatus19:02:12

You may say "don't write DSL" and in this case I'm 100% sure it can be replaced with a (really simple) data structure but it doesn't depend on me unfortunately

noisesmith19:02:13

@gr.evocatus at least once upon a time instaparse was the go-to https://github.com/Engelberg/instaparse

noisesmith19:02:44

looks like the last commit was a couple of months ago, so it might still be the right choice

gr.evocatus19:02:37

@noisesmith thanks 🙂

noisesmith19:02:14

to re-use clojure reader code, you can use clojure.core/read or clojure.core/read-string or the clojure.edn equivalents more likely - I'm not sure if it's reasonable to reuse more granular parts of the reader

alexmiller19:02:51

instaparse is a great choice

lvbarbosa21:02:35

Anybody else getting this warning when running midje? (Clojure 1.10, Midje 1.9.6) WARNING: any? already refers to: #'clojure.core/any? in namespace: leiningen.midje, being replaced by: #'leiningen.midje/any?

alexmiller21:02:53

it's just a warning, so can be safely ignored

alexmiller21:02:09

just saying that midje is shadowing a core function (added in later Clojure version)

alexmiller21:02:03

it looks like that's coming not out of midje itself, but out of the lein-midje plugin

alexmiller21:02:49

it's an easy fix to make that go away by adding (:refer-clojure :exclude [any?]) to the lein.midje namespace declaration

dts.siedel21:02:53

I've seen similar warnings when libraries I require shadow things in core. Is there a way to silence this?

dts.siedel21:02:33

Mainly when I know and accept the minor shadowing risks, but don't want to spit ugly warnings in production

alexmiller21:02:20

the :refer-clojure will silence the warning

dts.siedel21:02:30

Doesn't that need to be applied to the ns at the top of the offending file? What if you don't control the library that's doing it?

alexmiller22:02:01

there's no way to control it externally

lvbarbosa23:02:51

Is this worth opening an issue in github?

alexmiller23:02:48

If you like, but I don’t consider it a big deal (issues are in jira btw)

hiredman23:02:44

it depends on what project you open an issue with

alexmiller23:02:57

oh, I thought you meant with Clojure. for the original project, sure.