clojure-europe

For people in Europe... or elsewhere... UGT https://indieweb.org/Universal_Greeting_Time
dharrigan 2020-11-09T06:29:35.237300Z

Good Morning!

pez 2020-11-09T06:47:33.238300Z

Good morning! That flow-storm-debugger looks super nice!

ordnungswidrig 2020-11-09T08:13:02.238500Z

Guten morgen!

simongray 2020-11-09T08:13:59.238700Z

morning

ordnungswidrig 2020-11-09T08:15:02.238900Z

“Wilt u uw eigen enquêtes maken?” :rolling_on_the_floor_laughing:

ordnungswidrig 2020-11-09T08:15:36.239400Z

(on “http://de.surveymonkey.com”, I guess the browser got cofuzzled by too much borkdude)

borkdude 2020-11-09T08:30:05.239600Z

haha

slipset 2020-11-09T08:39:42.239800Z

God morgen

raymcdermott 2020-11-09T09:02:14.240200Z

Good dawning

javahippie 2020-11-09T09:40:44.240600Z

Guten Morgen!

slipset 2020-11-09T10:09:27.244900Z

So, this mornings topic from work: Given a map (or record) like so:

(def user {:first-name "Erik" :last-name "Assum"})
Should we be happy with
(:first-name user)
or should we go with
(defn first-name [user] (:first-name user))
I feel really torn here. I really like the conciseness of the first alternative, but it leaves little or no wiggle-room if you later want to change how we store the first-name of the user. The second alternative gives all kinds of wiggle-room, but it also forces us to create accessors/mutators (getters and setters) for stuff that is easily handled by the clojure std library.

slipset 2020-11-09T10:09:41.245200Z

Expert answer is as always "it depends", but I'd be happy if you would share what you think it depends on.

borkdude 2020-11-09T10:10:52.245900Z

@slipset we have a couple of those functions around in our app. this is especially handy if you end up renaming keys later on

borkdude 2020-11-09T10:11:17.246400Z

but you can also just refactor from keywords to functions later of course

slipset 2020-11-09T10:11:27.246600Z

exactly 🙂

borkdude 2020-11-09T10:12:15.247300Z

another one: :user/first-name or :first-name or :first_name (no translating keys when dealing with database)

slipset 2020-11-09T10:33:27.248300Z

I'm somewhere between denial, acceptance, and wishing the world was a better place.

2❤️
jasonbell 2020-11-09T10:39:36.248500Z

Morning

ordnungswidrig 2020-11-09T11:39:03.252900Z

@slipset it’s a more genera question of how strongly you want to couple two things. I this case data representation and the code location(s) using it. Same goes for protocol if you only have a singe implementation (yet) or using sql vs build a data abstraction layer. Question you might want to ask when it comes to coupling: • How often will it change? • How likely is a change? • What is the cost of the change? • What is the code of the abstraction the allow to decouble from the change? • Will the abstract catch all the change? • What is the impact on testing? • …

ordnungswidrig 2020-11-09T11:40:21.253Z

Also known as “the cost of abstraction” (see https://250bpm.com/blog:86/)

slipset 2020-11-09T11:45:17.253200Z

Thank you!

simongray 2020-11-09T12:44:26.260900Z

@slipset My take is this: as long as (first-name user) and (:first-name user) evaluate to the same thing, defn'ing first-name seems like a premature (and pointless) abstraction. If :first-name at some point changes to a different key you can still easily search-replace all instances of :first-name (…or if you use namespaced keywords in intellij simply automatically refactor the keyword). And if the way you access the first name in user changes drastically, you can still defn a user-name function and then just replace all occurrences of (:first-name user) with (first-name user). The only thing defn'ing first-name at the onset really gives you is fewer search-replaced lines down the line if you do decide to change it. At the same time, it actually hides valuable information from the reader (the fact that user is associative and has a :first-name key). Faced with this trade-off, I much prefer using the keyword directly, preferably a namespaced one.

pez 2020-11-09T13:08:00.262200Z

I am with @simongray here. Transparency is nice.

2020-11-09T13:20:20.263100Z

I generally use namespaced keywords directly, but then I'm usually not going in to/out of a database or other system to force camel/snake/kebab like problems

2020-11-09T13:20:58.263800Z

if I do have csk things, I generally go with the most restrictive system and then leave it rather than converting everywhere.

borkdude 2020-11-09T13:22:49.267Z

At first :foo_bar seemed heresy to me, but after trying it out and seeing how much headaches this saves me, not making any mistakes translating maps back and forth, I think it's worth it, when dealing with the most restrictive systems (like postgres)

2020-11-09T13:22:55.267200Z

tho in my data scrubbing code lately I have taken to using namespaced keywords for each bit of the stage. I have nice kebab'ed ones for my domain that have a good domain keyspace, and the ones that read in from a client specific file have a client specific namespace for their keywords. This way I can trace how I've done the transformations from row in excel/csv -> map of those values -> proper domain map the rest of my data science model code wants

2020-11-09T13:23:51.267800Z

but the point of most of my systems is converting from a pile of files to something I can calculate

borkdude 2020-11-09T13:24:14.268100Z

map-csv-reduce ;)

2020-11-09T13:35:54.269700Z

all day long, every day

2020-11-09T13:36:12.270500Z

tho most of it is excel nowadays as that way I don't have people messing up the csv export

2020-11-09T13:37:08.271900Z

I had a read of: https://clojurians.slack.com/archives/CBJ5CGE0G/p1604916751247500 and I like it for domain things that will be long lived. I'm trying to decide if it makes a difference in my transformation code

pithyless 2020-11-09T13:37:18.272100Z

RE: keywords; there's actually a third option I've seen in the wild:

(def first-name :first-name)
See e.g. https://github.com/fulcrologic/fulcro-rad/blob/develop/src/main/com/fulcrologic/rad/report_options.cljc You use the var as you would use a keyword, but you're free to add docstrings and the keyword namespace does not have to match the actual namespace (while still allowing you to use an imported ns alias).

2020-11-09T13:37:54.272700Z

that I've not seen before

2020-11-09T13:38:25.274300Z

I'm generally not a fan of creating getters and setters. That was an OOP habit I was hoping to have left behind by getting to values

borkdude 2020-11-09T13:38:37.274800Z

@pithyless Good point. I do that with re-frame as well.

(def tag-path [:foo/bar :baz/tags])

(reg-event-fx ... (update-in db tag-path ...))

1❤️
borkdude 2020-11-09T13:38:54.275100Z

so I can later on change things more easily without refactoring a whole bunch of things

pithyless 2020-11-09T13:40:44.277100Z

Yeah, it's interesting to use e.g. when you want to use 3rd party keywords (both for having a single source of truth and also having a good place to write some documentation for yourself). The only thing that bugs me about it is you lose the keyword destructuring sugar syntax.

pithyless 2020-11-09T13:48:28.282Z

> I'm generally not a fan of creating getters and setters. That was an OOP habit I was hoping to have left behind by getting to values I don't consider (def foo :foo) an OOP getter/setter pattern. Instead, I think of it as an additional hop that decouples your local app name from the data layer name. If it's true that "your data lives longer than your application", then your ::domain/first-name may change less frequently than your favorite ::app.ns/first-name ; I've been going back-and-forth whether this distinction is worth the trouble of foregoing certain syntax conveniences and making this distinction more explicit in my own code.

borkdude 2020-11-09T13:52:20.282300Z

yes, it's just an extra level of indirection, the solution to almost anything in CS

1
2020-11-09T14:07:16.289100Z

except too many layers of indirection

1💣
orestis 2020-11-09T17:04:16.290300Z

I needed to make a POST request to an endpoint I’m developing to validate “external” behaviour and I started (yet again) googling for curl arguments to make a JSON post payload etc. Then I realized I had my REPL open and I could just do a clj-http request 😄

borkdude 2020-11-09T17:11:26.291Z

If you really need to go through curl:

$ bb -e '(-&gt; (curl/post "<https://postman-echo.com/post>" {:body "dude" :headers {"Content-Type" "text/plain"}}) :body (json/parse-string true) :data)'
"dude"

1❤️
slipset 2020-11-09T17:21:01.292800Z

@orestis I/we have fns for that in our dev/user.clj which handles auth and stuff. Quite useful.

slipset 2020-11-09T17:22:26.295100Z

Another thing that’s quite useful is to have a great story on integration-tests so it’s really simple to write a simple test for your new endpoint. C-c C-t r is your friend in that case.

borkdude 2020-11-09T17:23:56.295300Z

C-c C-t is undefined in my emacs

slipset 2020-11-09T17:25:11.296300Z

I took it from memory :( my fingers know the key binding, my brain does not

slipset 2020-11-09T17:25:28.296800Z

Basically it’s rerun failing tests

djblue 2020-11-09T18:10:35.297800Z

I think you might find https://github.com/djblue/portal/pull/18 interesting. Still working on it but it should address your concerns around long sequences.

raymcdermott 2020-11-09T18:15:24.298800Z

👋:skin-tone-3: @djblue ... bonjour Chris

djblue 2020-11-09T18:16:02.298900Z

Hello @raymcdermott!

raymcdermott 2020-11-09T18:16:46.299500Z

oh and did I tell you I hate threads 🙂

dominicm 2020-11-09T18:16:55.299600Z

No?

1😆
djblue 2020-11-09T18:17:02.299900Z

Do you? 😏

raymcdermott 2020-11-09T18:17:18.300600Z

🤐

dominicm 2020-11-09T18:17:19.300800Z

Threads are rather terrible. All the extra clicking.

djblue 2020-11-09T18:17:37.301100Z

True, but they scope conversations 🤷

djblue 2020-11-09T18:17:45.301500Z

Like a namespace

djblue 2020-11-09T18:17:58.302Z

And don't we all love namespaces?

raymcdermott 2020-11-09T18:18:07.302200Z

ok, let's just say that this is a flat namespace

raymcdermott 2020-11-09T18:18:26.302800Z

channels scope conversations too, like a namespace

1👍
raymcdermott 2020-11-09T18:18:42.303200Z

anyway welcome ... 🙂

raymcdermott 2020-11-09T18:18:56.303700Z

you know I 😍 you

djblue 2020-11-09T18:20:49.304Z

Likewise

dharrigan 2020-11-09T18:24:21.304700Z

I’m not a fan of threads either. All that extra jumping around.

dharrigan 2020-11-09T18:24:31.304900Z

IRC FTW!

orestis 2020-11-09T18:28:57.305400Z

You know @borkdude I still haven’t installed babashka on my machine 🙈

dominicm 2020-11-09T19:13:56.306300Z

I like threads as a concept, just not how slack does it.

djblue 2020-11-09T19:49:53.307Z

I think they use to be way worse before you could resize the window split

dominicm 2020-11-09T20:02:08.307500Z

They still don't update on the threads page though

ordnungswidrig 2020-11-09T20:02:08.307600Z

I want tabs.

borkdude 2020-11-09T20:16:37.307800Z

I want true multi-threading

1😂1😆
dominicm 2020-11-09T20:25:46.308400Z

I'd be happy with communicating sequential people