Seit Beginn der Entwicklung an Node.js 2009 hat das Projekt enorme Aufmerksamkeit erfahren. Während die Spitze des Hypes Ende 2011 erreicht schien und mittlerweile wieder etwas abgeflacht ist, hat es sich zu einer ernstzunehmenden Entwicklungsplattform gewandelt. So haben etwa LinkedIn und die New York Times die Backends ihrer mobilen Anwendungen mit Node.js realisiert.

Mittlerweile haben sich einige Einsatzgebiete herauskristallisiert, in denen Node.js seine Stärken bezüglich Ein- und Ausgabe besonders gut ausspielen kann (siehe Abb. 1). So hat es sich im Webbereich als System für „weiche“ Echtzeit in Backends von WebSocket-Anwendungen und Streaming-Plattformen oder für das Implementieren von CRUD-Webanwendungen (create, read, update, delete) bewährt. Auch als schlankes, plattformunabhängiges Scripting Tool und als Plattform für Consumer Robotics konnte es sich etablieren. Daneben gibt es Module und Pakete für eine Vielzahl von Aufgaben, über die man sich auf Websites wie nodejsmodules.org einen Überblick verschaffen kann.

Node.js und die aus dem Ökosystem hervorgegangenen Module und Bibliotheken bieten eine Vielzahl an Einsatzmöglichkeiten – was genau noch der Entwicklung bedarf und was sich bereits gut verwenden lässt, zeigt die Übersicht (Abb. 1).

Beim Einsatz von Node.js für CRUD-Webanwendungen ergibt sich der Vorteil, dass sich JavaScript gleichermaßen für die Implementierung von Frontend und Backend nutzen lässt. Es gibt dafür eine ganze Reihe von Webframeworks, wobei Express wohl zu den derzeit beliebtesten zählt. Es setzt auf das etablierte Kommunikationsframework Connect, für das zahlreiche, gut gepflegte Plug-ins existieren. Connect vereinfacht es, Filter und andere Codefragmente auszuführen, bevor die eigentliche Anwendungslogik Requests verarbeitet oder Responses an den Nutzer sendet. Beispielsweise lassen sich mit ihm zusätzliche Authentifizierungsverfahren nachrüsten. Express wiederum ergänzt Connects Fähigkeiten um Funktionen zur Abbildung von Anfrage-URLs auf JavaScript-Funktionen, einen Konfigurationsmechanismus und eine Integrationsmöglichkeit für Template Engines. Insgesamt handelt es sich um ein vergleichsweise schlankes Framework, mit dem sich in Kombination mit einer Template Engine vollwertige Webapplikationen oder -dienste, die dem Paradigma des Representational State Transfer (REST) folgen, erstellen lassen.

Für viel Aufsehen hat das Framework Meteor (siehe dazu Seite 80) gesorgt, dessen grundlegende Technik das transparente Synchronisieren von JavaScript-Objekten zwischen Client und Server ermöglicht. Leider distanziert sich Meteor bewusst von den etablierten Techniken und Bibliotheken des Node.js-Ökosystems. Daher sollte im Vorhinein genau geprüft werden, ob Meteor für die geplante Applikation alle benötigten Features bereitstellt.

Moderne Webanwendungen benötigen für die gewünschte Interaktivität eine Möglichkeit, Daten an den Client zu pushen, wofür das traditionelle HTTP-Protokoll nur schlecht geeignet ist. Als Lösung für diese Aufgabe unterstützen alle gängigen Browser mittlerweile das standardisierte WebSockets-Protokoll, das bidirektionale Kommunikation zwischen Client und Server ermöglicht. Oft geht es bei den typischen Anwendungsfällen darum, kleine Datenmengen mit niedriger Latenz an die Clients zu senden. Genau in solch einem Szenario kann das asynchrone Programmiermodell von Node.js glänzen, weshalb es sich – besonders im Zusammenspiel mit der Bibliothek Socket.IO – zu einer beliebten Plattform für Echtzeitwebanwendungen entwickelt hat.

Paralleles Arbeiten

