admin-announcements

Announcements from the Clojurians Admin Team (@U11BV7MTK @U077BEWNQ @U050TNB9F @U0ETXRFEW @U04V70XH6 @U8MJBRSR5 and others)
tolitius 2015-12-23T04:47:03.002273Z

@sveri: the behavior is a lot more transparent in 0.1.8-SNAPSHOT, affected states would be restarted on namespace reloads: https://github.com/tolitius/mount/blob/0.1.8/README.md#recompiling-namespaces-with-running-states

sveri 2015-12-23T06:31:40.002275Z

@tolitius: Thanks for the quick update, I will definitly try it, if I find out how to include snapshot versions in my project. Anyone knows what I need to add to my leiningen definition?

sveri 2015-12-23T06:33:56.002276Z

Never mind, I had a typo

sveri 2015-12-23T07:22:36.002277Z

Ok, I opened two new issuse for everyone interested: https://github.com/tolitius/mount/issues/26 and https://github.com/tolitius/mount/issues/25

sveri 2015-12-23T07:23:25.002279Z

Also I'd like to thank you for your work, it's great to see an approach to components that is more clojuresque. I really love the idea :simple_smile:

2015-12-23T10:30:50.002282Z

@tolitus "Keep the code that interacts with external resources at the edges of the application. The core business logic should be pure and testable, while anything that deals with side effects and external resources should be pushed to a thin layer around it" This almost sounds like a hexagonal architecture used in a Clojure context. Is that the case?

dm3 2015-12-23T11:40:16.002283Z

that's how purely functional programs should be structured

dm3 2015-12-23T11:41:18.002284Z

which is conceptually similar to "hexagonal architecture"

2015-12-23T11:46:06.002286Z

@dm3 I'm now become slowly aware that paradigms I'm used to in the OO world have their origins from the functional (bow)

sveri 2015-12-23T12:04:33.002287Z

Hm, I have been thinking a lot about this. But, I am not so sure. Saying that anything dealing with side effects should be pushed to a thin layer around it, sounds like that's only a bit code. But doing any development that faces users or other clients I mostly have code that deals transforming data, from user to application to database or wherever and back. Mostly, the code that does any business logic is the smaller part of it

sander 2015-12-23T12:12:33.002288Z

sveri: you may be able to express most of the data transformations in pure functions, and just have (read key) and (write key val) functions in your side effect layer

sveri 2015-12-23T12:13:40.002289Z

@sander: I know and mostly I do so, but still, the whole intent is to move data from a to b and adapt the to suit b's needs.

sander 2015-12-23T12:15:14.002290Z

yeah being a thin layer it probably still won't be just a little bit of code

sveri 2015-12-23T12:16:07.002291Z

Currently I am playing stockfighter and for lvl 2 I built a whole web interface and websocket connections and a log and what not stuff. All interacting with their REST API or my web UI. It was a lot of code (not needed to solve lvl 2, but, well it was fun). And to solve lvl 2 I needed three functions integrated into all my other stuff. I guess that there like 2 % "business logic" compared to the other stuff connecting pieces.

jaen 2015-12-23T12:16:42.002292Z

But if you do this, then you have the benefit of being able to not touch the domain logic if you need to change the data store, or the user interface. I guess that's the main benefit of the hexagon.

sveri 2015-12-23T12:17:28.002293Z

I guess you could do that too if you abstract the data acess away into protocols or similar stuff. Indenependent from where they reside

sveri 2015-12-23T12:18:56.002294Z

So, I am not saying hexagon is bad or so. It's just the saying "put the side effecting stuff into a thin layer around the domain logic" suggests that the side effecting stuff is small and can be done in a few functions, but, from my experience the opposite is what usually happens. However, it's only my experience and surely depends on the domain.

sveri 2015-12-23T12:26:30.002295Z

I can imagine, if you do data analyisis where you have a connection providing a stream of data that you analyse and just pass on to another stream that there may be less glue code..

