Is Clojure a good pick for me?

I’m a Go developer looking to be more productive. Go is really good, I really like the language, but the productivity is not that great. I’m looking for something better. I know a little of Elixir too and to be honest, Elixir almost checks all the boxes for me. But there is something that pulls me to Clojure :sweat_smile: I can’t explain.

Elixir:
+++ Supervisors
+ Erlang/BEAM integration
+ Immutable
+ Best async development in any language in my opinion
+ Predictable performance / preemptive scheduling
- Web development is mostly based on Phoenix and tied to frameworks, I do prefer libraries
- No CLI support
- "Slow"
- No JS compilation / WASM support

Clojure:
+ Lisp
+ JVM
++ Focus on libraries
- JVM
- Can mutate state
- Exceptions
- Syntax seems cryptic

Mostly what I do is backend development exposing JSON web services. But from time to time I would like to do CLIs too, which it’s possible with Clojure using GraalVM, right?

Sometimes I need to do the frontend as well. Today I would use things like NextJS but I’m not a big fan of Javascript and I think I’m able to do the same using Clojurescript, right?

The fact that Clojure has exceptions is almost a deal-breaker for me, I really freaking hate exceptions but I would like to hear from you guys.

So, what you guys have to say to me? I know that this is a bias place to get an opinion between Elixir or Clojure, but I want your sincere opinion.

And still at the Clojure part, what are the best books I can get? Development in general + web development. (It can be more than one, no problem with that).

Ahh forgot to say that I’m not a functional programmer, I do understand the things but never had done anything meaningful with it.

I love that you have “JVM” under both the + and the -! :slight_smile:

I’ve been doing Clojure for about a decade and I enjoy it more than any other language I’ve ever used (and that’s a lot of languages: I’ve been a professional programmer for close to 40 years now). Clojure brings me joy, every day, in a way no other language has.

To answer your questions:

  • I am almost entirely backend, producing (mostly) APIs and services – Clojure is a great fit for that.
  • Yes, you can build native images via GraalVM for fast startup utilities, but there’s also babashka which is built with GraalVM and implements most of Clojure and bundles several libraries to allow for shell/script programming with Clojure with fast startup (so you might not even need to use GraalVM yourself).
  • Exceptions are fine for exceptional situations: both the JVM and JavaScript have native support for them and they make a lot of sense for the right uses. You can (and should) use “error” return values for situations that are expected in my opinion (not exceptions).
  • Web Development with Clojure (3rd Ed) is probably going to be a solid place for you to start with web development but it is also pretty dense and makes a lot of assumptions, so you’ll probably want a more gentle introduction such as Getting Clojure or Living Clojure (I don’t have the latter but I hear good things about it; I have the other two and like them both).
  • Shifting to a functional mindset can be the toughest part of learning Clojure if your background is Java/JavaScript.

Join the Clojurians Slack and jump into the #beginners channel there and ask lots of questions – and you can get replies in real-time from beginners and seasoned veterans alike. http://clojurians.net to sign up, https://clojurians.slack.com for chatting. ClojureVerse is great for longer-form discussions (like your questions).

6 Likes

Clojure has been my go-to language for over 10 years and I’m still happy. I have certainly tried alternatives, and while interesting, Clojure remains my daily driver.

But from time to time I would like to do CLIs too, which it’s possible with Clojure using GraalVM, right?

Check out babashka if you just need fast-starting CLI scripts (milliseconds, like you’re used to from golang): https://github.com/babashka/babashka
Disclosure: I’m the author of babashka.

GraalVM can be the next step if your project is complicated enough.

Co-incidentally I just learned some golang over the Christmas break to write some extensions for babashka:


3 Likes

Nice! I’ll take a look at those libraries.

I love that you have “JVM” under both the + and the -! :slight_smile:

Yeah, I “like” the JVM. It’s a state of art VM but comparing with the BEAM it leaves a lot on the table. Erlang and Elixir are almost the same thing, the biggest difference is the syntax and we can’t say the same as Java and Clojure.

And I fear a little of this not ideal integration like, do I need to know Java to be a good Clojure developer?