Node.js unterstützt kein Multithreading, weshalb sich bei Webapplikationen schnell die Frage nach der Skalierung stellt. Die gängige Antwort darauf liegt in einer Loadbalancing-Architektur mit sogenannten Shared Sessions. Eingehende Anfragen verteilt ein vorgeschalteter Load Balancer auf mehrere Node.js-Prozesse. Der globale Applikationszustand, beispielsweise die Information darüber, welche Nutzer gerade eingeloggt sind, wird dabei in einer Datenbank gehalten oder über Message Queues verteilt und steht so allen Prozessen zur Verfügung. Aufgrund der kurzen Startzeit einer Node.js-Anwendung lassen sich bei Bedarf dynamisch zusätzliche Prozesse zuschalten. Beim Load Balancer ist gegebenenfalls darauf zu achten, dass er WebSockets unterstützt, der Webserver nginx tut das beispielsweise erst seit April 2013.

Es gibt zwar Anstrengungen, Multiprocessing beziehungsweise Multithreading in Node.js zu integrieren – so beinhaltet es inzwischen beispielsweise das cluster-Modul – die entsprechenden Projekte befinden sich aber noch in einem relativ frühen Stadium, sodass von ihrem Einsatz in professionellen Umgebungen abzuraten ist.

Interessanterweise findet Node.js auch in der Robotics-Gemeinde starken Anklang. Das mag damit zusammenhängen, dass die dort eingesetzten Mikrocontroller meist am besten mit Single-Processing-Applikationen zurechtkommen und Sensorik-I/O einen wesentlichen Faktor darstellt. Außerdem lässt sich Node.js vergleichsweise einfach auf unterschiedliche Prozessorarchitekturen – insbesondere ARM – portieren. Vom Einsatz in Spielzeug-Dronen (zum Beispiel mit node-ar-drone) bis hin zu Arduino-Applikationen der unterschiedlichsten Anwendungsgebiete existiert inzwischen eine breite Palette von Robotics-Applikationen und -Frameworks (etwa Johnny-Five).

Der Load Balancer teilt eingehende Anfragen auf mehrere Node.js-Prozesse auf (Abb. 2).

Ein zunächst eher unerwartetes Einsatzszenario ist das Nutzen von Node.js als Ersatz für traditionelles Shell Scripting. Im Gegensatz zu Bash oder Perl lässt es sich vergleichsweise leicht unter Nicht-Unix-Plattformen installieren und bietet viele nützliche Funktionen für den Zugriff auf das Filesystem in der Core Library. Praktische Zusatzbibliotheken für diesen Zweck sind unter anderem Optimist zum Verarbeiten von Kommandozeilenparametern oder ShellJS, das Unix- Kommandos wie find, cat oder sed plattformübergreifend in JavaScript implementiert.

Entwicklungstools für JavaScript hingen lange Zeit dem hinterher, was man von nicht dynamischen Sprachen wie Java gewohnt war. Diesbezüglich hat sich in den letzten Jahren viel getan.

Der erste Schritt beim Aufsetzen einer Entwicklungsumgebung ist üblicherweise das Installieren von Node.js. Oftmals bleibt es aber nicht bei einer einzigen Installation, weil beispielsweise an mehreren Projekten entwickelt wird, die jeweils unterschiedliche Versionen erfordern. Zur parallelen Installation mehrerer Releases kann man zum einen auf Betriebssystemtools zurückgreifen, zum anderen gibt es Node.js-spezifische Versionsmanager. Sie sind sowohl für Linux und MacOS (nvm, n), als auch für Windows (nvwm, nodist) verfügbar und können jeweils alle auf der Webseite der Plattform vorhandenen Versionen zur Verfügung stellen.

Entwicklungsumgebungen

Jede Node.js-Installation beinhaltet das Kommandozeilentool Node Package Manager (npm). Mit ihm lassen sich zusätzliche Module (Tools, Frameworks oder Bibliotheken) zu einer Installation oder einem Projekt hinzufügen. Zur Verfügung stehen dabei alle in der zentralen npm-Registry vorhandenen Pakete – eine Übersicht befindet sich auf der npm-Webseite [1].