jaen 2015-12-23T12:27:38.002296Z

Well yeah, vanilla OO hexagon is heavily based around abstracting any outside communication into protocols/interfaces. I guess it might also depend on how you think about "side effecting stuff", but I agree the layer might not be as thin as one would hope, especially if the domain itself is simple. Writing a CRUD blog in a hexagonal way is probably way more effort than strictly required to just get it working. But when the ratio of the domain logic to the surrounding glue is more favourable (the domain is complex enough - maybe it's banking or shipping or commerce) then it would probably start coming out ahead in testability and maintenance compared to effort.

jaen 2015-12-23T12:33:18.002298Z

I think in general it's probably dependent quite a bit on the point of view - I've had a elective course on systems architecture this semester (first good course in six years...) and people had a hard time to understand the benefits Event Sourcing brings - if you have an immutable event stream and you can do time travel, speculative updates, easy merges and the application states basically lives only in-memory as a fold over the events and not like in more "normal" systems in an external database you really get a powerful toolset to deal with problems. It' s probably quite obvious for us here, since Clojure has parts of it built into the language with persistent data structures and reference types, Datomic uses some of those concepts in it's design and so on, but for students that have been learning programming for 3 years only and in imperative OO languages to boot? That was something they couldn't grasp at all.

jaen 2015-12-23T12:34:36.002299Z

And I'd hazard a guess it might be somewhat similar with those side effects you mention being pervasive. It might be just obvious to deal with them as you go, instead of pushing them to the outside due to how ingrained it is.

jaen 2015-12-23T12:36:00.002300Z

But it's a one big maybe - I just feel that sometimes things we think are necessary are not from another point of view. And maybe those side effects are not necessary where you want them, but are part of how you view the problem.

sveri 2015-12-23T12:38:16.002301Z

You could be right here. When I started on the web UI for stockfighter I was only doing side effecting stuff and building up state inside my application. So, I was basically only working in the "thin" layer and nothing else. When I was done with it I had only the thin layer, which is big, of course. Then adding the domain logic seemed like the easy task.

jaen 2015-12-23T12:39:11.002302Z

Could be.

jaen 2015-12-23T12:46:07.002303Z

I remember how hard Event Sourcing was to get for me, when everyone tried to explain it in terms of OO objects interacting with each other. I couldn't get it for the longest of times. And then I read somewhere that event sourcing is basically producing state by the way of left fold over a stream of events and I was enlightened. Similarly during this course when event sourcing was being explained one student was all like "but what if I had to fix a past mistake in event sourcing, don't I have to change past events then" and no matter how much he was being explained to he was all like "but if...", because to him mutability and the database being source of truth for the current state only was natural. If you come from the FP mindset the "don't change past, lay it over" is a natural approach.

👍 1
jaen 2015-12-23T12:46:42.002304Z

So I guess at some point if you try to structure applications as to separate the domain logic from the external interface you will see how the lines are best drawn.

jaen 2015-12-23T12:46:55.002305Z

And I'm saying this to myself as well, I hardly know that either.

robert-stuttaford 2015-12-23T13:56:24.002306Z

event sourcing ftw

tolitius 2015-12-23T14:57:14.002307Z

@sveri: looks like a foo.bar.components.handler from your example (great example btw :)) is missing a :stop function (for both #25 and #26). I added a bit more details in the github issues.

sveri 2015-12-23T15:05:52.002309Z

@tolitius: Thanks for looking at it. I already commented and will give it a "real" try later :simple_smile:

2015-12-23T19:09:35.002312Z

Are there transcripts of the cognicasts?

2015-12-23T19:29:21.002316Z

Question: How do I turn a number into a vector of its digits?

jaen 2015-12-23T19:31:08.002317Z

Is the number an integer or string representation of it? In the first case I would repeatedly do modular division by 10 to produce a list of digits, in the second exploding the string by characters and then turning them into numbers would be appropriate.

jaen 2015-12-23T19:31:09.002318Z

I think.

2015-12-23T19:31:54.002319Z

@jaen: It’s the first case

jaen 2015-12-23T19:32:20.002320Z

Yeah, then do modular division as long as you're non-zero and you should have a list of consecutive digits.

2015-12-23T19:33:08.002321Z

modular division? if someone has the patience, please explain. (new to clojure)

2015-12-23T19:33:57.002322Z

Is it using the modulus operator?

jaen 2015-12-23T19:34:27.002323Z

Yeah. It's usually % if you used any C-like language.

jaen 2015-12-23T19:34:31.002324Z

In Clojure it's mod.

2015-12-23T19:38:42.002325Z

Thanks

2015-12-23T19:39:01.002326Z

Wrapping my head around this pure(-ish) functional thinking

2015-12-23T19:39:08.002327Z

(seq (str n)) where n is your number

2015-12-23T19:41:18.002328Z

@jr: ok, why does the output look like (\1 \2 \3)? What are the backslashes?

jaen 2015-12-23T19:41:28.002329Z

It's a character

👍 1
jaen 2015-12-23T19:41:39.002330Z

like '1' in C-like languages.

2015-12-23T19:42:07.002331Z

(map int (str n)) will convert those to integers if that’s what you want

👍 1
jaen 2015-12-23T19:42:39.002332Z

(defn digits [number]
  (if (> number 10)
    (conj (digits (quot number 10)) (mod number 10))
    [number]))

jaen 2015-12-23T19:42:44.002333Z

Here's an example solution

jaen 2015-12-23T19:42:47.002334Z

For the integer case.

👍 1
2015-12-23T19:47:40.002335Z

@jaen: wait, i’m getting an error after i pasted that in and then did (digits 123)

jaen 2015-12-23T19:48:22.002336Z

Interesting, I'm pretty sure I've pasted a working code from the REPL, maybe I messed something up when formatting.

jaen 2015-12-23T19:48:40.002337Z

boot.user=> (digits 12234729385)
[1 2 2 3 4 7 2 9 3 8 5]

jaen 2015-12-23T19:48:45.002338Z

What error do you get?

2015-12-23T19:48:59.002339Z

java.lang.IllegalStateException: Attempting to call unbound fn: #'sandbox16491/digits

jaen 2015-12-23T19:50:09.002340Z

That's weird, where are you compiling that?

2015-12-23T19:50:30.002341Z

http://www.tryclj.com/

jaen 2015-12-23T19:50:50.002342Z

Oh, maybe you can't define functions there

jaen 2015-12-23T19:51:18.002343Z

Try here - http://clojurescript.io/

jaen 2015-12-23T19:51:20.002344Z

Seems to work

2015-12-23T19:54:27.002345Z

tryclj worked fine for me

jaen 2015-12-23T19:56:01.002346Z

Hm, interesting, I've tried just now and it worked as well

jaen 2015-12-23T19:56:03.002347Z

Interesting.

2015-12-23T19:56:34.002348Z

Maybe I entered it wrong? 🤷

2015-12-23T19:57:00.002349Z

In any case, it worked on http://clojurescript.io

2015-12-23T19:58:08.002350Z

Heh, I tried changing the namespace to see if I could see the error for myself: java.lang.SecurityException: You tripped the alarm! in-ns is bad! Well, I guess I'm glad they thought of that. :simple_smile:

2015-12-23T19:59:29.002351Z

OK, something tells me that I probably need to get “The Joy of Clojure"

2015-12-23T20:01:30.002352Z

Because I don’t want to keep asking silly questions

2015-12-23T20:02:00.002353Z

@jaen, if you’re awesomely patient enough, could you please walk me through the logic of the function you wrote?

2015-12-23T20:02:24.002354Z

i don’t understand how it works for digits larger than 99

jaen 2015-12-23T20:03:00.002355Z

Well, if you're just starting out with Clojure I suggest getting "Programming Clojure" first (aka. The Swan Book). "The Joy of Clojure" is pretty great, but not as a first book.

jaen 2015-12-23T20:03:02.002356Z

As for logic.

jaen 2015-12-23T20:04:30.002358Z

It's pretty simple recursion.

jaen 2015-12-23T20:04:36.002359Z

If the number is less than 10

jaen 2015-12-23T20:04:40.002360Z

It's a single digit

jaen 2015-12-23T20:04:53.002361Z

So we just return it in a one-element-vector.

jaen 2015-12-23T20:05:47.002362Z

Otherwise we use conj to add (mod number 10) that is the number modulo 10 (which is the remainder of division, and remainder of division is equal to the last digit of a number)

jaen 2015-12-23T20:06:38.002363Z

to a result of recursive call to (digits (quot number 10)) where quot is integer division - that is for (quot 4 3) you get 1.

jaen 2015-12-23T20:09:03.002364Z

So for example for (digit 123) it will result in something like this if we do it step by step:

(digits 123)
(conj (digits 12) 3)
(conj (conj (digits 1) 2) 3)
(conj (conj [1] 2) 3)
(conj [1 2] 3)
[1 2 3]

jaen 2015-12-23T20:09:17.002365Z

@kopasetik: does that explain how it works well enough for you?

tim_h 2015-12-23T20:09:25.002366Z

@kopasetik: If you’re looking for book recommendations, "Clojure for the Brave and True" was my first book clojure book, it’s very beginner friendly. I think the online edition is free. (http://www.braveclojure.com)

👍 1
2015-12-23T20:10:45.002367Z

@jaen: Yes, that makes a lot more sense. Thank you :simple_smile:

jaen 2015-12-23T20:11:30.002368Z

No problem.

jaen 2015-12-23T20:12:11.002369Z

Anyway - for first book it's better if you go with my or tim_h's suggestion. Joy of Clojure is good only after you get somewhat comfortable with the language.

👍 2
2015-12-23T20:22:19.002371Z

Does clojure have function hoisting?

2015-12-23T20:24:11.002372Z

@kopasetik: none that i’m aware of, but this might be close: https://clojuredocs.org/clojure.core/declare

👍 1
2015-12-23T20:27:35.002373Z

Ok, I’ve read that clojure/lisp in general is so simple in terms of its set of native functions that you can fit such a set onto a napkin. Have you experienced that?

2015-12-23T20:46:08.002374Z

@kopasetik: Well, kind of. You do have a small set of building block functions/macros that take you a long way in Clojure. Having said that, core isn't exactly small... but a lot of that is more for convenience than anything else, I think.

2015-12-23T20:46:36.002375Z

@solicode Awesome response, thanks!

2015-12-23T21:14:03.002376Z

Is there a clojure/clojurescript style guide that I can consult to make my code as legible as possible?

eggsyntax 2015-12-23T22:28:45.002380Z

@kopasetik: there’s a very very small set of functions that are sufficient to fully define Lisps, which may be what you’re thinking of. And then you build everything else in terms of those functions, building up to whatever level of abstraction you prefer. Clojure uses a richer set of base functions for convenience, and then gives you loads of other handy functions, but those are the ones built on top. You very definitely want an editor that handles the parens well so they don’t get confusing, and several of those have aggressive formatters you can use that’ll keep your code formatted properly at all times (or on save, if you like) so it doesn’t get too confusing. Dunno if anyone suggested this above, but you’ll probably want to join #C053AK3F9 — you can feel free to post loads of questions there, and there’s usually someone around to help out. Good luck & have fun!

😀 1
2015-12-23T22:30:53.002382Z

@eggsyntax: Just joined #C053AK3F9. Thanks for all of the info!

jaen 2015-12-23T22:34:50.002383Z

If you're looking a for a good editor, then Curisve is pretty neat. Has structural editing, debugger, and other niceties.

2015-12-23T22:43:03.002384Z

OK :simple_smile: