Some better than none: sync vs. async in ssjs

This past week, I had a fantastic time travelling over to Warsaw, Poland for Front Trends 2010 conference. I was very honored to be invited to speak, and I gave the most recent incarnation of my talk on middle-end UI architecture, Rise of the Middle End (slides).

Overall, the reaction in discussions over beer, feedback/ratings, and tweets has been pretty positive. Even for those who seem to strongly disagree with my thoughts on this topic, I’m pleased that people are talking about it, which means they’re thinking about it, which means I accomplished my real goal: get people to start asking the right questions.

One of the most fascinating things to me was that immediately after I gave my talk, Doug Crockford’s talk on server-side JavaScript in some respects presented a very different view on things than my approach. So, back-to-back, two talks focused heavily on server-side JavaScript, and yet had a very different take on a key issue: synchronous vs. asynchronous.

After a few twitter conversations on the distinct differences between those two messages, I felt like it would be a good idea for me to write up a quick post to clearly state what I think about the sync/async debate, as I’m not sure it’s been well understood thus far.

Crockford is right

That’s correct, you did just read that. I think Doug is absolutely correct in his assertion that non-blocking I/O and asynchronous evented architecture are by far superior to synchronous, blocking I/O. There’s no question that JavaScript shines as an asynchronous language (despite the pains of us figuring out the right way to approach patterns like Promises), and so it’s a completely natural and right direction for Node.js to be taking server-side JavaScript into the asynchronous paradigm.

If I wasn’t clear enough, let me say it this way: async is better than sync.

Synchronous Middle-End?

So wait, if I agree that the async Node.js approach is the best way, why do all my talks deal with synchronous JavaScript on the server via BikechainJS?

What you really need to understand is that just because you run code synchronously doesn’t mean that such code will only run in a synchronous environment. If you write the code correctly, which I’m trying to do, then synchronous vs. asynchronous execution concerns become rather moot. More on that later below.

Again, let me be clear: BikechainJS is not intended to replace or compete with Node.js.

BikechainJS and my synchronous per-request POC code/demos for the middle-end are merely side shows to the main attraction: the importance of middle-end architecture in the web stack.

Hear me on this: you should be architecting the middle-end into your web applications regardless of whether you use JavaScript on the server or not, and regardless of if you want/need to do things synchronously or asynchronously.

The back story

So now, let me explain why I still am showing middle-end code demos using synchronous approaches.

Considering the variety of web application stacks I’ve worked in over the last several years, these architectures have ranged from Java to Grails to .NET to Python to PHP. The code bases have spanned from decent to horrible. Web performance optimization is always a tuning after-thought rather than a key business-driver feature. And the applications have all been built from the back-end up rather than the front-end down.

In all cases (and indeed for most of my 10 year web dev career thus far), some things have been true across the board:

  1. I’m a front-end/JavaScript person, and I prefer not to have to dig deep into the bowels of back-end platforms to accomplish my front-end tasks.
  2. Universally, when I attempt to re-factor the front-end for web performance optimization, I run into the hassles of not having adequate control over the middle-end pieces (buried deep in the platform/framework guts), and moreover, I often have to deal unnecessarily directly with how the back-end works just to make changes to the front-end.
  3. And most importantly, they have all been 100% in the synchronous, per-request paradigm of the web stack. They all used synchronous, single-threaded (process-oriented) web servers like Apache or IIS.

That reality may not be your reality where you work. And if not, great. But having had a dozen jobs so far and seeing the same patterns repeated consistently, I’m willing to believe it’s more the norm than the exception that synchronous per-request is the overwhelmingly common paradigm, and that no matter how hard platforms/frameworks try to keep front-end and back-end separate, they all fail to do so well, when the rubber meets the road.

So, mentally walk in my shoes for a moment, in the types of jobs and environments I’ve been in for the majority of my career. The web application code bases are well established, and for the most part working ok. The boss(es), and 3-8 other devs on the team, are all pretty familiar with that paradigm. The IT support staff are all very familiar with the quirks and behaviors of that stack, and are in some cases quite experience/certified in how to manage it and ensure production up-time.

More than anything, stability and status-quo rule the pack.

The plot thickens

For my last several jobs over the last 2+ years (aka, long before Node.js came around), I’ve been trying to find a pragmatic way to introduce server-side JavaScript into the architectures of the web application stacks at my jobs. My goal has been to find a realistic way to address the middle-end failings of all these different web application stacks, especially in a repeatable and patterned way, and I feel that server-side JavaScript provides a very compelling answer to many of those questions.

Reality check: It is not particularly easy to introduce asynchronous code into a synchronous environment. It requires some very careful planning and often times some complicated and risky changes to existing architecture. In short: it messes with stability and the status quo.

I’ve tried to pitch how server-side JavaScript can be of benefit, but whenever my boss or team starts to evaluate how to make that happen, major sticking points like that are always the death of the idea. For my jobs, their pragmatic (and defendable) position is that they would not be willing to devote the time to such radical rearchitecture (like replacing Apache with Node.js) and/or re-writes of significant portions (or all) of the code base, just to get JavaScript in the server part of the stack.