Der PaaS-Betreiber Nodejitsu verwaltet die Registry momentan in einem Data Center in den USA und bislang gibt es noch kein offizielles Mirroring-System. Daraus resultieren gelegentliche Einschränkungen bezüglich Verfügbarkeit und Latenz. Es ist allerdings möglich, selbst einen lokalen Mirror aufzusetzen, der auch die Verwaltung und Verteilung firmeninterner Module übernehmen kann.

Alle Node.js-Projekte, die npm verwenden – egal ob lokale Anwendung oder in der Registry veröffentlichte Bibliothek – beinhalten die Datei package.json. In ihr lassen sich Abhängigkeiten und verschiedene Metadaten angeben. Pflicht sind jedoch nur Angaben zu Version und Name des Projekts. Versionsangaben zu Abhängigkeiten können sehr großzügig gehandhabt werden, wodurch es bei einigen Modulen schwierig ist, identische Installationen zu erzeugen.

Während npm eher dafür gedacht ist, einzelne paketspezifische Operationen auf der Kommandozeile auszuführen, vereinfacht das Scripting-Tool Grunt die Automatisierung komplexerer Aufgaben. Es hat sich als De-facto-Standard für das Erstellen von Build-Skripten in Node.js-Projekten etabliert. Gegenüber älteren Tools wie Make oder Ant hat es nicht nur den Vorteil, dass es ebenfalls mit JavaScript arbeitet, sondern auch, dass es eine Vielzahl hilfreicher Plug-ins gibt (beispielsweise zur Codeanalyse oder zum Cloud-Deployment). Sie lassen sich mit JSON deklarativ konfigurieren und Nutzer können mit JavaScript eigene Erweiterungen implementieren.

Einige Plug-ins mit besonders häufig genutzten Funktionen stellen die Grunt-Entwickler selbst bereit, die meisten stammen jedoch aus der Community. Naturgemäß schwankt deshalb die Qualität und auch die Konfiguration ist nicht immer ganz einheitlich.

Die Unterstützung statischer Codeanalyse hat in JavaScript zwar noch nicht das Niveau von Java erreicht, es gibt allerdings vielversprechende Ansätze. Das Urgestein aller JavaScript-Analysetools ist JSLint, ähnliche Funktionen bieten dessen Fork JSHint und der Google Closure Linter. Der Fokus dieser Tools ist das Prüfen des Programmierstils, beispielsweise auf fehlende var-Angaben, die zum (versehentlichen) Deklarieren von globalen Variablen führen. JSHint bietet gegenüber JSLint eine flexiblere Konfiguration, was insbesondere bei Legacy-Code sinnvoll ist, um nicht eine Flut von Warnmeldungen auszulösen. Außerdem sind einige erweiterte Metriken enthalten, etwa die maximale Verschachtelungstiefe von Funktionen. Darüber hinaus bieten die Tools SonarQube und Plato statische Code-Analyse in Verbindung mit einer anschaulichen Visualisierung der Ergebnisse.

Für das Erstellen von JavaScript-Code bieten beispielsweise die kommerziellen Entwicklungsumgebungen von JetBrains Unterstützung. Mit WebStorm gibt es eine IDE für Web- und JavaScript-Entwicklung inklusive Node.js-Unterstützung, alternativ dazu lässt sich beispielsweise IntelliJ IDEA mit dem NodeJSPlug-in verwenden. Neben Syntax-Highlighting bieten sie eine gut funktionierende Code Completion inklusive Unterstützung für das Node.js-Modulsystem. Daneben sind Werkzeuge zum Debuggen, für Refactorings und statische Codeanalyse vorhanden. Weitere IDEs mit JavaScript Tooling sind das EclipsePlug-in Nodeclipse und die kommerzielle Komodo IDE. Neben den klassischen Desktop-IDEs gibt es zudem Cloud-Angebote wie Cloud9.