Exceptions are fine for exceptional situations: both the JVM and JavaScript have native support for them and they make a lot of sense for the right uses. You can (and should) use “error” return values for situations that are expected in my opinion (not exceptions).

But exceptions are the default way of handling errors? Really, my head does not work with exceptions, they simply don’t make sense. For example, how do I know if I need to add a try catch? It’s the same in every language, we don’t know. We just gonna know when the server closes in production or you spend time looking at log files.

With Go for example I know exactly what operation can return an error or not because the language kind of forces me to handle the error case.

Web Development with Clojure (3rd Ed) is probably going to be a solid place for you to start with web development but it is also pretty dense and makes a lot of assumptions, so you’ll probably want a more gentle introduction such as Getting Clojure or Living Clojure (I don’t have the latter but I hear good things about it; I have the other two and like them both).

Thanks! I’ll take a look.

Shifting to a functional mindset can be the toughest part of learning Clojure if your background is Java/JavaScript.

Yes, this I’m aware of :sweat_smile:

Never used NextJS, but from a look at the project page, yes. ClojureScript is super strong for SPA stuff (but not really something to reach for when you just need some JS on some pages).

Generally, about being productive. Clojure is amazing for me in that respect. I have a hard time pinpointing exactly what that is about, but there is something with me being able to go directly at the problem and avoid the ceremony that I feel other languages force on me. I have to say TypeScript does a lot of that for me as well, but not at the level Clojure does it.

I think you should give functional a real try. You’ll reap benefits from it even if you later decide that Exceptions just make Clojure unusable for you. :grinning_face_with_smiling_eyes:

2 Likes

Returning errors as values is also something that is done a lot in Clojure btw. But being a hosted language, there are always exceptions.

1 Like

If, by “errors”, you mean “possible expected failures”, you would mostly handle those by returning error values of some sort. If you mean “possible unexpected failures”, those are “unexpected” by definition and therefore “exceptional” and throwing exceptions makes sense :slight_smile:

But I do understand where you’re coming from: Go forces everything into returning error values so you always know how to handle something. When you’re working in a language hosted on top of the JVM or on top of JS, you’re going to run into exceptions from things you call that are native/idiomatic to the host platform – but those should only be “unexpected” things. Unfortunately, the reality is that a lot of such libraries throw exceptions for completely expected failures in some cases :frowning:

I’ve always worked with exceptions (stretching back to my early COBOL days, and I’d encountered exceptions when learning PL/1 prior to that – PL/1 is considered to have pioneered exception handling in the '60s, and Lisp has also had something very close to exceptions since the early '60s). It’s an interesting world now, in programming, that folks can learn to program and get a software engineering job where they don’t need to learn about exceptions! Maybe one day we’ll look back on the long history of exceptions and wonder what on earth we were all smoking for sixty-plus years? :slight_smile:

You don’t really need to know Java (or JavaScript) to become a good Clojure developer but you will have to learn some of the basics of the infrastructure/ecosystem – and you’ll have to learn to read the unfortunately large stack traces that can appear when your code blows up. That said, while those stack traces initially look intimidating and the error messages may seem obscure, you quickly learn to skim them to pick out the useful bits and you learn what common errors (from the underlying runtime) actually mean in terms of your code.

4 Likes

I use Clojure because I find it more fun and interesting to program in. As a bonus, it happens to also be practical, robust, productive and safe; with great tooling, a huge ecosystem, reach to the browser, server, command line, and desktop/mobile, good performance, good scale, and an awesome community.

Because of that, for me, yes, Clojure is a great option for everyone, unless you’ve got reasons why you just can’t use it at all, like needing total control of memory, doing high performance graphic rendering or digital signal processing, targeting a platform which doesn’t support or allow it, needing hard real time guarantees, etc.

I’ve done a little Elixir (on my free time), and it’s also a pretty fun language to program in, which actually takes a lot of inspiration from Clojure. So I wouldn’t blame you for going either way. Now I’ll say that from a work perspective, there’s more places using JS or JVM where you can sneak in some Clojure, where as there’s a lot less places already running BEAM to sneak in some Elixir, and convincing a full platform change is much harder in my experience.

