> ClojureScript has unlocked whole new levels of productivity
I keep seeing this claim over and over again about Clojure and Clojurescript. I don't get it, at all. I tried it, multiple times, I don't get where the productivity boost could come from. I though maybe the so-called REPL-driven development (as if clojure is the only language ever with a REPL), I watched videos about REPL-driven development, developed a project that way, cool... not more productive than say TDD or hot-reloading
> I enjoy it because there is little cognitive load in terms of understanding what the program is doing.
Is there? I mentioned I was not more productive in clojure, in fact I was actually much slower in clojure. It's not lack of FP knowledge, because in fact I love how productive I am with Elm, so maybe it's the lisp style, or maybe my inexperience with the language, I can't memorize all thousands of functions to manipulate lists and hashs in clojure (get-in, map-vals, conj, dissoc, select-keys, sorted-map-by, do you know what all those do?) which do a lot, I felt clojure was dense, the opposite of little cognitive load
After that, his following arguments about reagent vs useContext and Re-Frame vs redux is not about some real advantage of clojurescript over javascript, but rather conscious decisions that js community did to be explicit over implicit, it was an explicit trade-off, doesn't convince me that much as positive point for cljs
I want to like Clojure and Clojurescript, I really do, I would like to brag about writing lisp like the rest of you too, please convince me, claiming productivity because of "repl" or "less symbols" is not working, I need deeper reasoning
I think claims of improved productivity when switching to Clojure have a lot to do with the person making those claims and where they are coming from.
I see Clojure as almost sub-set of JavaScript bundled with a great standard library akin to Lodash or Ramda. You can write very Clojure-y functional code with JavaScript, and if that is what you are already used to doing, than you might not see a big difference in switching to Clojure.
But JavaScript is a bit of a kitchen sink. You want classes, you got em. You want prototypes, you got em. Functional programming, sure. This wide mix of language features means that everyone’s experience with the language will be different, and if somebody is coming from a very object-oriented background, being exposed to the data-oriented functional approach of Clojure can be an eye-opener.
Personally, using Clojure had a huge impact on how I approach development (having from from a traditional C#/Java background). I consider myself much more productive now and view problems in a completely different light. I don’t write Clojure for work, I’m pretty much full-time Node.js these days, but I credit Clojure with changing my development practices for the better.
I guess what I’m saying is that it’s not necessarily Clojure-the-language that make people feel more productive, but maybe it’s just the development style that Clojure almost forces upon people that makes them feel more productive.
(And personally, I just love the elegance of a language with such minimal syntax... and an abundance of parens)
I agree with this. Many JS programmers have come into it either as their first language, or from object-oriented languages like Java. Unlike Python, there is no One True way to do things in JS. If you look at JS in the wild you'll see the same thing done in a myriad of different ways. I often think JS programmers prefer the one that makes them look the most clever. Learning a language like Clojure teaches you the importance of mutability, functional style etc. Once you know those things deeply, it's not about aesthetics or looking clever any more, it's about writing good code.
But there is also the practical aspect. Plain JS lacks a lot of standard library support to be functional. You have to be really careful about what is functional and what isn't. The standard library is also inconsistent, like PHP (for example, how Map and Set .add returns the object but .delete returns a Boolean).
> I can't memorize all thousands of functions to manipulate lists and hashs in clojure (get-in, map-vals, conj, dissoc, select-keys, sorted-map-by, do you know what all those do?) which do a lot, I felt clojure was dense, the opposite of little cognitive load
Funny, I would say that it’s the functions for manipulating data structures that makes clojure a joy to use. To me it feels like there are very few of them, and there’s a lot of consistency which makes it easy to guess what one does if you haven’t seen it before (once you’ve learned map, map-keys/map-vals/mapv don’t really need learning etc). Yes there are actually a lot, but I basically only use a dozen or so. Would be interesting to see the frequencies of clojure syntax vs other languages.
Clojure was my first (professional) language though, and I have used it every day for the last 4 years. I guess it’s different if you’re trying to learn it on the side.
I have dabbled in a few other languages on side projects (js/go/swift/svelte) and while there are definitely big improvements to be found in the tooling, nothing really matches Clojure as a language for me. Though I won’t claim that ‘clojure is more productive’, I will claim that ‘I am more productive with Clojure’, probably largely for the same reasons that you are not, it’s comfortable for me.
Clojure is not easy, but it is simple, as Rich Hicky explained.
For the trivial projects, you won’t find yourself bulding products faster in this stack compared to others.
To feel productive, you need to amortize your time spent learning Clojure over the time saved building and maintaining complex, non-trivial projects.
I can’t say for Elm as I never tried it. But, as a mostly backend developer, moving from Javascript to Clojurescript was a huge enablement for me. I am a rather mediocre programmer in a two man team. Still, with Clojure/Clojurescript, I was able to make something I could only dream about before.
Also, can you explain what you mean with the following:
"with Clojure/Clojurescript, I was able to make something I could only dream about before."
What does CLJS enable you to do that you can't do with JS / TS?
PS. I'm in a somewhat similar boat, i.e. not a great programmer (not my job anyway) - more of a prototyper - hence my interest in your experience with CLJS.
No. I am using Clojurescript for frontend. What I meant was that my strong point is server side programming and I lack experience and time to master all the nooks and cranies of programming in Javascript.
I built a voice broadcasting service as a side project in Clojure, built on top of freeswitch and Datomic. From low level library (freeswitch-clj) to API server and frontend SPA, all in Clojure(script). The whole system is approximately 32K SLOC, written over 3.5 years. I have tried similar projects with other stack, mainly with PHP+js and python+js. None went as far as this one. Although we are yet to make a profit, I am very satisfied with the whole development process and subsequent maintainability offered by Clojure. In frontend, we are using reframe + antd react UI library, along with other necessary glue libraries from npm.
> I can't memorize all thousands of functions to manipulate lists and hashs in clojure (get-in, map-vals, conj, dissoc, select-keys, sorted-map-by, do you know what all those do?) which do a lot, I felt clojure was dense, the opposite of little cognitive load
In fact you need to memorize 10-20 functions to be productive in Clojure. Many of them are common across the other FP languages and some FP libraries for imperative languages and most of them cover common patterns for vector/map manipulation. Yes, the names could be confusing at first but there is good reasoning and logic behind them so it’s easy to learn.
> because in fact I love how productive I am with Elm
This is interesting because according to Real World App benchmarks Elm implementation has ~4x more lines of code then Clojurescript one [1]. How could it be more productive to write 4x code for the same result?
I’ve never personally tried Clojure[script] or Elm, so I have no real skin in this game, and I love Lisp and Scheme and Haskell alike, but:
Writing 4x more lines code can be more productive if your IDE makes it easier to write that code because of better tooling - say, because it can help refactor or provide effective type-directed autocomplete, so you don’t need to waste lots of time looking up documentation.
Or, you can be more productive even just if the documentation is better-organized, meaning when you have to look things up it takes you less time to find what you need.
Or, if the documentation is better, so you have to spend less time staring at it to understand.
Or, if there’s a larger community that provides solutions that are a google away when you’re stuck.
Or if the type-checker is better at catching errors in advance, meaning that even if you spend more time writing code, you spend less time testing and debugging it.
Or (and I’m speaking generally here and everywhere) if the compiler is significantly faster, so testing becomes less painful.
Or if the debugging tools are better, so that debugging is less painful.
Or if the code is considerably more readable, meaning you spend less time reading old code or others’ code and saying, “wait, what does this do again?”
Or, honestly, even if your lines of code are 1/4 as dense you can write 4x as many lines of code with, all other things being equal, roughly the same amount of productivity.
I’m sure there’s other things too. LOC is a questionable metric for the productivity a language ecosystem can provide is what I’m saying, basically.
> How could it be more productive to write 4x code for the same result?
Lines of code in Elm is not directly comparable to Clojure. The standard Elm formatting uses very short lines and lots of vertical whitespace. Without looking at it, I'd guess 1.5-2x more actual code bytes for Elm. As for why the increased size would be more productive, Elm is content to trade verbosity for lower cognitive load/fewer concepts so it's slightly boilerplate and every app I've run across shares the Elm architecture so the patterns are similar.
I prefer Clojure/Clojurescript and re-frame in particular for the task but I can see how someone with different preferences would be faster in Elm.
elm-format naturally creates more lines than formatted clj code.
Also, you have extra code for types, but also the convenience of a great type system. If you were to add clojure.spec to RWA it would probably be just as verbose.
I ask myself is the type system that great if you need to write times more LOC just for the sake of it? More lines lead to more bugs exponentially.
As for the spec - the benefit of it is that you are not forced to add it everywhere. You can cover crucial points of program only and leave the rest uncluttered.
I agree with you. I have used Clojure many times in work environments because, well, that is what the customer/teams used. I also like Clojure, and am currently writing a short cookbook style book on Clojure AI projects. But, but, but: I am so much more efficient working in Common Lisp.
I think it is more about good software developers using the tools they love and getting good with them. Years ago, one of my repeating consulting customers brought me into a Clojure project where he had hired the Clojure Company Cognitect. One of their people (I think it was Stuart Sierra) was just incredibly productive. I think it was because of who he was and his skill set, not the language.
Several years ago, I managed someone who had non-computer science PhD, who was incredibly productive using Python. Was it Python? I don’t think so.
BTW, re: REPL based development (which is how I roll): I don’t much like Python, but I can’t imagine doing exploratory development not using Emacs and a REPL, in the same mode as using Emacs+Clojure+Cider. Different languages, same experience. It is the mode of development that is more important than the language.
I got into clojure as a hobby for more than one year I am not an expert yet by any means.
It took me a long time to become productive in Clojure. There were simply too many things to learn at once, from syntax, to tools, to, more important, change of paradigm. I did the mistake to also learn Emacs at the same time (love it, but it just took too much time that I didn't have).
I know feel very productive because everything is done in the same way and those dozens of functions you mention is all I have to use 95% of the time. It takes time to learn them and even more to become proficient, but once you are there everything is very simple and fast.
There are two misconceptions that took me way too much time to realize:
- Macros are unfortunately needed sometimes, but they should be avoided as much as possible. DSLs are better done with data structures.
- REPL driven development is messy and stateful (you keep modifying vars all the time). A test driven development is much better. Having the REPL is still valid and all what you need most of the time for simple things, though.
Clojure can be very productive, but it requires significant (in my particular case, very significant) investment to get there. In the process, I learnt a lot about FP and, more importantly, about how to model almost anything as immutable data. Once this clicked on me, working in languages without this support for easy manipulation of immutable data structures looks like going backwards.
It's okay for you not to have been more productive. Programming always involves the programmer to be in the loop, so the language can only help the programmer be more efficient, and a lot of that has to do with how the particular programmer thinks, reasons, and develops, their style and their way of approaching programming. It depends a lot on where your own bottlenecks are, what motivates you, what keeps you engaged, productive, what gets out of your way, and what lets you focus in joy on your problem and work.
Clojure/Script does that for some, it truly makes them more productive, and maybe it doesn't for you, that's totally fine, there's nothing to convince you of.
It's a mistake to think that something that works for you should work for everyone, Clojure/Script truly works for some, and probably won't for everyone and that's okay.
Yeah, I would like to see more examples of startups picking up Clojurescript (or any of these non-mainstream languages), and running circles around their competitors as a result.
Could it be because it is somewhat similar to Javascript in a way in that it is a dynamic language? Javascript while some may argue is clunky needs to be known to work on web stuff so I still have to learn it anyway. From what I've seen expressing concise patterns isn't where the weakness of modern Javascript is, and therefore I'm not sure if adding Clojure makes it that much better. It doesn't necessarily address the weaknesses that slow me down when working with Javascript is what I'm getting from your comment.
REPL development is great, but I'm more keen to try it on something like F#'s Fable, where I get static typing, the REPL driven development experience (F# also has an adequate REPL with package manager support), with a concise language that maps pretty closely to Javascript. At least then I'm covering up the weaknesses in development I see when doing Javascript - the lack of a type system especially as the project scales. If I'm going to use something to better my Javascript it needs to add something that Javascript doesn't have to make up for the extra complexity IMO. My biggest frustration when writing Javascript is remembering what each function returns especially cross libraries/cross projects. At least for me I'm not sure how ClojureScript fixes that problem. Especially since I could use something like Lodash to get the standard FP functions/syntax.
It's not the only language with a REPL but in few languages the REPL is really usable.
For example, I tried the Python REPL recently. It's not worth the effort. Pervasive mutability in the language makes it basically useless for anything practical. No tooling is designed for it, and I believe it can't be without making a new language effectively. If somebody has really used a Python REPL to a great effect, I would like to see it, please let me know.
Clojure allows you to escape "place oriented, mutable-first programming" that is super easy to fall into with all other popular languages. You won't see a benefit if you just try for a day or two.
And yes, I do know what all of those do :) (using Clojure since ~2014).
In reality, you probably need ~20 functions to be productive in Clojure. It's much better IMO to memorize consistently named functions that don't ever change than figuring out what some specific string syntax means in some (new) language. That's just a benefit of being a Lisp, nothing specific to Clojure (in that case).
I have used Python's REPL successfully before. You need to have an editor with a good "send to REPL" function. It works when you are writing a single script, like people do with Jupyter notebooks. I've worked with scientists over my shoulder in this fashion and it's really helped them understand what I'm doing for them.
Where it falls apart is when developing a "real" package that is split into several modules. You can't use it for that.
True, this form of REPL development is not as good for large multiple file projects. I think that is OK. I start building software from the bottom, and a REPL session gets me one low level function written and debugged. I switch to using an IDE for “whole project” development.
For Clojure, I use all three: Emacs+Cider, VSCode+Calva, and IntelliJ+Cursive. I get something different from all three environments.
For me, it comes from a few things, none of which are unique to Clojure or necessarily from the language itself. I use reagent, re-frame and shadow-cljs and use the REPL very infrequently in clojurescript:
1. Reagent provides a much simpler and stable abstraction that js react does. Almost all my reagent views today look exactly the same as they did six years ago, while react has went through a number of API shifts. I barely noticed the switch to hooks, for example, the only place where it mattered to me is with interop with native react components and that was rather minimal. My reagent views are typically extremely simple with no logic, except when needed for performance optimisation.
2. I use live reload (figwheel in the past, shadow-cljs now) to auto update my changes. I use reframe-10x to inspect my state.
3. Re-frame gives me the application structure and let’s me write reusable code easily.
Clojure’s immutable data structures make this pleasant and safe (I don’t really need to think about what could be mutating what outside of interop, but the same can be done in js with a re-frame-like framework and a little discipline) and the sequence abstraction is a natural way of dealing with collections of data for me.
These things make clojurescript react development very productive and pleasurable for me. But like I said, none of these things are actually unique to Clojure.
> I can't memorize all thousands of functions to manipulate lists and hashs in clojure
I mean, that’s just part of learning any language or framework and takes time and hands on coding. When I started with Clojure I would regularly just browse the clojuredocs reference pages to remind me what exists. After a while you stop having to look them up. This is no different from learning any function library really, except that if you’re using an OO language with good tooling or static types your autocomplete might be able to better predict what is relevant to you. After years of using Clojure, I rarely need to look functions up, which is similar to how after years of C++ I don’t use autocomplete to find functions (I use it just to save time typing, not to find what the function might be).
I dunno how long you spent with Clojure but it sounds to me that maybe you didn’t spend long enough to get comfortable enough to see any productivity boosts? Clojure isn’t an easy language to learn so it wouldn’t be reasonable to expect to see productivity right away. It’s also not everybodies things, so maybe it just didn’t click with you.
I don't get it either. I do backend mostly, but my main differentiator isn't even functional vs. imperative, it's typed vs. untyped. As much as this take is going to make half of HN throw up, I'll take Java over Clojure any day, and Java doesn't even have a good type system to begin with.
I could see myself being very productive with lisps for small, plumbing-type stuff that you would use Python or Perl for, but in that area the foremost priority is libraries and the ecosystem, and Python isn't going to lose to any lisp in that department, even though I'm not a fan of the core language.
It's a trade-off, you trade certainty of types validated by the java compiler that comes with alot of ceremony with conciseness and agility provided by the repl, the downside being you need to ensure the result via tests and discipline.
Source code quality and developer ergonomics are somewhat subjective, so its natural different people have different opinions.
The "level of productivity" when writing a browser app is going to depend completely on your other skills as a developer and not on the superficial differences between JS and Cljs. Only language zealots say Cljs gives them "whole new levels of productivity" over JS, learn to recognize them and ignore them.
For many, learning Clojure can make them better developers but most don't keep using it once they realized they can apply all the hindsights they learn from Clojure to a more productive ecosystem.
> For many, learning Clojure can make them better developers but most don't keep using it once they realized they can apply all the hindsights they learn from Clojure to a more productive ecosystem.
Exactly. I feel Clojure/Script too heavy to jump fully in, but it taught me about data structures, sequences, composition which lead me to Ramda.js.
This little functional library can be learnt in no time, and gives similar powers like Clojure, while learning Clojure and the ecosystem would take at least months.
If you have the chance to work with a team, you can get proficient in a couple of weeks. What you don't know right now is probably how the glue code for a cljs project works (eg shadow-cljs) and the core library.
I have tried both ways, and I agree with what you've said. It's not faster than hot-reloading, and it's not faster than TDD either given the tests run super fast. Both are not too hard to achieve in the JavaScript world.
However, I found where REPL-driven development shines and more productive, is when there's no specific requirement and the programmer is exploring things. Traditionally there are product owners, designers, and programmers in the team, and they work in the pipelines. Both the functionality and the design are settled, the programmer just needs to implement the functionality and the UI.
Now just imagine in a small team there's no split between roles. One obvious way to work is to pretend there are roles: 1) design the core functionalities on paper 2) design the UI on Figma 3) write the code. Although this approach brings clarity, it's rigid and not pretty productive.
A reasonable alternative is to do all the things altogether: design when programming. REPL-driven development is a perfect fit for this methodology. TDD, in this case, is not working well because tests need rigid boundaries to test on, if I write tests I have to erase them repeatedly because I don't have specific ideas of what I'm going to build in the first place. What about hot-reloading? Say if we are developing a game, and the player can jump, with hot-reloading, I still have to implement a button to jump, while with REPL I can send a piece of code to let the player jump without writing UIs for it at all. REPL-driven development provides a perfect playground that can be leveraged as a tool for both thinking and programming.
In hindsight, TDD resonates functionality designs from product people - if it's settled we can write test cases and just implemented it. And hot-reloading helps a lot in implementing settled graphic design - because there's no better way to test graphic than just seeing it in real-time. If there is neither functionality design nor graphic design in the first place, we need new things to help us to do the all designs with our code, where REPL-driven programming is a perfect it. Rather I would call it REPL-driven design.
To maximize gains from a tool, the way we work and think must be adjusted. As another example, many programmers who favor statically typed languages program in dynamically typed languages, usually don't write in the same way as those who favor dynamically typed languages, thus for them, dynamically typed languages are just net loss.
IMO the REPL-driven design resonates with Paul Graham: A programming language is for thinking about programs, not for expressing programs you've already thought of. It should be a pencil, not a pen. . This approach also reminds me of the 'Sketch HTML' approach in Getting Real from 37 Signals.
I keep seeing this claim over and over again about Clojure and Clojurescript. I don't get it, at all. I tried it, multiple times, I don't get where the productivity boost could come from. I though maybe the so-called REPL-driven development (as if clojure is the only language ever with a REPL), I watched videos about REPL-driven development, developed a project that way, cool... not more productive than say TDD or hot-reloading
> I enjoy it because there is little cognitive load in terms of understanding what the program is doing.
Is there? I mentioned I was not more productive in clojure, in fact I was actually much slower in clojure. It's not lack of FP knowledge, because in fact I love how productive I am with Elm, so maybe it's the lisp style, or maybe my inexperience with the language, I can't memorize all thousands of functions to manipulate lists and hashs in clojure (get-in, map-vals, conj, dissoc, select-keys, sorted-map-by, do you know what all those do?) which do a lot, I felt clojure was dense, the opposite of little cognitive load
After that, his following arguments about reagent vs useContext and Re-Frame vs redux is not about some real advantage of clojurescript over javascript, but rather conscious decisions that js community did to be explicit over implicit, it was an explicit trade-off, doesn't convince me that much as positive point for cljs
I want to like Clojure and Clojurescript, I really do, I would like to brag about writing lisp like the rest of you too, please convince me, claiming productivity because of "repl" or "less symbols" is not working, I need deeper reasoning