Im Bereich der Editoren bietet Vim zahlreiche Erweiterungen für Node.js [2]. Er beinhaltet bei den meisten Standardinstallationen bereits Syntax-Highlighting und Code Completion für JavaScript, mittels des Plug-ins vim-nodejs-complete lässt sich Letztere noch um die Core-Module von Node.js und lokal installierte Komponenten ergänzen. vim-syntastic ermöglicht das Ausführungen von JSLint/JSHint und markiert Fehler direkt in der betroffenen Zeile.

Optimieren und Integrieren

Ein vergleichsweise komfortables Programm, um Anwendungen mit einem hohen Ressourcenverbrauch (CPU-Zeit, Speicher, I/O) zu untersuchen, ist node-inspector. Es ermöglicht das grafische Debuggen von Node.js-Anwendungen mit den in Chrome enthaltenen JavaScript-Entwicklungstools. So lassen sich beispielsweise Memory Leaks oder die benötigte CPU-Zeit einer Funktion ermitteln. Um es verwenden zu können, ist Node.js zunächst entweder mit dem debug-Flag aufzurufen, was einen Neustart der Anwendung erfordert, oder das Signal USR1 an einen laufenden Prozess der Plattform zu senden. Damit wird der in der JavaScript-Engine V8 enthaltene Debugger gestartet, der wiederum einen TCP-Port öffnet, zu dem sich Debugging Clients wie node-inspector verbinden können.

Zu Erwähnen bleibt noch, dass Continuous Integration (CI) auch in der JavaScript-Welt Einzug gehalten hat. So bietet der CI-Server Jenkins eine gute Unterstützung von Node.js – wenn auch noch nicht auf dem Niveau von Java. Innerhalb von Jenkins lässt sich ein Shell-Skript konfigurieren, das wiederum Grunt oder Make aufruft, um das Projekt zu installieren, Tests auszuführen oder andere Node.js-Tools zu starten. Für einzelne Werkzeuge wie JSLint existieren eigene Plug-ins, die stattdessen verwendet werden können. Auch die Visualisierung von Testergebnissen ist möglich, falls der gewählte Testrunner beispielsweise das TAP-Format unterstützt.

Das Cloud-Angebot Travis CI wurde vor allem als vergleichsweise leicht zu integrierende, kostenlose CI-Lösung für auf GitHub gehostete Open-Source-Projekte bekannt. Mittlerweile gibt es ein kommerzielles Angebot für private GitHub Repositories. Da es auf speziellen Erweiterungen des Codeverwaltungsdienstes aufbaut, ist es mit anderen Repositories derzeit nicht verwendbar.

Coding Practices

Um langlebige Anwendungen zu erhalten, ist beim Implementieren von Serveranwendungen in JavaScript vielleicht mehr noch als bei Frontend-Anwendungen auf eine klare Struktur, gute Verständlichkeit und Dokumentation des Quellcodes zu achten. Viele Prinzipien und Good Practices der Frontend-JavaScript-Entwicklung lassen sich dabei auf die des Backends übertragen.

In Node.js werden alle Aktionen in einem einzigen Thread, dem Event Loop, ausgeführt. Damit er nicht blockiert, sind langdauernde I/O-Aktionen wie Dateizugriffe zu delegieren und asynchron abzuhandeln. Das lässt sich durch ein Programmiermodell erreichen, das stark auf Callbacks setzt, wobei Funktionen als Parameter an andere Funktionen übergeben und von ihnen erst aufgerufen werden, wenn ein bestimmtes Ereignis eingetreten ist. Konkret bedeutet das, dass ein korrekt implementiertes Node.js Modul versucht, nie den Event Loop zu blockieren, sondern so früh wie möglich ein Resultat zurückliefert. Die Callback-Funktion wird erst nach Beendigung einer I/O-Operation ausgeführt.

var doSomething = function (){
    fs.writeFile('message.txt', 'Hello Node', function (err) {
        if (err) throw err; console.log('It\'s saved!');
    });
    return "doSomething() finished. Not sure if the Callback has finished too";
}
Listing 1: Beispiel Callback

