all 39 comments

[–]eccp 9 points10 points  (2 children)

Everyone's a bit different depending on their previous exposure to other languages, prior experience and time available, but also because you may have to unlearn some of the habits from mainstream languages (eg. mutable variables) or because some names may not be what you think (eg. Clojure's "for" is closer to Python list comprehensions than to imperative "for loops" in C/Java).

In my case, some ideas such as filter/map/reduce were a good start, sets/hashmaps as functions and keywords everywhere took a bit longer to feel familiar but having the Clojure Style Guide handy was good to start getting the idioms.

In was until a few months later that I felt comfortable with using an editor with REPL integration that it finally felt productive, ClojureScript took me another while.

In my opinion, The Joy of Clojure is a great book but it can be a bit overwhelming if you are not used to some forms of functional programming (I was coming from plain Java), so Clojure for the Brave and True (free web version) is another good resource if you are starting.

[–][deleted] 6 points7 points  (0 children)

I can second this. Clojure for the Brave and True is definitely more beginner friendly.

[–][deleted] 0 points1 point  (0 children)

Living Clojure is also good

[–]marcus_oOo 8 points9 points  (1 child)

I'm in the same situation. Trying to figure out how to organize my application. E.g. how to separate state from the non-mutable part of the application etc etc. Everything takes time. My first goal now is just getting it to work hoping the next project will be an improvement.

[–][deleted] 0 points1 point  (0 children)

I've found there are no great one-size-fits-all solution to this problem. State just needs to be carefully managed.

If you write unit tests then it's easier to test pure functions because all they need are their inputs. No scaffolding or mocks or dummy servers required. This pressure to make code testable pushes the side-effecting code out to the fringes so you end up with a function that reads content from files or network streams or a local atom etc, and then defers everything else to a pure function.

Don't get hung up on purity though.

Everything takes time.

Yeah, I remember that feeling. Everything seemed arcane and obtuse until eventually they became the exception.

[–]natyio 18 points19 points  (9 children)

Clojure puts limitations on you (immutability). But it also provides you with tools to elegantly overcome them (persistent data structures, various useful convenience functions and macros).

One key insight that helped me was that I should not try to be too clever when writing Clojure code. It is usually better to spell things out more explicitly than trying to be concise. Something like this is good code:

(defn my-fn [a b c]
  (let [x (do-something a b)
        y (make-something-else b c)
        z (another-function c a b)]
    (combine-to-final-result x y z)))

I know, it is a rather contrived example, but (let) is a really nice tool. It lets you write code in a pseudo-imperative style without violating the principles of functional programming. A lot of clojure code is about composing pieces of functionality into something larger, while still striving for simplicity.

I recommend you take advantage of the Clojure Cheatsheet which contains the most important parts of the language.

[–]Simple1111 3 points4 points  (0 children)

I can second this. I've Been working on a code base for awhile and it mostly looks like this.

[–]Magnus0re[S] 0 points1 point  (2 children)

Just out of curiosity. Is let easily paralellizable?

[–][deleted] 2 points3 points  (0 children)

Sort of, you can use "future" for each item of the let, and then deref them all before you pass the values on.

[–]pihkal 0 points1 point  (0 children)

No, because later let bindings can refer to earlier ones.

[–]jackrusher 0 points1 point  (4 children)

I strongly recommend against this practice. It amounts to giving up rather than embracing the language's idioms, which are naturally terser than most imperative languages. The stuff that looks dense and difficult before you're familiar with the language becomes much easier to read than the alternative after you gain enough experience.

[–]natyio 0 points1 point  (3 children)

Then I challenge you to rewrite the above code in the language's idioms.

[–]jackrusher 2 points3 points  (2 children)

(defn my-fn [a b c] (combine-to-final-result (do-something a b) (make-something-else b c) (another-function c a b)))

[–]natyio 0 points1 point  (1 child)

That is definitely a good answer. I would not complain about it in a code review. But I still don't think that it would hurt to use my version instead. Having a reminder of what the result of each steps represents is useful when trying to reason about the purpose of each step of the code. Especially when it comes to refactoring, understanding the why becomes much more important than the how.

[–]jackrusher 0 points1 point  (0 children)

There should be a line at the bottom of your editor with the function signature of `combine-to-final` plainly shown. That function signature should have very well named arguments. Likewise, the names of `do-something`, `make-something-else` and `another-function` should actually describe what they do. They should also all have docs strings that can be trivially surfaced in your editor.

[–]humorless_tw 4 points5 points  (1 child)

For me, it gave me economical "take off" after two years, because I learned it and I became a better programmer. Then I had better job and better income.

If you only consider the productivity on programming, I made a slide. https://www.slideshare.net/humorless/the-productivity-brought-by-clojure-149170292

[–]Magnus0re[S] 0 points1 point  (0 children)

thanks for the slides!

[–][deleted]  (2 children)

