JavaScript based server for JavaScript, Java based server for Java

Introduction

This post is about Node.js basics, mainly from a pragmatic point of view. The majority of TOPdesk developers have a Java background (I previously focused on backend), but during the development of my latest project my team decided to use Node.js. We have surprisingly positive feelings about it, and we think it is worth sharing our experiences.

1. Node.js. What’s that?

Node.js is a platform:

It’s a JavaScript runtime environment. Assuming that Node.js is installed, it will execute my-code.js:

node my-code.js

It has core modules (i.e. JavaScript packages) available for your code as imports. For example: fs for filesystem, http for handling requests-responses etc.

If you are very interested in Node.js, you can find more advanced topics later in this post, such as the event loop, non-blocking I/O and asynchronous programming. For now, let’s get back to the basics.

This is a Node.js based HTTP server. You just import it as a module and add one line of code to listen to HTTP requests on any port you want. In your code, you map URL paths to different functions to be invoked when the incoming path matches. Express builds up a routing table based on your mapping code, and invokes the mapped function by passing the request data (query strings, form data etc.) to it. While your function is preparing the response, it can do networking, I/O operations etc.; so everything you expect from a considerable programming language and runtime environment. After processing, another one-liner is called to pass the processed data (web page, JSON content etc.) to the response. The rest – i.e. sending back the response on HTTP to the client – is done by Express and Node.js.

3.1. Express server at TOPdesk

Express server serves as a REST container once the RESTful endpoints and routing rules are provided. But don’t forget about securing the calls on the server side, i.e. authorizing the user.

My project is frontend heavy, and so we use Node.js and Express only as a web server for the client side. The TOPdesk Application Server acts as the backend (business logic and data). In our case we don’t do anything with authorization, but in return the server side routing capabilities of Express are not leveraged.

We use the following routings:

REST API calls to the TOPdesk Application Server system.

Static file serving (images).

Responding with the same index.html for any other request. This is a single page application: index.html is loaded only once, so pages are not reloaded. Later, client side routing of Vue.js will update the GUI by loading the proper component. Furthermore, Vue.js keeps components in sync with an inner state.

Conclusions: Node.js at TOPdesk:

JavaScript is convenient for implementing a strong frontend with a Service Oriented Architecture, with a TOPdesk Application Server as backend (via its REST API). MongoDB is easy to add to the project (just like Express) once you need to store frontend state persistently.

A common mistake with structuring the code is letting the business logic flow into frontend code. Keep them separated. Let a properly designed REST API be the boundary between the frontend and the backend layers. Note that Node.js makes the code running on the server side also available for the client. This kind of “blending” is ok for some use-cases like validations, weekend check in a calendar etc.

Be open to using pure JavaScript stack for your frontend: don’t package your JavaScript into a jar file just to make it runnable on a Java based server if you don’t want to make use of the capabilities of Java. Besides, it’s not that much fun to fight with the Node.js Maven plugins.

+1: Node.js advanced (advanced for a Java developer like me).

The strength of Node.js is – besides its ease of use – its performance when the application is I/O intensive or network intensive. Performance measurements and comparisons are out of the scope of this post. I just want to say a few words about how it works inside, and why you always bump into terms like “event loop”, “single threaded” and “asynchronous non-blocking I/O” when googling for Node.js related technicalities.

The event loop running in one single thread

Node.js and JavaScript handle threads quite differently from Java, which is optimal for an average web application (although suboptimal for a mathematical algorithm). The so called event loop resides inside the Node.js engine, and loops continuously, waiting for the incoming events (operations) in a dedicated queue. This is one single thread.

Extremely slow operations can and should be outsourced from the event loop by asynchronous programming. To decide which operations count as extremely slow, check out the following figure. It shows a comparison of the cost of different I/O operations:

If you call a slow function asynchronously, then the event loop gets the work done on an external line (e.g. disk or network). This prevents it from blocking the CPU, which in turn is freed up to handle the next operation in the queue. We refer to this as the non-blocking I/O. The slow operations are running outside the event loop served by a thread pool and the fast ones are running inside, always in the same thread. No time is wasted with opening and closing threads unnecessarily. Once the slow operation is finished, the execution is passed back to Node.js (the event loop in the CPU). In practice the programmer implements this by callbacks, promises and event emitters.

The importance of asynchronous programming

The application developer needs to know how to program asynchronously to leverage its capabilities. If the code overuses synchronous calls, then slow operations keep running in the event loop, blocking everything else in the queue and resulting in a slow application.