2 years of Clojure, and it still isn't clicking. What am I doing wrong?

So I’ve been using Clojure professionally for about 2 years, and played around with it quite a bit before, but I still haven’t had it click where it is intuitive and incredible to work with like everyone always talks about, even co workers. What am I doing wrong, or what can I do, or what should I do? To be honest i’m lost, and I am an experienced senior dev.

Thank you.

2 Likes

Not enough context to provide useful advice IMO (at least not tailored advice). Need to know what you are doing to try to inform what you may be doing wrong… Sample repos / code you can share, delimited repetitive pain points, and things you have tried (or failed with) would be helpful. Prior language background also helps compare/contrast experiences.

I’m curious about your workflow and use of the REPL, as well as how proficient you feel with what proportion of the standard library.

It’s a large re-frame application, and in the past years I’ve used Javascript, Typescript, Python, Java, Lua, Go, quite a few.

It’s still not enough. Given that little bit of context, the only specific thing I can ask is whether you have read the whole re-frame and perhaps Reagent documentation.

But there are also some generic questions:

  • What do you struggle with the most when working with Clojure[Script]?
  • What do you dislike the most in the language or its ecosystem?
  • Have you tried pair programming with your coworkers that seem to like Clojure? Or maybe with other people that definitely like it?
  • Have you tried creating a web app from scratch?
2 Likes

I would say I mostly have trouble with reading and understanding Clojure code quickly, coming up with Clojure idiomatic solutions, and editing it. I use neovim.

I have created many web apps from scratch with it and watched others as well.

Do you know the standard library well enough so you don’t have to look most things up?

If you don’t, you should definitely memorize the most frequently used vars.
If you do, I’d say it’d still be useful to go through all the articles in the Getting Started section and the Reference section of the website.

Given your familiarity with other languages, another potentially useful thing to do to make it “click” is to go through all the pages in the Clojure category on the Rosetta Code website and compare the code to one of those languages you’re familiar with. Quite a lot of work so I’d filter out any examples where the code in a language you’re comfortable with isn’t obvious after half a minute of staring at it.

And if nothing works and there are no more ideas on what to do, it might be that your brain is somehow stuck in the “ALGOL family” of programming languages (all the PLs you have listed are very similar) and for some reason only looks at other PLs through the lens of all the existing experience. If that’s the case, you’ll have trouble getting comfortable with any language that doesn’t adhere to the approaches familiar to you (examples from the linked article: Racket - other Lisp, Prolog - a logic language, Forth - a stack language, APL - an array language, Haskell - a functional language). Sounds bleak and I don’t know what to do here apart from keeping banging your head against all the new stuff till your head finally concedes and starts taking it all in, if ever.

1 Like

I would say I mostly have trouble with reading and understanding Clojure code quickly, coming up with Clojure idiomatic solutions, and editing it.

I think it helps to break down Clojure into three categories:

  1. (Pure-ish) Functional Programming

I know a lot of people, it takes them a while for this paradigm to click. Because you are often tempted to organize things as classes and objects, or interfaces and methods. And it’s also hard to figure out how to perform operations when you can’t do imperative loops, and if/else branches, and all that.

I would go read on that, and practice exercises here: https://4clojure.oxal.org/

Once you know how to perform operations using map/reduce and recursion, without mutable state, and have learned about the higher order functions like filter, remove, partition, group-by, juxt, fnil, and all that, it should start to click.

Also, learning how to structure code functionally, how to manage state, side effects, break things down in an Onion/Clean architectural style, model entities with functions that operate on them but without classes and objects and all that. I’m not sure of a good resource here though.

  1. Interactive Programming

You start the program with an empty template, and you build it up as you go, loading code in one function at a time, reloading as you iterate on each function, etc. All from inside your IDE, connected to live resources the app will be using, etc.

Getting used to REPL-driven-development basically.

Again, I’m not sure of good resources. But this is another aspect that should eventually “click”.

  1. Lisp

Figuring out how it’s all based on very simple syntax and initial rules, and it builds up to complex semantics through macros. Getting to read code bottom up, and inside out. Learning how to navigate and edit s-expressions quickly using semantic editing. Learning how you can create new syntax and new semantics to help you get rid of verbosity and repetition in your code by adding macros, or producing data based DSLs. The latter should make you learn about homoiconicity and why that makes things easier to inspect, and helps with building DSLs both data-driven or macro based.

This should also eventually “click”.

Those three things are orthogonal, but come together nicely. They each take their own getting used too and “ah ha!” moment though. I think it’s easier to tackle them one at a time.

3 Likes

It took me longer to learn Clojure than any other programming language, and I’d had a little Lisp experience beforehand (a gateway, of sorts, I guess).