The biggest argument for server-side JavaScript at this point is massively scalable performance. But most of the jobs I work at never see enough performance bottlenecks where we could ever eventually prove the speedups in any measureable way.

All in all, I’ve had to face this reality in my jobs: if I want to do server-side JavaScript, I’m going to have to find a way to do it that fits more nicely into existing architecture and doesn’t cause quite so many waves. Otherwise, server-side JavaScript will only ever be something I get to toy around with on fun experiments like chat servers (web sockets) and games, and never see any real production usage.

Swim with the current

Instead of trying to simultaneously fight the battle of changing to asynchronous architecture and to switch to middle-end architecture using server-side JavaScript, I’ve chosen to separate those two battles and focus just on one of them for now.

What do I mean? There’s still an uphill battle to get server-side JavaScript into the stack in my real-world job place, but if it’s ever going to happen, it’s almost certainly going to need to play easily and nicely with the existing synchronous per-request paradigm.

Is it possible to use Node.js in this way? Theoretically, yes. You can run Node.js as a separate server instance, and from your synchronous code (PHP, Java, etc), make a blocking I/O call over to Node.js to ask it do something, and block the process waiting for the response. You can run Node.js like a proxy server in tandem with Apache, etc.

But notice what we’ve done: we’ve taken something whose almost entire value-proposition is performance from asynchronous eventing, and handcuffed it in an awkward and inefficient way to make it fit into our synchronous world.

In that respect, running synchronously against Node.js over an HTTP connection is not really conceptually much different than just running the JavaScript directly in a sub-process. It is however probably going to lose any possible performance benefits when considering the on-server overhead of making such HTTP requests as opposed to direct process execution/communication. Moreover, Node.js is phenomenally powerful and complicated, but restricting it in this way makes it be very much overkill for the simple things we want it to do.

Switch into an easier gear

After pushing about and thinking on these complications for quite awhile, that’s where BikechainJS was born. It’s an incredibly simple, stripped-down, highly-focused, synchronous, single-thread/single-process approach to running server-side JavaScript. It has only the bare minimum necessary to accomplish middle-end tasks, like file I/O, process execution, etc. It has NONE of the bells and whistles that make Node.js so sexy, but it also isn’t hampered by any of them getting in the way of its very specific task: run the middle-end.

BikechainJS is not what you want if you’re planning to write a significant amount (or all) of your server code in JavaScript. BikechainJS cannot do many of the most awesome things that Node.js can do.

But BikechainJS can easily be fired up to execute some simple JavaScript logic for middle-end tasks without creating too much overhead in your existing web stack and code. It has absolutely no dependencies except V8, and it’s just a single executable binary file. It’s footprint is extremely small, and it touches almost nothing that you don’t tell it to, which greatly reduces the risks involved in introducing it into your existing code.

BikechainJS is not designed to replace Node.js, it’s designed to run in all the other places where Node.js is too awkward, risky, or difficult to implement.

Sync vs. Async

It’s very important to note that just because I’m currently executing JavaScript in a synchronous way doesn’t meant the code itself is purely/only synchronous.

Most of the code I’m writing, I’m using Promises as a way to cleanly express logical steps which are reliant on each other, even if one of the steps is not immediate/synchronous. Using Promises, code can easily be written that will either work synchronously or asynchronously with little or no code changes at all.

You see, I obviously don’t want to needlessly tie my code to having to run in a synchronous way. I just want to execute my code synchronously, for now, so that it’s easier to integrate with the rest of the synchronous stack. That’s not so evil, is it?

You can very easily take a lot of this code and drop it into an asynchronous JavaScript environment like Node.js, and without much effort to adjust, it should run just fine. This is important in terms of future-proofing the code to be more useful as paradigms shift. I have the flexibility to run synchronous or asynchronous as the situation dictates. This is a very powerful realization.

Putting it into practice

How I am currently using this approach (and middle-end concepts) for my real-world job is to start to take little tiny pieces of the existing code, such as routing, headers, etc, and little by little, re-write them in JavaScript. In my existing web stack, when I want to hand off the execution context to my JavaScript code, I simply execute the BikechainJS environment and hand it some data and wait for the response.

Since the tasks it’s doing are very small and focused, it takes practically no time/overhead at all to do so (certainly way less than constructing and transmitting an HTTP request, even on-server, to a socket server instance).

Eventually, I hope that all of the middle-end logic in our app will be in BikechainJS driven middle-end JavaScript code. But I have the freedom to make the switch in very small chunks without major refactoring or rearchitecture. I’ve found a more plausible approach that my boss doesn’t get as worried about when I propose.

Bottom-line: I’ve found a way to introduce server-side JavaScript to an environment that otherwise flatly rejected the notion of a major sync-to-async rearchitecture. I believe that some server-side JavaScript is better than none at all.

I secretly hope that this move will be just a “gateway drug”, and that eventually, we can move to a much more powerful and asynchronous approach to our middle-end and back-end, probably using Node.js. Because I’ve written most of my code to be agnostic of such concerns, such a switch down the road shouldn’t be as painful as it otherwise might have been. We’ll already be more than halfway there with server-side JavaScript in the stack, and introducing asynchronous architecture patterns (while challenging) won’t necessarily be impossible to sell to the decision makers.