Da das Modell zu vielen verschachtelten Aufrufketten führt, kann es gerade bei unerfahrenen Entwicklern schnell dafür sorgen, dass sie den Kontrollfluss nicht länger überblicken, was in der sogenannten Callback Hell [3] (siehe Listing 2) enden kann. Das lässt sich umgehen, indem man diszipliniert auf explizit deklarierte Funktionen zurückgreift (Listing 3) und wenige anonyme Funktionen als Callbacks nutzt.

do1(function(){
    do2(function(){
        do3(function(){ ... });
    });
});
Listing 2: „Callback-Hell“ mit anonymen Funktionen
var callback1 = function (){
    do2(callback2);
}

var callback2 = function (){
    do3(callback3);
}

var callback3 = function (){
    ...
}

do1(callback1);
Listing 3: Callbacks mit expliziten Funktionen

Eine weitere Möglichkeit bietet die inzwischen etablierte Bibliothek async.js, die Abstraktionen für typische Callback-Ketten bietet und so den Code strukturierter erscheinen lässt. Auch das in der Frontend-Entwicklung nicht zuletzt wegen seiner Nutzung in jQuery beliebte Promise-Modell bietet einen Ausweg aus stark verschachtelten Callback-Aufrufen. Dabei liefert eine asynchron arbeitende Funktion ein Promise als Rückgabewert. Sind die aufgerufenen I/O-Funktionen beendet, wird das Promise erfüllt und entsprechende Callbacks für Erfolgsoder Fehlerfall ausgeführt. Inzwischen existieren dafür der offene Standard Promise-A+ und zahlreiche Libraries wie Q oder when.js.

Das Baukastenprinzip

Das Testen von Node.js-Applikationen stellt Entwickler vor dieselben Schwierigkeiten, die schon beim Testen von asynchronem Frontend-Code auffallen. Oft ist das Ergebnis einer asynchron ausgeführten Funktion abzuwarten, was allerdings innerhalb des Event Loops passieren muss, der nicht durch Warten blockiert werden darf. Glücklicherweise gibt es eine große Zahl von Testing-Frameworks, die helfen, den Widrigkeiten der Asynchronizität mehr oder weniger gut aus dem Weg zu gehen. Eines der ältesten Frameworks ist das zusammen mit Node.js entstandene nodeunit. Mittlerweile existieren fortgeschrittenere Varianten, die sich – ganz in Node-Manier – in Test-Runner, Assertion Library und Mocking Framework aufteilen und beinahe beliebig miteinander kombinieren lassen. Beispielsweise ist Mocha zusammen mit den Bibliotheken chai (für Behavior und Test Driven Development) und Sinon.JS (unter anderem zum Aufzeichnen von Variablenwerten und ähnlichem) eine beliebte Kombination.

Des Weiteren erfreut sich das oft zum Testen von Browser-Code verwendete Jasmine serverseitig einiger Beliebtheit. Möchte man Prüfungen nach dem Ansatz des Behaviour Driven Development durchführen, eignet sich hingegen vows gut. Eine jüngere Alternative zu den genannten Frameworks, die sich gleichzeitig zum Testen des Frontend-Codes eignet, bietet das noch stark in der Entwicklung befindliche buster.js.

Die Testabdeckung lässt sich mit dem npm-Package istanbul ermitteln. Es kann mit jedem Testframework verwendet werden und erzeugt Reports in verschiedenen Formaten. Ein schon etwas älteres und umständlicheres, aber immer noch weit verbreitetes Tool ist jscoverage. Es erstellt aus dem originalen Quellcode eine instrumentierte Kopie, in der zusätzliche Steuerfunktionen eingefügt sind, um den durchlaufenen Code zu protokollieren. Test-Runner wie Mocha unterstützen jscoverage standardmäßig.

Da die aktuelle Version von JavaScript keinen Standard für die Modularisierung von Anwendungen beinhaltet, haben sich mehrere externe Standards dafür entwickelt. So verfügt Node.js über ein einfach zu verwendendes Modulformat, das sich am CommonJS-Module-Format orientiert. Ein neues Modul lässt sich als Funktion nach einem vorgegebenen Schema in einer eigenen Datei definieren und anschließend mittels require-Kommando einbinden. Jedes Modul hat dabei seinen eigenen lokalen Scope.

