It encourages good practices by defaulting to immutability. This naturally leads to code that can be reasoned about in isolation.
I find the tooling is superior. Leiningen lets me do the same thing as a grab bag of Js build tools, such as dependency management, building, packaging, and so on.
There's still no equivalent to Figwheel in JavaScript workflow. The productivity of being able to see changes as you're working without having to reload the page and rebuild state can't be overstated.
Reagent/re-frame combination much cleaner than React itself in my opinion. It also avoids much of the complexity in React as described here https://purelyfunctional.tv/article/react-vs-re-frame/
I haven't seen much code that uses the bad aspects of JS, or at least exposes it in library APIs. You can just stick to the good parts of JS and have the same benefit. Clojure also has its quirks, btw. Every language will.
> It encourages good practices by defaulting to immutability. This naturally leads to code that can be reasoned about in isolation.
The language may encourage it, but given that none of the JS libs I've used mutate anything I give them, it sounds like the benefits of immutability have spread enough that mutation is no longer a problem in practice.
> I find the tooling is superior. Leiningen lets me do the same thing as a grab bag of Js build tools, such as dependency management, building, packaging, and so on.
If you write a good set of config files with something like Webpack, it's fire-and-forget. And in practice, Leiningen isn't all that simpler than JS alternatives. Trying to understand the sample project.clj for a real-world ClojureScript project was kind of a nightmare for me.
> There's still no equivalent to Figwheel in JavaScript workflow. The productivity of being able to see changes as you're working without having to reload the page and rebuild state can't be overstated.
We'll have to agree to disagree. I can make changes to my site and the page reloads live with only 14 lines of vanilla JS code on the front-end[1] and back-end[2] each. If I need to make changes while keeping state instead of reloading (which I haven't really seen a need for) I'm sure I can whip something up using `eval`. Plus even if you follow the Components architecture and avoid global state, there are still situations where you have to reload the page from scratch.
> Reagent/re-frame combination much cleaner than React itself in my opinion. It also avoids much of the complexity in React as described here https://purelyfunctional.tv/article/react-vs-re-frame/
That may be true, but that doesn't prevent equivalent libraries to Reagent/re-frame from being created in JS. And maybe there already is an exact copy of that in JS somewhere. React may be the king in this space for now, but there are lots of alternatives or plugins while sticking to JS.
[1]: https://github.com/sdegutis/sdegutis.com/blob/master/src/tem...
[2]: https://github.com/sdegutis/sdegutis.com/blob/master/index.j...
Every language will have quirks, but Js certainly has a lot more quirks than Clojure. My team saw a huge gain in productivity moving from Js to ClojureScript on the front-end.
>The language may encourage it, but given that none of the JS libs I've used mutate anything I give them, it sounds like the benefits of immutability have spread enough that mutation is no longer a problem in practice.
That's certainly not my experience. Everything in Js is passed around by reference, and it takes a lot of discipline for teams to write applications in a maintainable way.
>If you write a good set of config files with something like Webpack, it's fire-and-forget. And in practice, Leiningen isn't all that simpler than JS alternatives. Trying to understand the sample project.clj for a real-world ClojureScript project was kind of a nightmare for me.
Leiningen is also fire and forget when you use a template. I don't think understanding Webpack and all of its config is any easier.
>We'll have to agree to disagree. I can make changes to my site and the page reloads live with only 14 lines of vanilla JS code on the front-end[1] and back-end[2] each.
This works fine for small applications, however in large real world apps where you have a lot of state reloading a page every time you make a change is just a non-starter. I might need to login, navigate to a specific section, load some data, and then work on the presentation. Repeating all these steps each time I change a few lines of code is absolutely insane.
>That may be true, but that doesn't prevent equivalent libraries to Reagent/re-frame from being created in JS.
Actually it does. Js syntax sucks for writing HTML, and that's why you have stuff like JSX in the first place. Now you have an additional DSL with all of its quirks on top of already quirky Js.
Were they using ESNext features? Where they using Babel to compile to ES3 or ES5? Or were they just using the old-fashioned JS that's filled with tons of huge warts? Because for me, the newer JS features are definitely a game changer. Not only do they reduce a ton of boilerplate code for me, but they make things safer, more predictable, easier to reason about, easier to catch bugs, and generally prettier.
> That's certainly not my experience. Everything in Js is passed around by reference, and it takes a lot of discipline for teams to write applications in a maintainable way.
There are several built-in methods in modern JS for returning new objects based on existing arrays and objects such as map, filter, and reduce, and there are libraries to polyfill basically the rest of `clojure.core` into it such as lo-dash.
> This works fine for small applications, however in large real world apps where you have a lot of state reloading a page every time you make a change is just a non-starter. I might need to login, navigate to a specific section, load some data, and then work on the presentation. Repeating all these steps each time I change a few lines of code is absolutely insane.
Unless your site needs to be an SPA, most of this is a non-issue. Just keep login information in either a cookie or localStorage/sessionStorage, and live-reload the page without worrying about state.
> Actually it does. Js syntax sucks for writing HTML, and that's why you have stuff like JSX in the first place. Now you have an additional DSL with all of its quirks on top of already quirky Js.
Sure, there are situations where you can't have your code be as nice without using some kind of compiler phase. ClojureScript macros may come in handy with this, but that still has its own caveats to be avoided. In my experience, it's not much different than the overhead you get from using JSX itself or a similar compiles-to-JS template language.
Each extension of Js adds complexity to the overall language with its own quirks and warts. Different libraries will be written in different styles and using different features, and you have to juggle all of that in your head to work with the language effectively. I think we have plenty of evidence nowadays that working with large languages introduces a significant mental overhead.
I don't see why I'd want to work with a large quirky language when I have a simple and focused one available to me. With all the new features that ES6/7 add, Clojure still ends up being more concise vast majority of the time.
>There are several built-in methods in modern JS for returning new objects based on existing arrays and objects such as map, filter, and reduce, and there are libraries to polyfill basically the rest of `clojure.core` into it such as lo-dash.
Or I can just use a language that was designed around immutability and avoid all that. What is the advantage here?
>ClojureScript macros may come in handy with this, but that still has its own caveats to be avoided. In my experience, it's not much different than the overhead you get from using JSX itself or a similar compiles-to-JS template language.
You don't need any macros for this. ClojureScript syntax maps really well to HTML because it's s-expressions. Reading hiccup syntax is actually easier than reading plain HTML in my experience. Also, since it's just regular data, it's trivial to manipulate it in the language. There are no new rules to learn, no DSLs to memorize, it's just plain data.
> The language may encourage it, but given that none of the JS libs I've used mutate anything I give them
> If I need to make changes while keeping state instead of reloading (which I haven't really seen a need for)
Speaking as an enterprise JS dev the kind of apps you are working on sound nothing like the kind of apps I work on.
I work with a lot of poorly written JS code, a lot of mutable state, and pages with lots of complex state setup.
In fact the state setup is typically so bad developers rely upon unit tests and only check the UI on feature complete.
> [I]n practice, Leiningen isn't all that simpler than JS alternatives. Trying to understand the sample project.clj for a real-world ClojureScript project was kind of a nightmare for me.