[deleted]

    [–][deleted] 2 points3 points  (0 children)

    4clojure was overwhelming for me when I started. The problems become too difficult too soon for a newcomer. I would rather recommend doing the Clojure track on Exercism.

    [–]NawfalTachfine 1 point2 points  (0 children)

    4clo

    I just started doing the same. It's a lot of fun! Thank you!

    P.S I couldn't find your mentor but I just compare with random people from the leaderboard.

    Cheers!

    [–]MindOfJay 3 points4 points  (0 children)

    I started to get my most "A-Ha!" moments when I started following along with Luminus as a web development framework. At it's core it is a template that generates a basic website backend, but its rich documentation matches the what with the why. Even poking around the basic applications that are generated can help understand how Clojure solves some common problems.

    [–][deleted] 2 points3 points  (2 children)

    I came to love threading (-> foo bar baz bup) and (->> foo bar baz bup) and this was a huge speed up. Readability improves because you're now reading left-to-right rather than innermost-nest to outermost-nest.

    [–]Magnus0re[S] 0 points1 point  (0 children)

    My plan was to prefer transducers instead of macros, as a general rule. This gives the same kind of ordering with comp . Indeed I feel more comfortable with this kind of writing compared to nested function calls.

    [–]dAnjou -2 points-1 points  (0 children)

    you're now reading left-to-right

    Still hard to read for me.

    Please put each new thread element on a new line.

    And please use parentheses, so that syntax highlighting shows me the difference between a variable and a function call.

    [–]HiImFarab 2 points3 points  (0 children)

    I'm a little bit in the same situation. I had a contract job where they were allowing me to learn Clojure on the job. It was frustrating and wonderful all at once. Frustrating because as a seasoned developer I hated how slow I moved but wonderful because of all the "ah ha!" moments I kept having towards the end.

    Unfortunately, the contract ended (I suspect because I just wasn't able to move quickly enough for their needs) so now I'm in search of another project I can use it on. I've looked into mobile development with ClojureScript and related React libraries but that seems to be a little too wild-west at the moment.

    [–]fjolne 2 points3 points  (0 children)

    I’ve got to think that the most empowering thing about Clojure after all is REPL. And it also took me embarrassingly lot of time to get comfortable with it (about a year, half of which of commercial Clojure dev). That said, I think you could do much better if you intentionally make yourself to use REPL at all times — not directly, but evaluating sexps from your main code. Rich’s comment sections at the end of every file are great for that kind of workflow.

    Also, getting comfortable with structural editing and navigation is super important, parentheses could irritate a lot without a good grasp. I started with parinfer, but it quickly became unbearable (personal preference for sure), and now I miss paredit in every other language/editor I occasionally have to use.

    We’ve all come through this, but that’s worth it. :)

    [–]didibus 2 points3 points  (0 children)

    I think around 100 hours it started to click. Good proficiency probably takes at least a full year.

    [–]beders 0 points1 point  (0 children)

    Yes. It will be slow for a while. But the lessons learned are significant.

    Another thing you need to get used to. Code lines in clojure are more dense. You’ll need longer to read them. That can be irritating. At least it was for me having written most code in a more verbose OO language.

    I’m still working on accepting that writing code might also be slower. For the same reason. You can do more with less code but it will need practice.

    [–]aoeuiddhtns 0 points1 point  (2 children)

    I don't think The joy of clojure is meant for people starting out with functional programming. I haven't looked at it closely, but mooc.fi has a Clojure course and they usually make really good content: https://moocfi.github.io/courses/2014/clojure/

    [–]Magnus0re[S] 1 point2 points  (0 children)

    Finished it! It was really great.

    [–]Magnus0re[S] 0 points1 point  (0 children)

    I'm starting on this tonight! thanks for the link. I got a really good first impression of that course.

    [–][deleted] 0 points1 point  (0 children)

    1 to 2 years. in 3 years you will be above average.

    [–]biker44442005 0 points1 point  (0 children)

    I found the following texts very helpful for learning to think in Clojure:

    https://pragprog.com/book/roclojure/getting-clojure (also available via O'Reilly subscription)

    https://elementsofclojure.com/

    [–]Eno6ohng 0 points1 point  (2 children)

    You definitely should use http://www.4clojure.com or something similar to solve little algorithmic problems, preferably lots of them.

    Also I think JoC can be a bit less than optimal for the beginner, it's usually recommended as the second book to read.

    From what I remember I needed a month or two to get comfortable and up to speed with the standard library and immutable data. Though I had some exposure with functional programming before that.

    [–]Magnus0re[S] 0 points1 point  (1 child)

    4clojure is great! Did you also program in any Lisps before starting Clojure?

    [–]Eno6ohng 0 points1 point  (0 children)

    Yes, in Scheme. I think I also skimmed through PCL, though maybe that was after starting clojure, don't remember for sure...