Fork me on GitHub
#beginners
<
2020-01-18
>
kamuela11:01:20

What does the extension .cljc tend to mean?

matti.uusitalo12:01:14

The source is intended to work in clojure and clojurescript both.

alexmiller12:01:32

the extra "c" stands for "common"

kamuela12:01:48

Ok thank you, very interesting

abdullahibra13:01:11

is there a way to indent and lint the clojure code which read from stdin and write to stdout ?

abdullahibra14:01:18

@k.i.o seems interesting, but how can i do indentation read from stdin -> stdout ?

abdullahibra14:01:38

maybe i can skip linter for now

markus.kiili14:01:06

Hi. How do you actually deploy a Ring app on a server? In other words, how to deploy an uberjar.

markus.kiili14:01:50

I have been able to make the jar run on my linux server. Just wondering what if there is some problem or the whole operating system reboots? How to make it so that it starts up again.

matti.uusitalo15:01:45

You can set up a system service which keeps it up. Checkout systemd, systemctl etc

matti.uusitalo15:01:23

Assuming your linux uses systemd

georghagen15:01:33

I am struggling a bit with the anonymous functions. I am trying to make two identical functions, the one with # works, but the one using the longer notation lambda (fn) doesnt.

georghagen15:01:43

(defn inc-maker
  "Create a custom incrementor"
  [inc-by]
  #(+ % inc-by))

georghagen15:01:55

(defn inc-maker2 “Create a custom incrementor” [inc-by] (fn (+ inc-by)))

nberani15:01:26

you did not tell the longer form about its arguments

georghagen15:01:01

(defn inc-maker2 
  "Create a custom incrementor"
  [inc-by]
  (fn [inc-by] (+ inc-by)))

georghagen15:01:37

Thanks, that one works.

nberani15:01:16

see, you want to have a function that accepts an argument x and increments it by inc-by

nberani15:01:29

in your short form, your x is %

nberani15:01:53

in your long form you have nothing to do the same job as % in your short form, get it?

nberani16:01:15

and, inc-by is the argument to inc-maker2 function, not to your resulting function

finn.volkel16:01:27

Hey, I just trying out the re-frame templete with cider. Did lein new re-frame yeah +cider and tried to jack in, but got the following error

Execution error (ExceptionInfo) at shadow.cljs.devtools.server.runtime/get-instance! (runtime.clj:11).
missing instance
lein dev runs fine

finn.volkel16:01:32

cider-jack-in-cljs btw

dpsutton17:01:09

it worked fine for me. Did you get an option for which build to use and you chose app?

dpsutton17:01:21

also, this project has two build systems. I saw that in lein it just calls out to shadow so when CIDER asks me which build it should use i just said shadow

finn.volkel17:01:09

@dpsutton yes did that

dpsutton17:01:36

and you're receiving that error message after choosing shadow and then app as the build?

finn.volkel17:01:38

cider somehow infers that it's shadow so only asks me for the build type

dpsutton17:01:05

yeah. in the dir-locals file it sets the preferred build tool

finn.volkel17:01:52

nevermind now I see what you meant, I thought you meant the CLJS repl type. That was actually the error.

finn.volkel17:01:21

In figwheel you still choose lein

finn.volkel17:01:34

Wasn't used to that

dpsutton17:01:16

awesome! glad its working

dehli18:01:31

Hello, I'm messing around with deftype and wondering if it's possible to create a variable that all the methods will have access to. Basically I'd like it to look something like this:

(deftype ManagementApi [endpoint]
  ManagementApiProtocol
  ;; (let [api (make-api endpoint)]
  (get-connection [this params]
    ;; Do something with the outer api
  )
  (delete-connection [this params]
    ;; Do something with the outer api
  )
Where both methods will have access to that api variable (not sure what the syntax would be)

dpsutton18:01:36

i don't believe so. What you can do is pass that in and make a function that takes the endpoint and returns the deftype with both items bound. Ie, (defn management-api [endpoint] (->ManagementApi endpoint (make-api endpoint)))

dehli18:01:51

Ahhh, that would be a good approach. Much more functional 🙂 Thanks @dpsutton!

christian.paling18:01:06

I have a somewhat conceptual question. So I come mostly from a Ruby background where a lot of ORMs are available. As far as I noticed, Clojurians do not seem to like ORMs. So how do you structure your persistency logic then? Do you just write specialized SQL queries for each API request? Do you have open source examples how you structure your database logic where there are more than one or two tables?

christian.paling18:01:38

Or is it possible to have a somewhat generic set of functions which you use to build the persistency logic? When I try thinking about how this could be achieved, it seems really hard e.g. when it comes to joining tables or other complex queries

seancorfield19:01:50

@christian.paling For basic CRUD, you can just read and write hash maps, and update/delete by example (using a hash map) against the database using next.jdbc (or clojure.java.jdbc or a few others). For more than simple CRUD, you can either write the SQL (and use any of those JDBC wrappers) or you can look to some of the DSLs out there like HoneySQL, Walkable, etc.

christian.paling19:01:10

Thanks for the links ! I will take a look at them ! So people do not use something like lightweight repository objects or anything. But actually just write the SQL queries they need

christian.paling19:01:20

I‘m sorry if these questions sound confusing, I‘m just used to having something like User.where(...).joins(...)

christian.paling19:01:12

And whenever I implement a system, even if I don‘t use a ORM library, I somehow have the urge to abstract my persistency logic, i.e. implement my own mini ORM

seancorfield19:01:32

Clojure has no objects, just bare data.

seancorfield19:01:41

But that User.where(...).joins(...) maps over to something like HoneySQL's DSL: (-> (select :a) (from :user) (where ...) (join ...)) to produce the data structure that represents the query. Then you call (jdbc/execute! data-source (honeysql/format dsl-data))

christian.paling19:01:33

That‘s true. It is actually that easy

seancorfield19:01:08

Clojure's way is all about "simple", rather than "easy". ORMs can seem "easy" but they are definitely not "simple".

christian.paling19:01:28

So an ORM is basically something that is overengineered?

christian.paling19:01:40

And where do you put your queries? Do you put them next to the API endpoints that need them? Or do you group them in namespaces like all user queries go into a user namespace?

seancorfield19:01:12

I've used a bunch of ORMs over the decades, including Object Databases when those were a thing, and I do think they're over-engineered but they're also problematic in so many ways.

seancorfield19:01:01

Heh, years ago, I even gave a conference talk about the problems with ORMs 🙂 Have you read Ted Seward's piece (from years ago) arguing that ORMs are the "Vietnam" of Software Engineering?

seancorfield19:01:41

As for where to put the queries, it really depends on how big/complex your app is. There are lots of ways to structure code and Clojure isn't very opinionated about that. The only guiding principle is to try to keep side effects at the edges and write as much of your code as possible as simple, pure functions that are easy to test/reason about.

seancorfield19:01:30

That's the one!

christian.paling19:01:56

Is your talk also available online? I was not able to find it

seancorfield19:01:59

Not online. It was at a conference that didn't video talks.

seancorfield19:01:43

I haven't spoken at any conferences now for nearly seven years. I was a fairly regular speaker around the world before then for Macromedia/Adobe-related tech (where I worked 2000-2007).

christian.paling19:01:20

I see. Well, thanks for your time and input. I’ve got a lot to read now ! For my next application I‘ll try out the Clojure way of working with the database 🙂

seancorfield20:01:59

If you have any Qs about SQL/JDBC stuff there's a #sql channel and there's also a #honeysql channel if you go that way.