I learn well from books and started with the Joy of Clojure, which might not be a good first book, but it kept my interest up to continue going deeper and deeper. But what really helped it click was doing almost all of the 4Clojure exercises (now at https://4clojure.oxal.org/)… and then doing them again. The second time through I was amazed at how much I’d learned – the solutions tended to be shorter, more functional… more beautiful. Looking at other solutions can help. As other respondents said, the functional paradigm shift is hard to get your head around, but once it gels, it changes everything.

Your mileage may certainly vary. One more aspect is using Clojure for professional development. Having gotten hooked on the language, I did somewhat of a career pivot and did eight years of professional Clojure development. It was a decidedly mixed bag (mostly because of the local corporate microclimates involved) and I’m currently taking a break from professional Clojure development, though I still use it for creative/hobby projects.

I offer that last bit of context because sometimes it’s not the language or the tooling but the environment that is getting in the way of learning and enthusiasm. I will say that, as a senior contributor, having one or two developers skilled enough to challenge you and to learn from can also be energizing (I’m looking at you, Ted :slight_smile: ).

Best of luck to you!

6 Likes

The question is: Does Clojure solve a problem you actually had before? If you’re happy with Python, Go, JavaScript and whatever you’re using so far, Clojure probably rather imposes further restrictions on you than freeing your thinking.
When I first looked at Go (coming from Java), I loved the way in which I can express relationships between things statically, i.e. as (nested) literals (slices, maps, structs). I also love maps, and in Clojure you’re dealing with maps all the time, which I love! Other programmers I know hardly ever use maps, and I wouldn’t waste any time showing them the beauty of Clojure.
I also struggled a bit with Clojure, having made two attempts (separated by one year) to really get into it. A year ago, I decided to work through Structure and Interpretation of Computer Programs (SICP), in order to really understand recursion. The first three chapters were an absolute revelation to me, and coming back from Scheme to Clojure now seems like coming home, but to a home that is vastly more convenient than anything before.

4 Likes

I agree! However, I would like to remark how important it is to separate learning Clojure from learning functional programming. When your background is in OOP and you start to learn Clojure, you will have to struggle with both. It will help a lot if you focus first in learning functional programming principles until these ideas click.

1 Like

That’s a good idea. However, you have to learn functional programming using a functional language. Of course you can start using apply, filter, map, reduce and the like in a language like JavaScript or Python. That will shift your thinking about programming towards functional programming. SICP worked well for me, because you use such a tiny subset of a rather small language to grasp recursion and other functional techniques.

I think this (CLJs) is the main issue. For me, developing a server side Clojure application is much more pleasant than client side CLJS with reframe. The workflow is a lot more straightforward.

Maybe you are overwhelmed by the concepts so it is hard to make progress. It could be worth stepping back a bit, and building your own toy backend from scratch to get a feel of how everything was put together. This may give you the confidence to dig in and continue.

2 Likes

I’d say that is normal, especially as a an experienced dev. All the languages you worked before have an entirely different view of the world, so Clojure will look Alien and unintuitive for quite a while.

For me personally Paredit, Host Interop and the CLJ+CLJS combo is what made everything click for me. So, if you are just doing re-frame frontend you are likely missing two of those. Do you use Paredit? I don’t know if neovim supports that, but for me it was absolutely essential to learn it. Before I did the syntax was weird und clunky, after struggling through learning it everything else is now weird and clunky. It was a struggle, and I needed more than one attempt but it was worth it. This is of course very subjective, everyone will have different experiences and what made it click for them.

Another thing for me was that even after it “clicked”, it took several years to unlearn everything I was taught was best practice before. I can’t remember how long it took until I was comfortable and more productive than what I had been doing with Rails or Java for 10+ years, but it was several years. It also sort of helped to do an absolute deep dive and not work in, or even look at other languages. Once I had migrated everything to CLJ+CLJS everything fell into place and I have never looked back and it just kept getting better.

Don’t forget to manage your expectations too, CLJ+CLJS are tools, not enlightenment. If you feel more productive in other environments that is completely fine. This is not a religon, even though it might be for some. It is fine and useful to have multiple tools in your repertoire.

6 Likes

I’m busy reading the book “Data-Oriented Programming”, by Yehonathan Sharvit. I think it’s particularly useful for people coming from an OO background that want to get into functional programming. It’s not Clojure specific though, but that does not matter, since Clojure is the perfect language for the kind of design that the book proposes, since a lot of the concepts that the book presents are embodied in Clojure.

3 Likes

Functional programming is closer i think to the way we reason(if you see lisp’s history it was used on symbolic AI), nested function calls, until the final result.Imperative programming is closer to the way we act, we keep state and based on it decide our actions.Both can be done with either languages, but for some people one of those is more natural.

Clojure with its lisp tree syntax, allows natural nesting, either bottom up, or up to bottom with macros like → this makes clojure so good on supporting nested function calls, for programming or data processing.

If you were new in functional programming, maybe it would take sometime to know if it fits the way you think, but 2 years seems alot, but if you have done imperative programming for decades maybe its not.

I think Clojure people are so excited because Clojure fits the way they think, at least thats why i always liked Clojure, when it clicks you never go back.
The rest are very important also like the fact that clojure is simple practical runs on jvm, compiles to javascript also etc, but if it doesn’t fit the way you think it will not be fun.

1 Like

First of all, thanks for sharing your struggles! That takes some courage. There is some excellent advice above, though it is hard with so relatively little context. It might be that your brain simply isn’t wired for this, and that is fine.
If idiomatic code / FP is one of your challenges, then https://grokkingsimplicity.com/ is IMO an excellent and highly accessible book.
Good luck!

3 Likes

+1 for Grokking Simplicity. That’s the book that made FP click for me. It’s had a big influence on the way I write in other languages and naturally fits the Clojure model.

so if it starts clicking, are you going to change your username?

The free Functional Programming Principles in Scala course at Coursera really helped me get into functional programming coming from Java. It was an eye opener in regards to recursion and immutable data structures.

1 Like