I'm an advocate for Clojure, and while I believe that the usability speed bumps are more than made up for, I completely agree with you. The awkwardness of Clojure's errors, REPL experience, and build tooling is a dealbreaker for many.
A couple years with Rust has taught me that intuitive errors and tooling will funnel you far enough into language to get you productive, and then you're much more likely to stay. There's just no way I would have stayed long enough to be a Rust professional if it hadn't been for cargo and rust-analyzer.
These "non-language" components of Clojure are just not easy enough to use, and its inhibited Clojure's growth. If, however, you do put in the time to grok these parts, the joy of using the language itself never fades.
Nice article in general, but seems to miss the most important point (at least for me) of why Clojure (and similar languages) are way better than anything else today: it's REPL driven development. Definitely more important for me than any of the other "why we love Clojure" points.
As long as Rust doesn't offer something similar as the REPL driven development Clojure offers, there is zero reason of preferring Rust (for me) over Clojure for the same tasks. Which, because of the last point ("Rust is not homoiconic") won't happen any time soon.
Now, if you need to do embedded system development, Rust might make more sense than Clojure, but it won't replace Clojure for the same tasks today.
It's an interesting idea, but the fact that the Rust compiler is an AOT compiler with an extremely minimal runtime makes it seem like a poor fit for Clojure which is very much an interpreter/REPL-driven language.
Am I missing something here? The experience is basically the same as the best available in JavaScript/TypeScript, how is it "nastier" or even "nasty" at all?
Also Clojure is doing just fine, not sure what you mean by "dying". The core and the tooling continue to improve, there are lots of libraries, more people writing than ever. I just don't see this death you're describing.
The comments here just strike me as ignorant and incoherent as a whole. Why do people who clearly have no experience actually trying to do something in Clojure have so much to say about it?
Clojure may support things that look daunting to you, but if you actually had any goal other than critiquing the variety of things you actually have no use for, you would not have the difficulties you describe.
Maybe I'm spoiled, I remember JDK setup being a pain on Windows a decade ago when I used it last, if that's the problem then I get it. My spoiled experience on a system with a functioning package manager is basically install-and-go, and
zero configuration required to get CIDER going after that.
I just don't get what's so bad about it, it's basically the same experience as Rust with Cargo; is that another "nasty" experience? What language with package manager has a better experience?
I think it comes down to the specific codebase for the Clojure version vs. the Rust version. In this case, after rewriting the code into Rust it was easier for the author to understand and reason with.
Not that you can't do it in Clojure or any given language.
In the end, they're happy with Rust. I really like what little Rust I've done. I still reach for JS/Node first only because I can get something working faster often because of what's in the box and in npm. It's far from the most performant, but often fast enough. C# tends to be my second level, though as I become more familiar with Rust, it may displace this.
You can't be an expert in everything and sometimes a given language will lend itself to the way you think in idiomatic terms.
The article is an anecdote on a personal experience, not an assault on Clojure or the ecosystem. Even if it is critical at a couple points.
I've been trying really hard to get into Clojure as a full stack dev, but this has been my experience as well. Building a simple crud app has been a nightmare. I find that:
- The debugger sucks
- There are other tools for debugging like Portal and Flowstorm, but they involve already knowing what the problem was so you can instrument the function and call it with the same arguments
- Java stack traces make the above very hard to do.
- You're a second class citizen if you don't use emacs. Half of Clojure devs are using the EMACS according to a community survey. Calva, the VSCode extension, does lots of automatic setup to make the REPL work, and when it doesn't work, you have no way to fix it. I have to restart the REPL a lot, which I'm told is the opposite experience I should be having. It took me days to set up a project just so my REPL would switch from Clojure to Clojurescript when I evaluate in different files, and everybody I asked about this didn't understand why I would need it because they were all using emacs.
- Complaining about Javascript and React and then having your whole ecosystem wrap around Javascript and React is really obnoxious. Reagent is falling behind in React versions and it's missing out on performance enhancements. If you need to do niche React things, it's a pain in the ass.
- This might just be me, but I used Citrus with Rum and I found it to be the most over abstracted thing I've ever seen in my life. I know it was inspired by re-frame, so maybe re-frame is the same. But it's like Redux X10 in terms of verbosity.
- Call me crazy, but the Java interop is worse than other guest languages because there's huge impedance mismatch between functional and OOP.
- There are very popular broken libraries. People say "It's okay if a library hasn't been updated in 6 years, because Clojure is so stable!." This is a total myth, there have been several flat out broken libraries being recommended in tutorials.
- While people are working on frameworks (Biff, Fulcro), there are no "best choices" for a lot of problems yet and it leads to frustration just trying to make a simple crud app.
The community hasn't been unfriendly or unhelpful, but sometimes it feels like I'm speaking to aliens.
I feel the same way about Clojure. For a LISP, where interactive development via the REPL is supposed to be one of the value-add of the language, it falls completely short in that aspect. They even have entire libraries and design patterns (Component, etc.) to work around the issue, but I find it ridiculous that your entire program structure is dictated by the fact that the REPL boot up time is too damn slow.
I'll second that the popular tooling, while powerful and reliable, its just not user friendly.
The official Clojure CLI, for example, is just plain confusing, and that's most people's first impression to the entire ecosystem. The config files, while they use the wonderful `.edn` format, are also not intuitive. Newcomers are the most likely people to encounter the most amount of error messages... which are famously difficult to read.
And that's before you even get into REPL configuration, which involves coordination with your editor process, a client process, and a server process. Even if you have a tool like Calva or CIDER managing it for you, you'll still get confused when something goes wrong unless you grok all the moving parts.
Even if you figure that all out, you still don't have Parinfer or equivalents setup yet in your editor. Also, clojure-lsp tends to require some configuration to get working the way you want. And that's before you get started with ClojureScript, which brings the complexity to another level entirely.
Despite all this, I love Clojure. It's an expert's language, even though it shouldn't have to be. Once you learn this stuff, you respect why much of this complexity exists. It's inherent to the amount of power the language gives you.
But doesn't mean we can't make it easier to use and get started with.
Right, I read your point that readability is as important to a language as other things.
But Rusher isn’t saying “use Clojure because it’s ahead of time as opposed to Rust/Go”. He’s making a point that some (often more niche) languages have built-in features that are better suited to what most of the development work is - debugging - and other languages should look to adopt them.
Clojure is wholly inadequate to meeting challenges of the industry today. Not just because it's dynamically typed (which means tooling for it is close to nonexistent and it has terrible performance), but also because its ecosystem is a ghost town.
It takes more than just a language to create a productive development environment in 2020, especially one which is so flawed by designed to the point of not even being statically typed.
My biggest problem with Clojure (specifically ClojureScript) is that it's too workflow opinionated. Nearly all Clojure devs use 1 of 2 text editors. Nearly everyone uses Leiningen. Nearly everyone uses some sort of auto-builder. Nearly everyone uses hot-swapping.
Clojure wasn't even optimized for this workflow, it's just the only one that works. So as much as I love the language I keep going away from it because I prefer the freedom of my own workflow.
You're definitely right, and from my experience the community has no interest in actually making the developer experience better. It's one of those "the first step to fixing the problem is admitting you have a problem" situations and for the most part the Clojure community can't even admit how bad their tooling is, they'd rather shift blame to the users and pretend that if you can't figure it out it means you're not smart enough to be using it.
I find Clojure is a lot more approachable if you start with Clojurescript / Reagent and go from there. You don't need to be running Clojure on the backend to make use of how awesome Clojurescript is, and it's about 10x more approachable.
I don't think anyone who uses Clojure in anger would put it on the same level as JavaScript when it comes to letting through a ton of runtime errors. The integrated tooling around editors, clojure.spec and the REPL is very good at curtailing the downsides of dynamic typing.
Rust and Clojure address completely different domains of problems.
Rust is competing with C++ for writing low level systems, whereas Clojure is designed for writing business applications.
Low level systems tend to have stable and well understood requirements, whereas the same cannot be said for business applications. Efficiency is not a primary concern of business applications, but flexibility is. The efficiency of Clojure is often "good enough" for business application, and there is no peer in flexibility. This explains the many fintech companies using Clojure, as well as many other B2B companies.
Been using Clojure professionally for 9+ years now and while I'm thankful that I can make a living writing the language and using Emacs all day, I've found these points to be spot on.
These issues have added noise/confusion to what used to be a much simpler ramp-up for new developers. For those who've been around for awhile, the overall experience definitely felt cleaner previously, with more obvious best paths. While it's hard to argue against more options, the effect on the ground is that it's also needlessly divided the already small community a bit too.
I agree with the sentiment and I don’t use Clojure as much as I did, partly for that reason.
I do recall Clojure/Quil being faster than Rust/Nannou in terms of the feedback loop, because once you’re running a REPL and you start to change and tweak things you can re-evaluate them live in the context of the running sketch.
Neither offers as fast a feedback loop as JS/P5.js, though, and for me Quokka gives much of the benefit of Clojure’s REPL but with less setup, faster boot, and consistency between editors.
By using Clojure, you’re missing out on reliance on poorly maintained ffi libraries, a messy library ecosystem where you get randomly surprised by side effects from mutability where you weren’t expecting it, and a poor build system.
I love writing CL but there’s a reason it’s not enjoying wide usage nowadays, and I definitely wouldn’t go around recommending it to unsuspecting people without heavy caveats.
I'm explaining to you why Clojure won't reach mass adoption. I could offer you a long list of situations for which slow startup is a PITA and you would rebut my points by offering workarounds and I would rebut yours by showing why the workarounds are ineffective, and so on, but it would be waste of time. Users (me included) don't want to have to adapt to their tools. Tools that require users to adapt won't be popular. Perhaps you don't get it, but this is reality.
The problems you listed are about ClojureScript. I agree the ergonomics are still behind JVM Clojure, but then again the competition is significantly worse too in the JS space.
And if you end up concluding some other front-end language is better, Clojure is still a really good choice for the back end.
No, you are missing the point. Slow startup and long compiles is a hindrance to all kinds of development. You can ask developers to adapt and use a long-running repl, but they won't. Complain all you want about drama and how stupid people are, they still won't choose Clojure.
A couple years with Rust has taught me that intuitive errors and tooling will funnel you far enough into language to get you productive, and then you're much more likely to stay. There's just no way I would have stayed long enough to be a Rust professional if it hadn't been for cargo and rust-analyzer.
These "non-language" components of Clojure are just not easy enough to use, and its inhibited Clojure's growth. If, however, you do put in the time to grok these parts, the joy of using the language itself never fades.
reply