I've been running my business for 10 years now, relying on Clojure and ClojureScript. It is amazing to be able to base one's livelihood on a foundation that is so stable and well designed. Clojure has been designed by a very smart and very experienced person, and it shows. It has then been maintained and extended by a team built around a culture of maturity and stability, and the result is something you can rely on.
The fact that I can use the same language to develop business model code that runs on both the client and the server, or that I don't have to use a different on-the-wire format for sending data between them (EDN does the job great) is just icing on the cake in this context.
I am very thankful to Rich and the entire Clojure (and ClojureScript) teams for giving me access to all their work (for free!).
BTW, if you haven't seen any of Rich's talks, go see them — they are worth it even if you do not intend to use Clojure.
Rich's talks have been the apex of my programming career. I didn't like sitting in front of a computer to the extent needed to make a living from it, so I moved on to another industry. And maybe I wasn't smart enough to become competent in Clojure. But I'm thankful for the eureka moments that Rich offered me. He's such a beautiful mind.
I would love to use Clojure but there are basically no jobs in my area with the language. Seems like the Nordics like Clojure but I'd need to move.
The very good backwards compatibility is attractive but as the result of the small community, there's also a lot of abandoned packages and fewer QoL packages (formatters, linters, etc); I know there are some but for example I had setup `cljfmt` in Emacs and it wouldn't work, didn't look further.
VS Code and its forks (Cursor, Antigravity, etc.) have Calva, a fantastic REPL with excellent linter Kondo. These are amazing tools; formatting is the very least of it. You don't need Emacs. I personally using VS Code + Doom Emacs. Also, many packages that look abandoned are simply mature. You can literally use ten year old packages.
I'm not a hot shot programmer, entirely self-taught but a decent architect who thinks hard about problems, and with LLM agents Clojure shines for me. There are some fantastic databases also starting with Datomic -- free now thanks to Nubank -- and everything inspired by it and the Clojure flavor of Datalog. These include Datalevin, Datahike, DataScript, XTDB. Datomic itself is probably best for enterprise though there's now an embedded version.
But I'm pretty convinced that most LLMs I've used are more reliable with Clojure (and Elixir) than with most of the popular languages, and I can say they use Datalog extremely well, seemingly much better than SQL despite the vast difference in corpus size. For one thing Datalog just gets rid of joins issues.
cljfmt is included with both Clojure-LSP and CIDER, so if you have either installed it should work out of the box.
With LSP mode the standard `lsp-format-region` and `lsp-format-buffer` commands should work, and on the CIDER side `cider-format-defun`, `cider-format-region` and `cider-format-buffer` should also invoke cljfmt.
I'll add a note to the cljfmt README to tell people about these commands, as your experience shows that it might not be obvious to people that they likely already have access to cljfmt in Emacs as a result of using LSP or CIDER.
There are still Clojure remote positions. Thankfully, I have used Clojure professionally long enough that my core ability shouldn't atrophy too much now that we have moved away from it at my current position. I am looking forward to Jank actually.
There were multiple reasons at our company -- my particular team, all skilled Clojurists, decided to default to python last year for a variety of reasons including both AI code generation suitability and AI model utilization in our code bases; the latter is of high relevance for our particular work. While I find Clojure to be among the best languages for interacting with LLMs via API, it is awkward for interacting with local models directly. Of all on the team, I was probably most open to a polyglot approach.
Incidentally, I am having great success using AI with Clojure. In fact, from what I read online, better than most. I'm not sure if it's due to Clojure's terseness (and hence, token economy), or other reasons, but it works very, very well.
Simple Made Easy[https://www.infoq.com/presentations/Simple-Made-Easy/] in particular had a huge impact on the way I think about writing software at a formative time in my development/career. I have not had the chance to use Clojure professionally, but thinking about software in terms of "intertwining" is the idea I return to when evaluating software designs, regardless of technology, and gave me a way to articulate what makes software difficult to reason about.
I’ve been writing ClojureScript now for around a decade. I tried to get into Clojure many times, but as someone with no Java experience, the JVM really makes it unbearable. I ended up trying Elixir though and absolutely loved it.
Both Clojure and Elixir really changed the way I think about programming. They’ve both basically ruined me as far as other languages go. Structural editing + repo driven development in Clojure, BEAM + pattern matching in elixir.
But there is something just infinitely more fun about writing Clojure code, and insanely satisfying. I’m eagerly awaiting the day that jank takes off and I can start building native mobile apps in Clojure (and who knows, maybe some web backend tech stack will spring up around it!)
I feel like calling Janet "A Clojure" is doing both a disservice. It's more like a "Clojure-like but smaller on purpose" programming language, and it's also (self-described) for "exploratory programming, scripting, and fun side projects" rather than Clojure's intended target audience.
Nothing wrong with that, having different target audiences makes sense and is probably preferable, but Janet is more than just "Clojure without the JVM" much like C# is more than just "Java without the JVM".
Every time I write another DTO → domain → DB mapping layer in Kotlin/TypeScript, I think about Clojure. I’m pretty grateful I learned it. It really changed how I think about software. Still, it’s a trade: less ceremony, more responsibility.
Clojure is very enjoyable if you respect the practices encouraged by Rich Hickey.
I've worked with Clojure in a number of companies, it's an elegant language and a thing of real beauty when done well, but it's not so much fun when you're working on a codebase that doesn't respect the philosophy of avoiding breaking changes; especially when these breaking changes are done in library code, and where a more liberal approach has been taken when it comes testing.
"less ceremony, more responsibility" is a good summary, in a larger codebase a bit of ceremony is not always a bad thing though. I'm also glad I learnt Clojure, it made me a far better programmer.
Kudos to Mr Hickey, I'm looking forward to the documentary.
Clojure is the language that made me "understand Lisp", as originally stated by Eric Raymond and citet by Paul Graham: https://paulgraham.com/avg.html
It seems like a small thing, but Clojure's choice to open up for other types of parentheses made seeing the structure of lisp programs much easier. This helped me understand how code is data and how macros are functions that can transform both code and data.
An important design philosophy (which is also hinted at in the trailer) is "simplicity". Clojure is designed to give you the tools to build simple solutions to the problems that you want to solve. It approaches mutability, which is one of the key sources of complexity in programming, with immutable data structures. It's a really clever way to do functional programming where your data is copied a lot but the copies are lightweight.
I don't write Clojure any more these days. I'm mostly doing Rust. But it is true what Eric Raymond said: Lisp has made me a better programmer.
Lisp philosophy is all about inventing languages (libraries), creating abstractions for each problem. Clojure is all about using primitive data types and maps everywhere explicitly.
> virtually all abstractions are built on top of primitive data types
Obviously. The point being made is that the Clojure style discourages building DSLs and the like and prefers to remain close to Clojure types and constructs. It departs in various ways from traditionally Lisps.
DSLs typically involves constructing macros that are domain specific (to cobble together a domain specific programming language on top of the host). Most of the linked examples are not macro based and are the exact opposite. They specifying domain specific data layouts built directly using the Clojure-native immutable datatypes. They don't create Domain specific datatypes or function-generating wrappers. It's just rarely necessary
A good example is making GUIs in Clojure. At first there was a cool macro based system called `fn-fx` that maked a JavaFX GUI. Then vlaaad wrote `cljfx` which just used plain Clojure maps and removed the macros entirely. This increased the boilerplate a tiny amount but made the system much more flexible and extensible
> DSLs typically involves constructing macros that are domain specific
a DSL is a constrained language for expressing domain concepts.
in traditional Lisps they are often syntax-oriented, because code is lists and macros are a natural tool.
in Clojure, pervasive use of keywords, vectors and maps allows you to shift DSL design towards data interpretation rather than syntax transformation.
so in Clojure doesn't discourage DSLs - clojure practicioners simply prefer data-oriented DSLs to macro-oriented ones, mostly because they are easier to reason about and process with existing tools, while macros are used more selectively.
"DSLs" can both mean "Using the language's variant of 'arrays' to build a DSL via specific shapes" like hiccup in Clojure does, and also "A mini-language inside of a program for a specific use case" like Cucumber is its own language for acceptance testing, but it's "built in in Ruby" in reality.
Clojure favors the "DSLs made out of shapes" rather than "DSLs that don't look/work like lisp inside of our programs".
Yes, maybe that's the sort of DSL you're talking about, the other person mentioned "Clojure style discourages building DSLs" which I'm fairly sure to be about the other DSL and is also true, hence the whole "you're talking/reading past each other".
Only a few languages allow you to change a system while it is running (saving time on deploying new development versions and re-creating state) ... and have a recording debugger (saving time since you can inspect any part of a recording at leisure instead of accidentally passing the interesting spot and having to start over)
I hope more people get to experience this kind of joy :)
I am so glad that this has been made! And happy that it features so many familiar faces from the last two decades of Clojure. There is a lot more to a programming language than just the code committed.
Same! I think I acquired 2-3 books that I tried to slog through in order to understand Clojure, but never really clicked until I bought and went through "Clojure for the Brave and True", which somehow made it click. Also available for free online, highly recommend: https://www.braveclojure.com/
Clojure is IMO indisputably a good language within a certain scope, and especially relative to many other languages used in practice. However, I think it's greatest merit is not so much the language itself - and there is nothing especially innovative about any of its features per se - but that it introduced so many programmers to a more functional style and the selection of very practical features it includes (Java interop was a smart move, as the ecosystem is a major hurdle for adoption). Much of the fandom and enthusiasm IMO comes from the contrast between the other sorts of languages people use in industry - which traditionally are imperative - and this functional style. It is much easier to reason about functional programs than imperative programs where names can refer to one thing at one moment, and to another at another moment. Mutability really is bad and should generally only be used judiciously and in very confined and controlled contexts.
In my experience, while I have found Clojure enjoyable and practical, it is still a "dynamic" language. A good deal of run-of-the-mill programming can manage quite well with such a language, but as projects become larger, deeper, and more complex, the lack of static types really does become a cost and an impediment. To understand any function and what it expects, you often need to read a few layers in to find what exactly something consumes and returns. Types really are a boon in such code bases. Some may point to various schema libraries in Clojure. While these can be helpful, they are often comparably inscrutable in practice (both in terms of specification and the resulting errors) and really do not compare to bona fide types, especially with LSP integration. And when you model something using types, the code sort of just falls out of the type definition.
On the backend side, you start your server once, and whenever you change it locally, you apply what you changed directly to the running process, so you don't lose any state and without having to restart the server at all, so iterating on the program becomes very easy. Bugs are easy to track down too, as you can evaluate parts ("forms") of the program inside the process itself, debugging becomes a breeze.
On the frontend side, you have ClojureScript that basically enables the same but in a browser environment. Usually I have the browser on the right, my editor on the left, and whenever I "evaluate a function", it runs in the browser context, so again same thing; the frontend keeps the same state even after your changes, so no more "make change -> wait for compilation -> get frontend into the state that reproduces the issue -> output debug info -> make change again", you just change one part, see the page update and then continue changing.
If you've used React+Redux (or similar) before, it's basically that experience, but much tighter and together with code evaluation inside of the browser context. If I recall correctly, Redux was pretty much directly inspired by ClojureScript and Reagent in the first place, I think Abramov even referenced ClojureScritp/Reagent in the first Redux talk.
clojure itself is a joy to use, on the web or outside of it
BUT
it doesn't have the equivalent of rails, mostly because lispers are an opinionated bunch and can't come together to agree on how web development should be done
the frameworks that do exist are more of a collections of libraries with some plumbing to connect the dots
Which in reality isn't a problem, once you absorb the ideas of Clojure and try to apply them when using Clojure. Composition of well picked libraries beat batteries-included frameworks for most use cases, both short term and long term, at least in 99% of the cases I'm writing Clojure/Script code.
I think it actually is a pretty big problem. "Once you absorb the ideas of Clojure" takes months or years to fully get. Composing libraries yourself, like your comment says, requires that they are "well-picked". Stitching together separate libraries is really time consuming and a distraction from the project you're trying to build. It also results in pointless thrashing within a team as everyone has become personally invested in their own mosaic of hand-selected libraries for every little thing. By the time a beginner learning Clojure has researched and put together their web stack and got it all hooked up and is ready to start, the Django developer already shipped their project last quarter, iterated on it a few times, and is on to the next thing.
One big library/framework has huge benefits and network effects, from enabling a big 3rd party plugin ecosystem, to a deeper documentation literature (including paid courses, books, and AI). It means that there's less or virtually zero getting up to speed when changing from one project to an other. It means that the upstream framework team takes care of upgrades whereas you have to consider, when a new technology comes up, how to integrate this into your stack. There's a reason that Laravel, Django, Rails, and Spring each have thousands or hundreds-of-thousands of times more websites in production than all of Clojure combined.
At a meta/discourse level, I also find the Clojure community's tendency to constantly deny and downplay any criticism or even just issue that people face to be really frustrating and counter productive.
> By the time a beginner learning Clojure has researched and put together their web stack and got it all hooked up and is ready to start, the Django developer already shipped their project last quarter, iterated on it a few times, and is on to the next thing.
Yes, but this is intentional. Django developers are optimizing for "easy" which makes it fast to spin up project after project, Clojure developers are optimizing for "simple" which means way longer time to get the project of the ground, to nail all the design before things start to actually be put together, which makes it easier and faster to iterate on the same codebase after years of working on.
Ask the Django developer how easy it is for them to add features after a project they've done that approach with for N years, then compare it to a Clojure codebase, and you'll notice the difference.
Sure, I guess this is "downplaying" and "denying", personally I see people who disagree with me as people who disagree with me, that's fine, I thought that was why we were sharing our opinions in this forum in the first place. But anyways, if you're very deep into "frameworks are clearly superior in every case", that we disagree probably matters less. Best wishes regardless!
Rich's Simple Made Easy talk is really interesting and insightful and I still love it but I think now the distinction is brought out too often almost reflexively, and used as a crutch. Yes "simple" and "easy" are not the same thing, but nor are they opposites. Just because something is "not easy" doesn't mean it's "simple".
I think there are lots of well maintained Django projects. In fact, if I do a search on AI and on google for what one web stack probably has the lowest overall total cost of ownership including maintenance years down the line, Django usually is what comes up, without even specifically searching for/mentioning it.
> if you're very deep into "frameworks are clearly superior in every case"
This is a mischaracterization of what I have said, and is more like the extreme position that Clojure devs seem to take. The original commenter said that Clojure is wonderful, but it's too bad that [for the people who want it,] there isn't the option of a well maintained, all-in-one, batteries included framework. You deny that this is a problem, saying that actually a well-chosen set of libraries are superior (I guess in every case, because if not then it actually would be a problem sometimes).
In my experience, Clojure was a huge pain in the ass to get into, and there's a non-zero amount of community members that talk about it in nothing about aphorisms. I really wanted practical advice, but getting people to talk normally about it was an uphill battle. This made me almost quit several times. But it is a very pragmatic language underneath (which you've already mentioned).
But I'm not sure a framework is really going to change that onboarding process, or help with network effects that much. Elixir has a de facto framework, but it's barely more popular than Clojure. I mean, we had Leiningen starter kits and we have Kit. But what's confusing to me wasn't setting up a project, it was learning how it was wired together. Wiring small libraries together and just passing data can feel surprisingly leaky, and I don't really have to peak into the internals of Laravel the way I do Clojure projects.
I think Biff is a promising step in the right direction. I think the way it has wired things up is easier to follow. But for whatever reason, they made the choice to use XTDB as a default, which is a huge cognitive burden for newcomers. They have an article on how to use something else instead, but this is already getting out of the "it just works" territory if you haven't even learned Clojure yet. But the author is a really nice and talented person, and I am looking forward to seeing where it goes.
> I think there are lots of well maintained Django projects. In fact, if I do a search on AI and on google for what one web stack probably has the lowest overall total cost of ownership including maintenance years down the line, Django usually is what comes up, without even specifically searching for/mentioning it.
Having used Clojure, Laravel, Spring, and Django, I wouldn't touch Django again with a 10 foot pole. I don't know what you're referring to by "doing a search of lowest cost of ownership" but it sounds pretty unscientific. Anecdotally, I do legacy apps, and I have picked up people's Django apps, and I've never loved what I saw. It's a classic fast to start, slow to maintain framework. Huge businesses have been built on it, but huge businesses have been built on everything.
> I'm not sure a framework is really going to change that onboarding process, or help with network effects that much
having one commonly accepted and recommended way does improve onboarding, because it collapses the decision space beginners face. right now they are supposed to make decisions (not even directly, but just through selecting one of the many frameworks) about things like:
1. which project templating tool to use? (lein, clj-new, neil)
2. which dependencies management tooling to use? (lein, deps)
3. which build tooling to use? (lein, tools build, boot)
4. which web server? (jetty, httpkit, undertow)
5. which routing library? (pedestal, reitit)
6. which templating engine? (hiccup, rum, selmer)
7. how to deal with javascript and it's build tooling? (clojurescript with a host of it's own decisions, bolt ts/js and wire it yourself, dodge that completely with htmx)
whats worse - most of the alternatives overlap in various ways, so making the "best choice" in order to reduce future headache induces quite a bit of anxiety.
yes, multiple frameworks exist that make those choices for you, but then you inevitably hit the problem that some of the components haven't been updated in a while, so documentation is out of date and when you try updating it just for your project you need to fix the framework plumbing and due to number of frameworks, the corpus of useful information on the internet is quite fragmented and the community help is limited, and on and on.
none of this is good beginner experience.
and don't get me wrong, choice by itself isn't bad, focus on composability of smaller libraries is important, dominant framework is not going to improve anything when it locks people into bad decisions.
what we lack is convergence behind a single "reference stack" of libraries that ought to be good enough for the general case and a minimal framework of plumbing that doesn't require dozens of files just to get started.
there doesn't need to be a single way of doing it, but there needs to be a single recommended way of doing it.
The fundamental mistake of Simple Made Easy was how many people interpreted them as orthogonal (or even opposing) qualities, when that's not inherently true.
This led to a lot of Clojure code being simple, but avoiding the hard additional work of also making it easy, and sometimes in even making it complete.
The prime example was tools.deps/deps.edn. It largely supplanted Leiningen for new code, but by being simple and minimal, it led to an explosion of ad hoc, custom tooling for 2-3 years afterwards, as everyone rewrote functionality that Lein already had, but tools.deps was missing. (And I say this as someone who once lost a whole week debugging a subtle maven/lein set ordering bug.)
Rich Hickey, Alex Miller, Stu Holloway, Nathan Marz, and the other people in this video are all very impressive, intelligent people. But never undercount how much if their success is due to consistent effort. They worked hard at something they cared about with depth, and also longevity. Anyone can learn Clojure with a bit of skill and tenacity. Anyone can contribute to the community in a meaningful way. It takes effort though. Please join us and contribute back to the community in ways that help you scratch an itch, give it some polish, and then share it. Or join the forums on Clojurians on Zulip. Come to Clojure/Conj, it was fantastic last year.
I feel this way about Common Lisp hackers too. What they have going on is very impressive wizardry. I want that. But whenever I try, it just does not mesh with my brain and I end up going back to Haskell and its compile-fix-compile-run loop instead.
It was sarcasm. My point was that with AI, anyone has a chance to make their name about this "amazing new tech" just like Rich and contemporaries did in the 2010's. Not AI as the means to an end, but as the end in itself.
I worked for a startup that used clojure and found it so frustrating because, following the idiomatic style, pathways passed maps around, added keys to maps, etc. For any definition which received some such map, you had to read the whole pathway to understand what was expected to be in it (and therefore how you could call it, modify it, etc).
I think the thing is that yes, `[a] -> [a]` tells you relatively little about the particular relationship between lists that the function achieves, but in other languages such a signature tells you _everything_ about:
- what you need to call invoke it
- what the implementation can assume about its argument
i.e. how to use or change the function is much clearer
I think the pipeline paradigm you speak of is powerful, and some of the clarity issues you claim can be improved through clear and consistent use of keyword destructuring in function signatures. Also by using function naming conventions ('add-service-handle' etc.) and grouping functions in threading forms which have additive dependencies, can also address these frustrations.
I've been running my business for 10 years now, relying on Clojure and ClojureScript. It is amazing to be able to base one's livelihood on a foundation that is so stable and well designed. Clojure has been designed by a very smart and very experienced person, and it shows. It has then been maintained and extended by a team built around a culture of maturity and stability, and the result is something you can rely on.
The fact that I can use the same language to develop business model code that runs on both the client and the server, or that I don't have to use a different on-the-wire format for sending data between them (EDN does the job great) is just icing on the cake in this context.
I am very thankful to Rich and the entire Clojure (and ClojureScript) teams for giving me access to all their work (for free!).
BTW, if you haven't seen any of Rich's talks, go see them — they are worth it even if you do not intend to use Clojure.
Rich's talks have been the apex of my programming career. I didn't like sitting in front of a computer to the extent needed to make a living from it, so I moved on to another industry. And maybe I wasn't smart enough to become competent in Clojure. But I'm thankful for the eureka moments that Rich offered me. He's such a beautiful mind.
Would love to know what industry you ended up in. Daydreaming about working with my hands out and about one day lol.
A lot of people abandon tech for less stressful careers. Things like air traffic control and firefighting, or deep sea diving for the oil industry.
I'm pivoting to mental health. But the trades are quite appealing too!
I would love to use Clojure but there are basically no jobs in my area with the language. Seems like the Nordics like Clojure but I'd need to move.
The very good backwards compatibility is attractive but as the result of the small community, there's also a lot of abandoned packages and fewer QoL packages (formatters, linters, etc); I know there are some but for example I had setup `cljfmt` in Emacs and it wouldn't work, didn't look further.
VS Code and its forks (Cursor, Antigravity, etc.) have Calva, a fantastic REPL with excellent linter Kondo. These are amazing tools; formatting is the very least of it. You don't need Emacs. I personally using VS Code + Doom Emacs. Also, many packages that look abandoned are simply mature. You can literally use ten year old packages.
I'm not a hot shot programmer, entirely self-taught but a decent architect who thinks hard about problems, and with LLM agents Clojure shines for me. There are some fantastic databases also starting with Datomic -- free now thanks to Nubank -- and everything inspired by it and the Clojure flavor of Datalog. These include Datalevin, Datahike, DataScript, XTDB. Datomic itself is probably best for enterprise though there's now an embedded version.
But I'm pretty convinced that most LLMs I've used are more reliable with Clojure (and Elixir) than with most of the popular languages, and I can say they use Datalog extremely well, seemingly much better than SQL despite the vast difference in corpus size. For one thing Datalog just gets rid of joins issues.
> I would love to use Clojure but there are basically no jobs in my area with the language
I created my own job :-)
(although there are Clojure jobs in my area)
Always a solution ofc!
cljfmt is included with both Clojure-LSP and CIDER, so if you have either installed it should work out of the box.
With LSP mode the standard `lsp-format-region` and `lsp-format-buffer` commands should work, and on the CIDER side `cider-format-defun`, `cider-format-region` and `cider-format-buffer` should also invoke cljfmt.
Hey! Thanks for creating the package =) I'll need to try the integration again.
I'll add a note to the cljfmt README to tell people about these commands, as your experience shows that it might not be obvious to people that they likely already have access to cljfmt in Emacs as a result of using LSP or CIDER.
There are still Clojure remote positions. Thankfully, I have used Clojure professionally long enough that my core ability shouldn't atrophy too much now that we have moved away from it at my current position. I am looking forward to Jank actually.
Why did you move from it if I may ask?
There were multiple reasons at our company -- my particular team, all skilled Clojurists, decided to default to python last year for a variety of reasons including both AI code generation suitability and AI model utilization in our code bases; the latter is of high relevance for our particular work. While I find Clojure to be among the best languages for interacting with LLMs via API, it is awkward for interacting with local models directly. Of all on the team, I was probably most open to a polyglot approach.
> AI code generation
Incidentally, I am having great success using AI with Clojure. In fact, from what I read online, better than most. I'm not sure if it's due to Clojure's terseness (and hence, token economy), or other reasons, but it works very, very well.
Fair enough!
Simple Made Easy[https://www.infoq.com/presentations/Simple-Made-Easy/] in particular had a huge impact on the way I think about writing software at a formative time in my development/career. I have not had the chance to use Clojure professionally, but thinking about software in terms of "intertwining" is the idea I return to when evaluating software designs, regardless of technology, and gave me a way to articulate what makes software difficult to reason about.
I have been writing Clojure since 2017. Unlike every other language that helps you achieve a task, Clojure helped me think.
Clojure for me is a rich vocabulary to talk interact with data. When Jank becomes stable, Clojure will be unstoppable.
I’ve been writing ClojureScript now for around a decade. I tried to get into Clojure many times, but as someone with no Java experience, the JVM really makes it unbearable. I ended up trying Elixir though and absolutely loved it.
Both Clojure and Elixir really changed the way I think about programming. They’ve both basically ruined me as far as other languages go. Structural editing + repo driven development in Clojure, BEAM + pattern matching in elixir.
But there is something just infinitely more fun about writing Clojure code, and insanely satisfying. I’m eagerly awaiting the day that jank takes off and I can start building native mobile apps in Clojure (and who knows, maybe some web backend tech stack will spring up around it!)
https://janet-lang.org is already Clojure without the JVM
I feel like calling Janet "A Clojure" is doing both a disservice. It's more like a "Clojure-like but smaller on purpose" programming language, and it's also (self-described) for "exploratory programming, scripting, and fun side projects" rather than Clojure's intended target audience.
Nothing wrong with that, having different target audiences makes sense and is probably preferable, but Janet is more than just "Clojure without the JVM" much like C# is more than just "Java without the JVM".
Yes, clojure-like is good
Every time I write another DTO → domain → DB mapping layer in Kotlin/TypeScript, I think about Clojure. I’m pretty grateful I learned it. It really changed how I think about software. Still, it’s a trade: less ceremony, more responsibility.
Clojure is very enjoyable if you respect the practices encouraged by Rich Hickey.
I've worked with Clojure in a number of companies, it's an elegant language and a thing of real beauty when done well, but it's not so much fun when you're working on a codebase that doesn't respect the philosophy of avoiding breaking changes; especially when these breaking changes are done in library code, and where a more liberal approach has been taken when it comes testing.
"less ceremony, more responsibility" is a good summary, in a larger codebase a bit of ceremony is not always a bad thing though. I'm also glad I learnt Clojure, it made me a far better programmer.
Kudos to Mr Hickey, I'm looking forward to the documentary.
Clojure is the language that made me "understand Lisp", as originally stated by Eric Raymond and citet by Paul Graham: https://paulgraham.com/avg.html
It seems like a small thing, but Clojure's choice to open up for other types of parentheses made seeing the structure of lisp programs much easier. This helped me understand how code is data and how macros are functions that can transform both code and data.
An important design philosophy (which is also hinted at in the trailer) is "simplicity". Clojure is designed to give you the tools to build simple solutions to the problems that you want to solve. It approaches mutability, which is one of the key sources of complexity in programming, with immutable data structures. It's a really clever way to do functional programming where your data is copied a lot but the copies are lightweight.
I don't write Clojure any more these days. I'm mostly doing Rust. But it is true what Eric Raymond said: Lisp has made me a better programmer.
Also: XKCD 224 and 297
Lisp philosophy is all about inventing languages (libraries), creating abstractions for each problem. Clojure is all about using primitive data types and maps everywhere explicitly.
virtually all abstractions are built on top of primitive data types and mappings
> virtually all abstractions are built on top of primitive data types
Obviously. The point being made is that the Clojure style discourages building DSLs and the like and prefers to remain close to Clojure types and constructs. It departs in various ways from traditionally Lisps.
> Clojure style discourages building DSLs
does it really? https://github.com/simongray/clojure-dsl-resources
DSLs typically involves constructing macros that are domain specific (to cobble together a domain specific programming language on top of the host). Most of the linked examples are not macro based and are the exact opposite. They specifying domain specific data layouts built directly using the Clojure-native immutable datatypes. They don't create Domain specific datatypes or function-generating wrappers. It's just rarely necessary
A good example is making GUIs in Clojure. At first there was a cool macro based system called `fn-fx` that maked a JavaFX GUI. Then vlaaad wrote `cljfx` which just used plain Clojure maps and removed the macros entirely. This increased the boilerplate a tiny amount but made the system much more flexible and extensible
> DSLs typically involves constructing macros that are domain specific
a DSL is a constrained language for expressing domain concepts.
in traditional Lisps they are often syntax-oriented, because code is lists and macros are a natural tool.
in Clojure, pervasive use of keywords, vectors and maps allows you to shift DSL design towards data interpretation rather than syntax transformation.
so in Clojure doesn't discourage DSLs - clojure practicioners simply prefer data-oriented DSLs to macro-oriented ones, mostly because they are easier to reason about and process with existing tools, while macros are used more selectively.
I think you're talking past each other.
"DSLs" can both mean "Using the language's variant of 'arrays' to build a DSL via specific shapes" like hiccup in Clojure does, and also "A mini-language inside of a program for a specific use case" like Cucumber is its own language for acceptance testing, but it's "built in in Ruby" in reality.
Clojure favors the "DSLs made out of shapes" rather than "DSLs that don't look/work like lisp inside of our programs".
no, not really. when people talk about DSLs in context of lisps, they usually still mean staying in the domain of s-expressions.
Yes, maybe that's the sort of DSL you're talking about, the other person mentioned "Clojure style discourages building DSLs" which I'm fairly sure to be about the other DSL and is also true, hence the whole "you're talking/reading past each other".
that doesn't make sense, why would they be talking about departure from traditional lisps if they weren't talking about macro-based DSLs?
I don't have much love for Java - it's an OK statically typed language - but I have the utmost respect for the Java runtime environment.
Clojure is a beautiful Lisp, and coupled with the JVM it's extremely powerful.
My favourite companion to Java, when on the JVM, especially because the host language community culture.
If you want a Lisp Machines like experience with Clojure, support the Cursive folks.
https://cursive-ide.com/
Where do I actually get the documentary on April 16th?
I think it’ll be on that same YouTube channel.
Only a few languages allow you to change a system while it is running (saving time on deploying new development versions and re-creating state) ... and have a recording debugger (saving time since you can inspect any part of a recording at leisure instead of accidentally passing the interesting spot and having to start over)
I hope more people get to experience this kind of joy :)
I am so glad that this has been made! And happy that it features so many familiar faces from the last two decades of Clojure. There is a lot more to a programming language than just the code committed.
I'm forever grateful for putting me onto this amazing language and even more amazing community. I know many others that feel the same way.
Very cool. My first instinct was to buy a Clojure book.. so for those that had the same,
Programming Clojure, Fourth Edition 4th Edition is on pre-order scheduled to be released May 2026.
https://pragprog.com/titles/shcloj4/programming-clojure-four...
Same! I think I acquired 2-3 books that I tried to slog through in order to understand Clojure, but never really clicked until I bought and went through "Clojure for the Brave and True", which somehow made it click. Also available for free online, highly recommend: https://www.braveclojure.com/
Yea, this book worked like a charm for me too.
The author recently weighed in on what he’d cut and add to a future version - could be useful to anyone reading today, if they want to skip some things. https://www.reddit.com/r/Clojure/comments/1rxknpj/quick_ques...
the wonders of visibility algorithm: https://news.ycombinator.com/item?id=47556827
I guess all the Clojure fans were in their hammocks?
Clojure is IMO indisputably a good language within a certain scope, and especially relative to many other languages used in practice. However, I think it's greatest merit is not so much the language itself - and there is nothing especially innovative about any of its features per se - but that it introduced so many programmers to a more functional style and the selection of very practical features it includes (Java interop was a smart move, as the ecosystem is a major hurdle for adoption). Much of the fandom and enthusiasm IMO comes from the contrast between the other sorts of languages people use in industry - which traditionally are imperative - and this functional style. It is much easier to reason about functional programs than imperative programs where names can refer to one thing at one moment, and to another at another moment. Mutability really is bad and should generally only be used judiciously and in very confined and controlled contexts.
In my experience, while I have found Clojure enjoyable and practical, it is still a "dynamic" language. A good deal of run-of-the-mill programming can manage quite well with such a language, but as projects become larger, deeper, and more complex, the lack of static types really does become a cost and an impediment. To understand any function and what it expects, you often need to read a few layers in to find what exactly something consumes and returns. Types really are a boon in such code bases. Some may point to various schema libraries in Clojure. While these can be helpful, they are often comparably inscrutable in practice (both in terms of specification and the resulting errors) and really do not compare to bona fide types, especially with LSP integration. And when you model something using types, the code sort of just falls out of the type definition.
Is this lang for web dev?
Yes, web development is a pleasure with Clojure.
On the backend side, you start your server once, and whenever you change it locally, you apply what you changed directly to the running process, so you don't lose any state and without having to restart the server at all, so iterating on the program becomes very easy. Bugs are easy to track down too, as you can evaluate parts ("forms") of the program inside the process itself, debugging becomes a breeze.
On the frontend side, you have ClojureScript that basically enables the same but in a browser environment. Usually I have the browser on the right, my editor on the left, and whenever I "evaluate a function", it runs in the browser context, so again same thing; the frontend keeps the same state even after your changes, so no more "make change -> wait for compilation -> get frontend into the state that reproduces the issue -> output debug info -> make change again", you just change one part, see the page update and then continue changing.
If you've used React+Redux (or similar) before, it's basically that experience, but much tighter and together with code evaluation inside of the browser context. If I recall correctly, Redux was pretty much directly inspired by ClojureScript and Reagent in the first place, I think Abramov even referenced ClojureScritp/Reagent in the first Redux talk.
clojure itself is a joy to use, on the web or outside of it
BUT
it doesn't have the equivalent of rails, mostly because lispers are an opinionated bunch and can't come together to agree on how web development should be done
the frameworks that do exist are more of a collections of libraries with some plumbing to connect the dots
Which in reality isn't a problem, once you absorb the ideas of Clojure and try to apply them when using Clojure. Composition of well picked libraries beat batteries-included frameworks for most use cases, both short term and long term, at least in 99% of the cases I'm writing Clojure/Script code.
I think it actually is a pretty big problem. "Once you absorb the ideas of Clojure" takes months or years to fully get. Composing libraries yourself, like your comment says, requires that they are "well-picked". Stitching together separate libraries is really time consuming and a distraction from the project you're trying to build. It also results in pointless thrashing within a team as everyone has become personally invested in their own mosaic of hand-selected libraries for every little thing. By the time a beginner learning Clojure has researched and put together their web stack and got it all hooked up and is ready to start, the Django developer already shipped their project last quarter, iterated on it a few times, and is on to the next thing.
One big library/framework has huge benefits and network effects, from enabling a big 3rd party plugin ecosystem, to a deeper documentation literature (including paid courses, books, and AI). It means that there's less or virtually zero getting up to speed when changing from one project to an other. It means that the upstream framework team takes care of upgrades whereas you have to consider, when a new technology comes up, how to integrate this into your stack. There's a reason that Laravel, Django, Rails, and Spring each have thousands or hundreds-of-thousands of times more websites in production than all of Clojure combined.
At a meta/discourse level, I also find the Clojure community's tendency to constantly deny and downplay any criticism or even just issue that people face to be really frustrating and counter productive.
> By the time a beginner learning Clojure has researched and put together their web stack and got it all hooked up and is ready to start, the Django developer already shipped their project last quarter, iterated on it a few times, and is on to the next thing.
Yes, but this is intentional. Django developers are optimizing for "easy" which makes it fast to spin up project after project, Clojure developers are optimizing for "simple" which means way longer time to get the project of the ground, to nail all the design before things start to actually be put together, which makes it easier and faster to iterate on the same codebase after years of working on.
Ask the Django developer how easy it is for them to add features after a project they've done that approach with for N years, then compare it to a Clojure codebase, and you'll notice the difference.
Sure, I guess this is "downplaying" and "denying", personally I see people who disagree with me as people who disagree with me, that's fine, I thought that was why we were sharing our opinions in this forum in the first place. But anyways, if you're very deep into "frameworks are clearly superior in every case", that we disagree probably matters less. Best wishes regardless!
Rich's Simple Made Easy talk is really interesting and insightful and I still love it but I think now the distinction is brought out too often almost reflexively, and used as a crutch. Yes "simple" and "easy" are not the same thing, but nor are they opposites. Just because something is "not easy" doesn't mean it's "simple".
I think there are lots of well maintained Django projects. In fact, if I do a search on AI and on google for what one web stack probably has the lowest overall total cost of ownership including maintenance years down the line, Django usually is what comes up, without even specifically searching for/mentioning it.
> if you're very deep into "frameworks are clearly superior in every case"
This is a mischaracterization of what I have said, and is more like the extreme position that Clojure devs seem to take. The original commenter said that Clojure is wonderful, but it's too bad that [for the people who want it,] there isn't the option of a well maintained, all-in-one, batteries included framework. You deny that this is a problem, saying that actually a well-chosen set of libraries are superior (I guess in every case, because if not then it actually would be a problem sometimes).
In my experience, Clojure was a huge pain in the ass to get into, and there's a non-zero amount of community members that talk about it in nothing about aphorisms. I really wanted practical advice, but getting people to talk normally about it was an uphill battle. This made me almost quit several times. But it is a very pragmatic language underneath (which you've already mentioned).
But I'm not sure a framework is really going to change that onboarding process, or help with network effects that much. Elixir has a de facto framework, but it's barely more popular than Clojure. I mean, we had Leiningen starter kits and we have Kit. But what's confusing to me wasn't setting up a project, it was learning how it was wired together. Wiring small libraries together and just passing data can feel surprisingly leaky, and I don't really have to peak into the internals of Laravel the way I do Clojure projects.
I think Biff is a promising step in the right direction. I think the way it has wired things up is easier to follow. But for whatever reason, they made the choice to use XTDB as a default, which is a huge cognitive burden for newcomers. They have an article on how to use something else instead, but this is already getting out of the "it just works" territory if you haven't even learned Clojure yet. But the author is a really nice and talented person, and I am looking forward to seeing where it goes.
> I think there are lots of well maintained Django projects. In fact, if I do a search on AI and on google for what one web stack probably has the lowest overall total cost of ownership including maintenance years down the line, Django usually is what comes up, without even specifically searching for/mentioning it.
Having used Clojure, Laravel, Spring, and Django, I wouldn't touch Django again with a 10 foot pole. I don't know what you're referring to by "doing a search of lowest cost of ownership" but it sounds pretty unscientific. Anecdotally, I do legacy apps, and I have picked up people's Django apps, and I've never loved what I saw. It's a classic fast to start, slow to maintain framework. Huge businesses have been built on it, but huge businesses have been built on everything.
> I'm not sure a framework is really going to change that onboarding process, or help with network effects that much
having one commonly accepted and recommended way does improve onboarding, because it collapses the decision space beginners face. right now they are supposed to make decisions (not even directly, but just through selecting one of the many frameworks) about things like:
whats worse - most of the alternatives overlap in various ways, so making the "best choice" in order to reduce future headache induces quite a bit of anxiety.yes, multiple frameworks exist that make those choices for you, but then you inevitably hit the problem that some of the components haven't been updated in a while, so documentation is out of date and when you try updating it just for your project you need to fix the framework plumbing and due to number of frameworks, the corpus of useful information on the internet is quite fragmented and the community help is limited, and on and on.
none of this is good beginner experience.
and don't get me wrong, choice by itself isn't bad, focus on composability of smaller libraries is important, dominant framework is not going to improve anything when it locks people into bad decisions.
what we lack is convergence behind a single "reference stack" of libraries that ought to be good enough for the general case and a minimal framework of plumbing that doesn't require dozens of files just to get started.
there doesn't need to be a single way of doing it, but there needs to be a single recommended way of doing it.
Wouldn’t touch it with a 10 foot pole. What would you prefer over django of the listed above? Curious.
The fundamental mistake of Simple Made Easy was how many people interpreted them as orthogonal (or even opposing) qualities, when that's not inherently true.
This led to a lot of Clojure code being simple, but avoiding the hard additional work of also making it easy, and sometimes in even making it complete.
The prime example was tools.deps/deps.edn. It largely supplanted Leiningen for new code, but by being simple and minimal, it led to an explosion of ad hoc, custom tooling for 2-3 years afterwards, as everyone rewrote functionality that Lein already had, but tools.deps was missing. (And I say this as someone who once lost a whole week debugging a subtle maven/lein set ordering bug.)
Have you seen this?
https://www.infoq.com/presentations/Simple-Made-Easy/
Yep
Welp, nothing I can say is going to make a stronger argument than that.
yep, every word.
Yes, huge selling point in favor of Clojure!
it really isn't, unless your goal is to scare away the casuals.
Yes, as ClojureScript
I'll never be as cool as them.
Rich Hickey, Alex Miller, Stu Holloway, Nathan Marz, and the other people in this video are all very impressive, intelligent people. But never undercount how much if their success is due to consistent effort. They worked hard at something they cared about with depth, and also longevity. Anyone can learn Clojure with a bit of skill and tenacity. Anyone can contribute to the community in a meaningful way. It takes effort though. Please join us and contribute back to the community in ways that help you scratch an itch, give it some polish, and then share it. Or join the forums on Clojurians on Zulip. Come to Clojure/Conj, it was fantastic last year.
Well yeah how can you compete with a programming language created by the 4th Doctor?
I feel this way about Common Lisp hackers too. What they have going on is very impressive wizardry. I want that. But whenever I try, it just does not mesh with my brain and I end up going back to Haskell and its compile-fix-compile-run loop instead.
But with AI now is your/everyone's chance!
AI might help you with building the thing that you want. But AI can't help you with finding out what is worthwhile wanting.
See also Rich Hickey's remarks on AI: https://www.youtube.com/watch?v=MLDwbhuNvZo
It was sarcasm. My point was that with AI, anyone has a chance to make their name about this "amazing new tech" just like Rich and contemporaries did in the 2010's. Not AI as the means to an end, but as the end in itself.
Supposedly. If the productivity boost is good for commercial software it's good for open source.
> `a -> a`; `[a] -> [a]`; It means nothing! It tells you nothing!
— Rich Hickey, Effective Programs[0]
[0]: https://www.youtube.com/watch?v=2V1FtfBDsLU&t=4020s
---
A disastrously poor take. I used to work at a Clojure company, and there's no chance I'd ever go back to that.
I used to work in a Clojure company, but you wouldn't believe how loudly the lead developer chewed when we had lunch, never Clojure again after that.
I worked for a startup that used clojure and found it so frustrating because, following the idiomatic style, pathways passed maps around, added keys to maps, etc. For any definition which received some such map, you had to read the whole pathway to understand what was expected to be in it (and therefore how you could call it, modify it, etc).
I think the thing is that yes, `[a] -> [a]` tells you relatively little about the particular relationship between lists that the function achieves, but in other languages such a signature tells you _everything_ about:
- what you need to call invoke it
- what the implementation can assume about its argument
i.e. how to use or change the function is much clearer
I think the pipeline paradigm you speak of is powerful, and some of the clarity issues you claim can be improved through clear and consistent use of keyword destructuring in function signatures. Also by using function naming conventions ('add-service-handle' etc.) and grouping functions in threading forms which have additive dependencies, can also address these frustrations.