I never heard anyone say “let’s rewrite this in Node” unironically.
I never heard anyone say “let’s rewrite this in Node” unironically.
What we've found happens to us, is that because Clojure is dynamically typed, we actually spend more time focusing on making sure we have well specified and properly designed our data model for data which enters/leaves the application boundary, and that we use runtime validation everytime the data is about to leave the app boundary or enter it from a non-trusted source.
When we used Java and Scala, we did not spend quite as much time here, because you've already got your internal types, and you kind of take them as your data model, and rely on them for validation and specification. The issue is the types only go so far to perform validation, and you've often designed them in terms of the implementation needs, and not the domain model. A dynamically typed language like Clojure teaches you to be extra careful with data to make sure you don't mess it up, and it gives you really powerful tools for it, such as Spec and the REPL.
This turns out to help I've found in an enterprise context, because even with a statically typed language, when data enters/leaves the boundary of the application it is no longer within the purview of the type checker.
So with Clojure, we end up spending way more time thinking through our domain model and validating it. Which worked pretty well for us.
You also need to learn how to properly design an app in Clojure, and it's very different than other languages, so it's possible to overcomplicate things and shoot yourself in the foot. But if you do it right, it makes for very simple code bases that are way smaller in LOC.
Generally, we have one module that specifies our data model for the bounded context of our app. Another module to construct, validate, convert, and manipulate entities from our data model. And then we have a main module with all our APIs, each API implementation lives in its own module. Shared logic exist in a shared module. And shared state exist in another shared module.
It takes a bit of a different mindset, like knowing to ski and then trying to learn to snowboard, but for me I ended up liking it much better, and the lack of static types didn't bother me, the strong functional immutable leaning of Clojure, along with the help of the interactive REPL development style makes up for it.
If I don't specify a type in the input, I have to check in the method body that what was passed in was something usable. Skip this is very bad, the best case scenario is something your code will error out on wrong input, the worst case is it computes the wrong result with no errors.
The exact same thing happens with dynamic languages - as long as I skip the tests (or write bad tests).
Actually it was (and is) quite common to see crufty old (but statically typed) C++, Java, what-you-have-you re-written in Perl and/or Python (well before the introduction of type annotations, in the latter case).
Reason: there are multiple factors involved in choosing a suitable language, and static typing is just one of them (and by no means a universal deal-breaker).
I never heard anyone say “let’s rewrite this in Node” unironically.
Good for you (and I would never say that other than as a tired, old joke). But unfortunately "respect" for Node runs quite high in some circles, and not a few developers consider to be not just occasionally acceptable server-side language, but (from the way they talk about it) to be the bees knees basically.
Why? TypeScript of course.