It's funny to me, I used to merely tolerate JavaScript... I came from Ruby (and PHP/Java/C# before that) where you could create these super complex control flow structures and JavaScript felt so verbose and unwieldy and limited.

I mean, no inheritance? No method_missing? How do you write humane, readable DSLs with just functions and prototypes?

I've explored all kinds of tricks since then: OO libraries, promises, fibers, CoffeeScript classes and all its other sugar.

What's interesting is I've swung fully back in the other direction. I find myself increasingly drawn to very simple, very JavaScripty JavaScript. Functions. Variables. Constructors. Prototypes. Closures. Arrays. Objects. I think almost all of the new JavaScript features are more trouble than they're worth.

Take promises for example. Here's some junky callbacky JavaScript:

libraryStuff(function() {
moreLibraryStuff(function() {
thirdLibraryStuff(function() {
console.log("done!")
})
})
})

Gross. Nesting. With promises you can do this lovely bit of magic:

libraryStuff()
.then(moreLibraryStuff)
.then(thirdLibraryStuff)
.then(function() {
console.log("done!")
})

Which certainly fixed the nesting problem. But you made your stack almost incomprehensible, and you made your execution thread harder to trace. And now the runtime is popping back and forth between your code and the promise library every step. But the scariest thing of all is you created a bunch of these promise objects that you could, like, return, and some totally unrelated code could interact with it and totally fudge up the control here. You took something that had really well bounded semantics and turned it into something that is wide open to be messed with in bizarre ways.

That's what power is. That's why people love promises, you have power to do all manner of outlandish control flow. Except I really don't want to have to debug your bizarre circus of promises.

Don't get me wrong, I am certainly capable of debugging your circus of promises. I just really would prefer not to.

And anyway there's a way easier solution. Because JavaScript uses function scope, you can just do this:

libraryStuff(yourResponse)

function yourResponse() {
moreLibraryStuff(yourNextResponse)
}

function yourNextResponse() {
thirdLibraryStuff(finish)
}

function finish() {
console.log("done!")
}

It's easily traceable. You get a real call stack no matter where you crash in that flow. And yeah, I doubled the number of symbols here, but that just means I was forced to actually label my application code. Which might not be such a bad idea anyway. In my production code all of these functions are going to be several lines anyway, and it's quite nice to be reminded that I should give them a good label.

Of course if this was CoffeeScript, your stacktrace wouldn't have function names because CoffeeScript threw away that feature in exchange for being able to type "->" instead of "function".

I've noticed this pattern over and over: someone gets frustrated because JavaScript doesn't give you insane tools to quickly spin up bafflingly complex flow structures. They find this frustrating, because they're used to baffling flow structures from all of the crappy code they've been forced to get comfortable with, so they write some insane library that lets you do crazy stuff in JavaScript.

The same thing happened to me in Ruby. I was so entranced by the power and magic of DSLs that I was constantly looking for excuses to return chainable objects from functions and all of this stuff. I would build things like that in production code, and feel proud of myself that I made this super powerful thing with a complicated implementation and a simple, prose-like interface.

But almost every time, after living with the interface for a while, I would realize that I could've solved the problem with just functions, literals, and arrays, and structs if I had actually taken the time to figure out the right abstractions.

Less and less do I think I need some fancy new kind of function. More and more I think I need to be more thoughtful about what the function actually does.