6 ms·
Why I'm ditching Clojure for JavaScript
- _sdegutis 9y agoI feel similarly about ClojureScript. It's a neat proof-of-concept, but I'm not really sure what it adds over regular JavaScript (or at least Babel + Webpack) these days.
- yogthos 9y agoMy team finds that it adds a lot. For starters, it's a much cleaner and simpler language. This means that you have a lot less mental overhead working with it. 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/ https://purelyfunctional.tv/article/react-vs-re-frame/
- _sdegutis 9y ago> For starters, it's a much cleaner and simpler language. This means that you have a lot less mental overhead working with it. 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/ 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/template/reload.js https://github.com/sdegutis/sdegutis.com/blob/master/src/tem... [2]: https://github.com/sdegutis/sdegutis.com/blob/master/index.js#L329-L346 https://github.com/sdegutis/sdegutis.com/blob/master/index.j...
- yogthos 9y ago>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. 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.
- _sdegutis 9y ago> 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. 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.
- dustingetz 9y agoClojureScript forces the whole ecosystem into doing immutability, properly, all the same way
- cutler 9y agoHave you worked with Leiningen? Try it and compare it to the hideous monstrosity that is Webpack. Have you worked with Figwheel? Try it and compare to debugging console.log statements.
- grzm 9y agoYour parent addresses both elsewhere in this thread, for example: > [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. https://news.ycombinator.com/item?id=15142735 https://news.ycombinator.com/item?id=15142735
- yogthos 9y ago>These days I prefer writing in modern JavaScript (ES2015 and better). With destructuring, lambda syntax, extended object literals, spread syntax, and just the general language overhaul, it's basically a tie with Clojure's terse syntax. One of the biggest advantages I find with Clojure syntax is that there's very little of it, and it's much more consistent than JavaScript. Sure, you can often write code that's just as concise in Js nowadays, but there are a lot more gotchas as well. The more syntax quirks you have, the more likely it is that you'll misread something and have a subtle bug slip in. I value simplicity and cleanliness of the language as much as its expressiveness. The article also doesn't explain why the author moved to JavaScript. It sounds like the author didn't want to use the JVM, but ClojureScript works just fine on Node. My team is using Macchiato https://macchiato-framework.github.io/ https://macchiato-framework.github.io/ for some smaller projects in production right now. I'd be interested in reading more about the specific reasons, and what problems the author ran into with the Clojure stack. That would at least help address the issues going forward.
- _sdegutis 9y agoAuthor here. My main reason for moving away from Clojure and ClojureScript, and not towards Haskell or OCaml or even TypeScript (yet!) but rather towards modern JavaScript, is because in general I've been learning to appreciate the Path of Least Resistance in software development. I wrote another aspect of this in Age of the Polyglot[1], which focuses on the friction when bridging loosely-compatible tools, but there's other friction points to the non-mainstream ecosystems, like having a stagnant or decaying community, lack of libraries, etc. A lot of active development seems to be happening in the Node world in the past 5 years, and although there's probably a ton of crap, there's also a ton of gold, and that's kind of what happens when you have a thriving community. [1]: https://sdegutis.com/blog/2014-08-18-age-of-the-polyglot/ https://sdegutis.com/blog/2014-08-18-age-of-the-polyglot/
- yogthos 9y agoMy team has been using Clojure for about 7 years now, and we started using ClojureScript about 2 years ago. We're certainly finding it to be the path of least resistance compared to keeping up with Js. For example, we've been using Reagent for the front-end, and it's stayed the same all this time. Even as React itself keeps changing, all we have to do is update the library version, and everything just keeps working. Keeping up with the way Js world evolves is absolutely bonkers in my opinion. By the time you finish writing an app, the whole stack becomes outdates as people jump onto new hot thing. Even if you stick with something like React, the practices around it keep shifting, you now have Redux and Relay, and god knows what else people will come up with next week. Having a stable development environment is a big benefit in my book. I'm also not seeing any problems with Clojure community being stagnant or decaying. It keeps growing steadily, and the library ecosystem is quite excellent at this point. Since Clojure embraces the host platform, you always have access to native libraries as well. If a cool library gets developed in Js or Java, it's immediately available in Clojure. Node has a lot of hype, but I haven't seen anything developed on Node that's not available on the JVM. The only advantage of Node I see is that it takes less resources. Having actually developed some ClojureScript apps on top of Node, I think that it's a strictly inferior experience. Callbacks are much harder to work with than threads, and even promises and async result in much gnarlier code. Given my experience with it, I would only use Node for very simple applications.
- Scarbutt 9y agoTbere's also a reddit.com/r/clojure thread FWIW.