Der sogenannte Strict Mode wurde mit der aktuellen JavaScript Version, ECMAScript 5, neu eingeführt. Er lässt sich durch das Pragma use strict auf Datei- oder Funktionsebene aktivieren und unterstützt das Erstellen von lesbarem und wenig fehleranfälligen JavaScript-Code, da das Verwenden einiger fehlerträchtiger oder missverständlicher Konstrukte wie dem with-Statement dann nicht mehr erlaubt ist.

Auch für JavaScript existieren mittlerweile Tools, mit denen sich eine API-Dokumentation aus kommentierten Quelltextfiles generieren lässt. Die meisten basieren auf JSDoc3, einer Markup-Sprache die sich an das aus der Java-Welt bekannte javadoc oder phpdoc aus dem PHP-Umfeld anlehnt. JSDoc3 definiert eine Reihe von Tags unter anderem zur Dokumentation von Funktionsparametern, Rückgabewerten und Exceptions. Viele IDEs und Editoren unterstützen das Erstellen und Parsen von JSDoc zumindest teilweise. Für das Generieren der Dokumentation gibt es unter anderem npm-Module und Grunt-Plug-ins – die meisten erfordern eine vorhandene Java-Installation, da JSDoc auf der damit arbeitenden quelloffenen JavaScript-Implementierung Rhino basiert. Ihr Standardausgabeformat ist HTML. Interessant ist zudem Docco, das als Besonderheit in den generierten HTML-Seiten den JavaScript-Code neben der Dokumentation anzeigt.

Irgendwann ist dann der Zeitpunkt gekommen, an dem eine Anwendung nicht mehr nur in der Entwicklungsumgebung existiert, sondern sich auch im rauen Produktivbetrieb beweisen muss. Grundlegenden Einfluss auf die Vorgehensweise hat dabei die Entscheidung, ob die Anwendung auf einem selbstgemanagten Server oder bei einem der zahlreichen Cloud-Anbieter, die Node.js als „Platform as a Service“ (PaaS) anbieten, betrieben werden soll. Bei Letzteren ist der Nutzer an die Vorgaben des jeweiligen Anbieters gebunden.

Zurück zum Tagesgeschäft

Auf einem selbstgemanagten Server gibt es zwar mehr Freiheiten, aber eben auch mehr Entscheidungen bezüglich Paketierung, Deployment, Architektur und Monitoring zu treffen. Bisher haben sich hier nur wenige Standardvorgehensweisen etablieren können. Bezüglich der Paketierung empfiehlt es sich generell, abhängige npm-Module zusammen mit der zu deployenden Software in einem Paket unterzubringen, sodass bei Nicht-Verfügbarkeit des zentralen npm-Repositories keine Probleme entstehen und sich Installationen identisch reproduzieren lassen. Bei Abhängigkeiten von nativen Modulen können diese außerdem vorkompiliert werden, was die Installation eines Compilers auf dem Produktivsystem erspart.

Eine Anwendung lässt sich entweder als Archiv packen oder mit den abhängigen Modulen in eine Versionsverwaltung einchecken. Alternativ kann man Pakete für mehrere Betriebssysteme erstellen, zum Beispiel deb (Debian) oder rpm (Red Hat Linux). Ein noch in der Entwicklung befindliches Tool mit einem anderen Ansatz ist Docker: Die Idee dabei ist, die Anwendung mit ihren Abhängigkeiten in einen isolierten LXC-Container zu installieren und diesen anschließend auf das Produktionssystem zu überführen und dort zu starten.

Für einen stabilen Betrieb sind robuste Tools zum Neustarten und gegebenenfalls Beenden von Node.js-Prozessen unerlässlich. Unter Linux bietet es sich beispielsweise an, das Init-System so zu konfigurieren, dass beendete Prozesse automatisch neu gestartet werden. Zusätzlich lässt sich das Node.js-Tool forever verwenden, das die Möglichkeit bietet, die Anwendung bei jeder Änderung an Dateien neu zu starten. Sollte ein einzelner Prozess unerwartet viele System-Ressourcen blockieren, lässt sich das Unix/Linux-Tool Monit zum Neustart Ersterer benutzen.

