Cultural differences between Clojure and NodeJS

(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: lawrence@krubner.com

Right now I have to work with NodeJS, because I have a client who uses NodeJS. I am getting used to the asynchronous style of NodeJS. I notice a subtle cultural difference between Clojure and NodeJS. Most of the tutorials for NodeJS assume the person reading is a beginner, someone who may not understand big complex words like “asynchronous”. In the world of Clojure, there is the assumption that the person reading the article has some experience. With Clojure, there is more focus on theory, and more focus on the difficult concurrency cases that one can face while programming, problems that Clojure was designed to solve. With NodeJS, there is more the sense that the asynchronous style was a historical accident, arising from the precedent established years ago by Ajax. NodeJS tutorials have the tone “This is the way things are, this is the way you need to adapt to circumstances.” Clojure is more “This is the way things used to be, thankfully we invented Clojure so those problems are solved now.”

To be clear: some of the tutorials about NodeJS are great. Check out We Have A Problem With Promises. It looks at 4 different cases:

doSomething().then(function () {
  return doSomethingElse();
});

doSomething().then(function () {
  doSomethingElse();
});

doSomething().then(doSomethingElse());

doSomething().then(doSomethingElse);

But consider the point he makes at the opening:

Fellow JavaScripters, it’s time to admit it: we have a problem with promises.

No, not with promises themselves. Promises, as defined by the A+ spec, are awesome.

The big problem, which has revealed itself to me over the course of the past year, as I’ve watched numerous programmers struggle with the PouchDB API and other promise-heavy APIs, is this:

Many of us are using promises without really understanding them.

That last sentence sums up the world of NodeJS. Developers are expected to copy-and-paste code without really understanding it. One doesn’t run into this attitude in the world of Clojure.

Consider how Tomasz Nurkiewicz wrote about Promises and Futures in Clojure:

Clojure, being designed for concurrency is a natural fit for our Back to the Future series. Moreover futures are supported out-of-the-box in Clojure. Last but not least, Clojure is the first language/library that draws a clear distinction between futures and promises. They are so similar that most platforms either support only futures or combine them. Clojure is very explicit here, which is good.

…Promise is a thread-safe object that encapsulates immutable value. This value might not be available yet and can be delivered exactly once, from any thread, later. If other thread tries to dereference a promise before it’s delivered, it’ll block calling thread. If promise is already resolved (delivered), no blocking occurs at all. Promise can only be delivered once and can never change its value once set:

(def answer (promise))

@answer

(deliver answer 42)

answer is a promise var. Trying to dereference it using @answer or (deref answer) at this point will simply block. This or some other thread must first deliver some value to this promise (using deliver function). All threads blocked on deref will wake up and subsequent attempts to dereference this promise will return 42 immediately. Promise is thread safe and you cannot modify it later. Trying to deliver another value to answer is ignored.

But the big difference in the cultures is seen when one wants to do something complicated. Because complicated asynchronous workflows are the specialty of Clojure, whereas they are simply a historical accident in NodeJS, and in a sense they cut against the idiom. Suppose one has a long chain of functions that return Promises, but one has the equivalent of guard clauses, deep down, where one wants to break out of a few levels of the chain, while allowing some higher level part of the chain to keep recursively looping over some data, perhaps making database calls on each row in an array. How would one get that array from one iteration to the next iteration, in NodeJS? The correct answer is that you pass the array all the way down, to the depths of the Promise chain, and then include it in any Exception that you throw, so that the higher level Promises can catch the Exception, and the array will exist in the scope of the code that handles that Exception. The pattern is almost the same as using a condition system, if one was creating one’s own personal condition system, but this seems very ugly in NodeJS. But I can’t figure out an elegant way to do it. Even if there is an elegant way to do it, it is noteworthy that using Google to search for answers yields so many digressions with NodeJS, with the overall implication that one should try to avoid complicated workflows in the asynchronous style. But Google turns up a wealth of answers when asking about complicated workflows in Clojure. (Before anyone suggests that you can write any kind of code in any language, please note that my point is about the culture, not about the technology.)

Source