Another thing is your investment in Clojure will take you further in my opinion. From a learning opportunity, there’s more to learn from Clojure, as it can support more paradigms and language constructs/patterns. And you can reuse a lot of your knowledge of it towards most other Lisps: Emacs Lisp, Racket, Common Lisp, Fennel, Janet, etc. From a practical standpoint, it lets you reach further too, cause you can reuse a lot of learnings as well when you venture towards ClojureScript, Clojure CLR, Babashka, Clojerl, Ferret, which allow you to target JS, .Net, Unity, scripting, Beam, C++, etc.

That said, it’s not without its quirks. Like you said, due to the JVM, you need to deal with exceptions, and for now (until project Loom arrives), async is a bit more cumbersome, because most of the Java standard API has blocking or multiplexed APIs, not async ones. And then there are some specific Clojure quirks, like slow startup times, a few things with slightly unintuitive names like contains?, slightly tricky handling of unboxed math, subpar error messages, lazyness gotchas, terse documentation, lack of free tutorials and guides, etc. Also, Clojure hates ready made things, so not a lot of giant frameworks with the kitchen sync. Some people don’t like the Lisp syntax and can’t get used to it. And the lack of static types can annoy some people as well. Clojure is also heavily functional (Elixir too), and some people don’t like that and never get used to it either.

Finally, I do want to insist on the Clojure community being awesome. Something that annoys me a lot in other language communities is you’ll very often search for something, only to find answers that really don’t know what they’re talking about, yet are upvoted, top search result, and worded like they are the most knowledgeable person. People might say like… Well you shouldn’t do this anyways bla bla. Like I’m way past that point buddy, and I need someone with deep knowledge here, and Clojure has an overabundance of absolutely knowledgeable and friendly devs in its community. People with two digit experience in the field, that are passionate, and who have tried a lot of other languages, and not just superficially tried them, like they’ve been around, and they’re smart. You’ll learn a lot from them, and the topics discussed will always be informative and interesting.

This has a downside that, if you’re beginner (especially to programming), they might be too knowledgeable for you, as they tend to want to teach you the details and all as well, and they might sometimes skim over the “easy” stuff.

Well hope this helps you make a choice.

8 Likes

That’s it guys! Thanks for the answers. I’m giving Clojure a try. I was way more inclined to go with Elixir but Clojure has something that pulls me, even having exceptions :sweat_smile:.

I think I’ll go with the Getting Clojure: Build Your Functional Skills One Idea at a Time book like @seancorfields suggested. Any other books that I should be aware of? I’m the kind of person that really likes to dive deep when trying something new. I heard good things about the Elements of Clojure too.

I have an allowance to acquire technical books at the company that I work, so just throw more book recommendations :sweat_smile:


Never used NextJS, but from a look at the project page, yes. ClojureScript is super strong for SPA stuff (but not really something to reach for when you just need some JS on some pages).

I think this was the reason in the end that made me pick up Clojure.

Returning errors as values is also something that is done a lot in Clojure btw. But being a hosted language, there are always exceptions.

Awesome! Yes, for sure, exceptions exist in almost any language. Go opts to return values but there is panics too which are the Clojure exceptions. We don’t use panics there but they can happen when you do an invalid operation like accessing an array out of bounds.

But as you said that Clojure return values as well, what is the defualt behavior? To raise an exception or return an error? Let’s suppose you need to parse a string to integer but the string is invalid, you throw an exception or return an error here?

It’s an interesting world now, in programming, that folks can learn to program and get a software engineering job where they don’t need to learn about exceptions!

Indeed it’s amazing. To be honest, Go was the single biggest jump in quality at my apps since I started programming. I did some really some big projects that never ever had any kind of runtime error due to errors not being handled. Bugs? Sure, every app has them.

I hope Clojure provide me the same experience :crossed_fingers:

Clojure hates ready made things, so not a lot of giant frameworks with the kitchen sync. Some people don’t like the Lisp syntax and can’t get used to it. And the lack of static types can annoy some people as well. Clojure is also heavily functional (Elixir too), and some people don’t like that and never get used to it either.

To be honest, I think this is a bonus. I don’t like the big frameworks as well and we don’t have them on Go. When I was doing Elixir most of the time I was doing the web stuff directly at the Plug instead of using Phoenix which is built on top of Plug

