I find there are really big differences between the dev experience in Python, Node, Clojure and Erlang. JS doesn't trap errors[1], so it's tedious to debug or to have confidence in correctness, and the callback hell APIs are high friction in interactive/REPL development. Node is a fine vessel for running ClojureScript though ;)
I agree that Node once felt tangibly worse. I used Clojure for three years to avoid Node until I had to use Node at work (nobody was going to learn Clojure) and I discovered Koa when it just released.
Even back in Koa 1, co/yield/function* closed the gap for me. Nowadays it's much better with ubiquitous promise usage and async/await.
I miss various things about Clojure like the editor-as-a-repl development cycle, but in my opinion, they still amount to small technical differences that play second fiddle to business concerns.
It's interesting that JavaScript on the server has grown at the same time front & back ends have separated. Which in my experience has drastically reduced development speed.
I haven't used it, but it's still the same pseudocode:
defmodule HelloPhoenix.UserController do
def index(conn, _params) do
users = HelloPhoenix.Repo.all(HelloPhoenixUser)
render conn, "index.json", users: users
end
end
For CRUD, I'm not too convinced it's much different than what you'd be doing anywhere else.
For websockets, streaming, and other stuff beyond request -> database query -> response, then competing abstractions get more interesting.
[1] See eg the bit about NaNs in the article.