Node.js bietet leider nur wenige Introspektionsmöglichkeiten, sodass ein Monitoring meist auf Applikationsebene durchzuführen ist. Eine generische Schnittstelle zum Interpreter ähnlich wie JMX bei der Java Virtual Machine fehlt gänzlich. Somit bleibt entweder die Möglichkeit, eigene Monitoringschnittstellen in die Applikation zu bauen, oder eine vorgefertigte Library wie das kommerzielle Nodetime zu nutzen. Letzteres umfasst neben der Monitoring-Funktion eine Analyse von Speicher-, CPU- und Datenbankzugriffsverhalten. Falls eine noch detailliertere Analyse notwendig ist, lassen sich auch Betriebssystemtools einsetzen. Für das unter MacOS und Solaris verbreitete DTrace gibt es für Node.js beispielsweise Probes für Sockets, HTTP und Garbage Collection. Außerdem lassen sich mit dem npm-Modul node-dtrace-provider anwendungsspezifische DTrace-Probes mit JavaScript ergänzen.

Ab in die Cloud

PaaS-Angebote gibt es mittlerweile unter anderem von Amazon (Elastic Beanstalk), Heroku, Joyent und RedHat (OpenShift). Microsoft unterstützt seit einiger Zeit die Weiterentwicklung von Node.js und insbesondere dessen performante Ausführung auf Windows-Systemen. Deshalb verwundert es nicht, dass auch das hauseigene Cloud-Produkt Windows Azure, das im folgenden als Beispiel dienen soll, Node.js unterstützt. Es bietet mehrere Tarife, von virtuellen Maschinen mit Vollzugriff bis zu einer Laufzeitumgebung für Node.js. Letztere firmiert unter dem Namen „Web Sites“ und wird in mehreren Preisklassen angeboten. Für die Datenspeicherung stellt Azure unabhängig vom gewählten Tarif die Datenbanken SQL Server, MySQL und MongoDB bereit sowie die Azure-eigenen Datenspeicher.

„Web Sites“ bietet keine Unterstützung für WebSockets und auch die Verwendung einiger Node.js-Module, die auf native Bibliotheken zurückgreifen, ist nicht möglich. Für das Deployment von Anwendungen stehen mehrere Optionen zur Verfügung, etwa via git push in ein bei Azure gehostetes GitRepository oder mit automatisiertem git pull aus einem öffentlichen oder privaten GitHub oder BitBucket-Repository. Abhängige npm-Module lassen sich dabei entweder in das Git-Repository miteinchecken oder nachträglich mit npm installieren. Ein unterbrechungsfreies Deployment ist möglich.

Allgemein kritische Punkte bei der Auswahl eines Cloud-Anbieters für Node.js-Anwendungen sind das Unterstützen von WebSockets und nativen Bibliotheken, die bereitgestellten Datastores, das Deploymentverfahren und die Brauchbarkeit der Standardkonfiguration.

Fazit

Mit zunehmender CPU-Leistung entwickelt sich das Warten auf I/O zum Flaschenhals – ein Problem, für das Node.js eine Lösung verspricht. Viele Pakete und Zusatzdienste bieten Hilfe bei den unterschiedlichsten Aufgaben und stärken so den Stand der Plattform. Für zusätzliche Bewegung im Node.js-Umfeld sorgt in naher Zukunft wahrscheinlich der neue JavaScript-Standard, ECMAScript 6, und auch die Entwicklungen zum Thema Multithreading bleiben spannend. Das immense Ökosystem, der stabile, unter anderem von Google vorangetriebene Kern und die hohe Entwicklungsgeschwindigkeit sprechen dafür, dass Node.js aus der Backend-Entwicklung von Webanwendungen zukünftig nicht mehr wegzudenken sein wird.

Referenzen

  1. npm, https://npmjs.org  ↩

  2. Vim–Plug–ins: Übersichtsseite von Joyent, https://github.com/joyent/node/wiki/Vim-Plugins  ↩

  3. Callback Hell, http://callbackhell.com/  ↩