2 Likes

I heard good things about Getting Clojure, Programming Clojure and Elements of Clojure. I also think they complement each other, from what I heard. Getting Clojure is more introduction, Programming Clojure goes in more details, and Elements of Clojure is more phylosophical (design/structure of code). That said haven’t read them.

I do personally recommend Clojure, The Essential Reference. It might not be best to learn Clojure at first, but once you know it somewhat, it’s great for deep diving further into every aspect of the core language.

I also really recommend at some point you read through the official Clojure overview, reference and guides:

And as a super quick intro like I want to get going in 30 minutes, I recommend the following small blog series:

It really depends, you kind of do whatever you want. Some people prefer throwing exceptions and use those, some people prefer returning errors (of various forms, could be returning exceptions as well, as opposed to throwing it).

That said, you’ll interop with Java a lot, and a lot of core functions are themselves just wrappers around Java, and Java will default to always throwing exceptions. That forces you to deal with this reality. Most popular libs I know of to do that are https://github.com/adambard/failjure and http://funcool.github.io/cats/latest/#exception

So I’d say there’s an even mix of both.

I also want to say, I personally like thrown exceptions, I think a lot of programmers maybe don’t understand them, but they actually derived from the issues that return errors used to have. For keeping some code pure, you’ll need to return errors sometimes, but for impure code, exceptions are so much nicer I find. Letting you easily pick exactly where in the stack is most appropriate to retry, recover, log or publish a metric without poluting every function up the stack.with error branching, short-circuiting and re-returning. And exceptions capturing stack trace come in super handy for debugging, there’s so many times I wouldn’t have been able to find the root cause of an issue without the full trace.

But you need to follow this pattern to use them effectively:

  • Every single procedure and function checks the sanity of its arguments and refuses to continue when the arguments are unreasonable, jumping out of the function.
  • When calling out other functions, program functions only check for errors if they are in a position to react meaningfully.
  • Error handling occurs at higher levels of function call chains, wherever it is meaningul to do so.

From: Exercises in programming styles book.

Just my 2 cents.

P.S.: In Clojure there’s also the condition restart way of handling errors such as with: https://github.com/clojureman/special

1 Like

Also: The Joy of Clojure (2nd Ed) for the “why” of Clojure and to help you “think idiomatically”.

1 Like

If you use interop with Java – Long/parseLong – then you’ll get an exception but you can always choose to check the string’s format before the conversion, or you can use a combination of, say, Clojure Spec and something like spec-coerce or exoscale/coax to provide a non-exception approach to value coercion and validation (which is the approach I prefer).

One pattern you will see in some Clojure code is (try (..) (catch Throwable _)) which will give you nil (Clojure’s universal failure/no-such-value) if the underlying code threw an exception, else the actual value. That would typically be wrapped in a small function and then the code that uses it will do something very Clojure-y:

(if-let [v (process-something x)]
  (do-something-with v)
  (unable-to-process x))

(if you only need pass/fail and nil isn’t a “real” value in the problem domain – which covers a lot of cases)

1 Like

Take a look at https://practicalli.github.io/clojure/ which covers a lot of the development tools available for Clojure.

I would also recommend using Clojure CLI tools to manage your projects, although the code is the same if using Leinigen.

This might seem like hyerbole, but it’s something that I felt myself, and then I started seeing others saying it, and I realized it wasn’t just me. Clojure is just fun. Of course, a lot of programming can be fun in nearly any language, but for me it’s more fun with Clojure than in most languages I’ve used.

How can that be? It’s just a programming language. It doesn’t say interesting things to you or throw a ball or purr or make pretty pictures (unless your code does). It doesn’t write your code for you (which wouldn’t be that much fun, anyway).

I think that at least part of the reason that Clojure is fun is design that makes different functions and data structures to operate together in ways that are natural and convenient. There’s a lot of that, and you can do a lot with the pieces that are designed to work well together. As a result, once you get used to Clojure, many routine tasks are easy, trivial, and the resulting code is easy to understand. That’s fun.

So it’s not just that Clojure is fun. The fun is tied to useful functionality, which makes you more productive.

5 Likes