Du hast deinen AdBlocker an?

Es wäre ein Traum, wenn du ihn für t3n.de deaktivierst. Wir zeigen dir gerne, wie das geht. Und natürlich erklären wir dir auch, warum uns das so wichtig ist. Digitales High-five, deine t3n-Redaktion

t3n 35

Flott zur App: Mit der JavaScript-Plattform Node.js Applikationen schnell umsetzen

Mit Note.js flott zur App.

Node.js verspricht eine schnelle Entwicklung von Realtime-Applikationen. Der Bericht aus der Praxis zeigt, ob Node.js hält, was es verspricht – und wie die Programmierung durch den Einsatz geeigneter Pakete noch einfacher von der Hand geht. Ein Showcase der Münchener Agentur Mayflower.

Um mehrere Projekte gleichzeitig verwalten zu können, ist ein Planungswerkzeug extrem nützlich. Mit einem solchen lassen sich Ressourcen von Entwicklern besser verwalten und verteilen. Kunden erhalten entsprechend genauere Auskünfte bezüglich der Umsetzungstermine für ihre Projekt. Die Anforderungen an dieses Werkzeug sind überschaubar. Es soll eine Matrix von Entwicklern und Kalenderwochen darstellen, deren Zellen den Namen des Projekts enthalten, das der Mitarbeiter über einen bestimmten Zeitraum bearbeitet. Das Tool bietet im Idealfall die Möglichkeit, Projekte und Entwickler anzulegen und beide zu verknüpfen. Und da die Applikation später für alle sichtbar auf einem Monitor laufen soll, sind Änderungen an den Daten direkt in Echtzeit sichtbar.

Es gibt eine Reihe von Werkzeugen, die diese Anforderungen erfüllen, einige von ihnen sind sogar kostenlos verfügbar. Der überschaubare Aufwand veranlasste uns dazu, die Applikation als Webapplikation auf Basis von Node.js selbst umzusetzen. Wir wollten damit prüfen, ob diese serverseitige JavaScript-Plattform wirklich das hält, was sie verspricht: eine schnelle und leichtgewichtige Applikationsentwicklung.

Installer-Pakete für Node.js sind sowohl für Windows als auch für Mac OS verfügbar und führen interaktiv durch die Installation. Auch auf den meisten Linux-Distributionen kann Node.js als Paket installiert werden. Daneben wird eine Datenbank zur Speicherung der Daten benötigt. Im Falle unserer Applikation kommt SQLite3 zum Einsatz.

Node.js ist lediglich die Plattform, die die Verbindung zwischen der JavaScript-Engine und dem Betriebssystem darstellt. Das bedeutet einerseits, dass sich mit nativem Node.js sehr vielseitig Projekte umsetzen lassen. Andererseits muss alles vom Entwickler selbst programmiert werden. Damit die Entwicklung allerdings schneller von der Hand geht, liefert der Node Package Manager (NPM) eine Vielzahl an nützlichen Paketen mit, auf die wir auch im Falle unserer Planungsapplikation zurückgegriffen haben.

Node.js mit Paketen ausstatten

Middleware-Komponenten mit Express

Das wichtigste Paket, mit dem man die Entwicklung einer solchen Applikation beginnt, ist Express, ein Web Application Framework, das neben vielen Middleware-Modulen auch Routing für die Applikation bietet. Neben Express werden außerdem der SQLite3-Treiber und Socket.IO als Realtime-Bibliothek benötigt. Diese Abhängigkeiten werden in die package.json-Datei der Applikation als Dependencies eingetragen, damit sie bei der Installation automatisch aufgelöst werden. Später müssen die Abhängigkeiten nicht mehr ins Versionskontrollsystem aufgenommen werden, ein einfaches „npm install“ in der Kommandozeile des Systems sorgt für ihre Installation.

Das Express-Paket bietet mit seinen Middleware-Komponenten vorgefertigte Lösungen für verschiedene Aufgaben. Express greift dazu auf die Middleware-Komponenten des Connect-Frameworks zurück. Beispiele für darin bereits enthaltene Middleware sind etwa die Unterstützung von Komprimierung, HTTP Basic Authentification und cookiebasierten Sessions.

Webserver mit Node.js

Unsere Planungsapplikation sollte so leichtgewichtig wie möglich sein und aus diesem Grund ohne einen separaten Webserver auskommen. Node.js verfügt selbst über ein HTTP-Modul, mit dem sich ein Webserver umsetzen lässt. Express erweitert diese Möglichkeiten, beispielsweise um die statische Auslieferung von Inhalten über die static-Middleware, die sämtlichen HTML-, CSS- und JavaScript-Quellcode für das Frontend ausliefert. Zur besseren Aufteilung werden sämtliche statische Inhalte in einem separaten Verzeichnis der Verzeichnisstruktur gespeichert. So kann das gesamte Verzeichnis freigegeben werden.

Die Matrix der mit Node.js umgesetzten Planungsapplikation kann von mehreren Nutzern gleichzeitig editiert werden.
Die Matrix der mit Node.js umgesetzten Planungsapplikation kann von mehreren Nutzern gleichzeitig editiert werden.

Die Kommunikation zwischen Client und Server beschränkt sich auf den Austausch von Daten. Zu diesem Zweck werden eine Reihe von Ressourcen in Form von URLs festgelegt und pro URL verschiedene HTTP-Methoden definiert. Das Auslesen einer Ressource erfolgt über eine Anfrage an den Server mit der HTTP-Methode GET, das Anlegen über HTTP-POST, das Aktualisieren über HTTP-PUT und das Löschen schließlich über HTTP-DELETE. Die Initialisierung der Applikation und die Definition der Routen ist aber auch schon alles, was in der Einstiegsdatei der Applikation gespeichert werden sollte.

Für die Strukturierung der übrigen Applikationslogik kommt das Node.js-Modulsystem ins Spiel. Das Ziel der Modularisierung ist es, die Dateien übersichtlich zu halten und den Quellcode sinnvoll anzuordnen. Solange die Applikation noch eine geringe Anzahl an Routen aufweist, reicht es aus, diese in der Einstiegsdatei zu verwalten. Sobald die Zahl der Routen aber so ansteigt, dass die Einstiegsdatei unübersichtlich zu werden beginnt, sollten die Routen in eine separate Konfigurationsdatei ausgelagert und über eine Funktion generiert werden. Für unsere bespielhafte Ressourcenplanungsapplikation reicht der erste Ansatz allerdings völlig aus.

Controller und Models

Für den Controller gilt, dass dieser möglichst wenig Logik aufweisen sollte. Im Normalfall werden hier die Models mit den Views verbunden. Die Applikation verfügt jedoch nicht über eine klassische View-Komponente. Stattdessen werden die Informationen an das Frontend im JSON-Format versendet, sodass Template-Engine und gerendertes HTML überflüssig sind. Der Controller kümmert sich also nur um die Instanziierung der Models und den Versand der Daten.

Die Models wiederum beinhalten die gesamte serverseitige Logik der Applikation. Das bedeutet, dass sie sich um Validierung, Escaping und Speicherung der Daten kümmern. In unserem Beispiel kommt SQLite3 als Datenbanksystem zum Einsatz, da es sich hierbei um ein sehr leichtgewichtiges System handelt. Der Zugriff auf die Datenbank wird über das NPM-Paket sqlite3 geregelt. Das sqlite3-Paket erlaubt nach der Installation die Verbindung zur Datenbank und sowohl lesenden als auch schreibenden Zugriff. Hinweis: Bei der Verwendung von SQLite als Datenbank kann es unter Umständen bei manchen Windows-Systemen zu Schwierigkeiten kommen, weil der SQLite-Treiber zuerst kompiliert werden muss, was eine entsprechende Umgebung erforderlich macht.

Das Problem beim Zugriff auf die Datenbank ist, dass sämtliche Operationen asynchron erfolgen. Das bedeutet wiederum, dass eine Entkopplung von Controller und Model schwierig ist. Der Controller soll sich um die Antwort an den Client kümmern, die allerdings erst erfolgen kann, sobald das Model die asynchrone Antwort von der Datenbank erhält. Eine Lösungsoption für diese Problemstellung bieten Promises, die für Node.js in Form des Q-NPM-Pakets vorliegen. Eine Promise stellt in JavaScript das Ergebnis einer asynchronen Operation dar. Mit Promises können vor allem ineinander verschachtelte Callbacks besser lesbar gestaltet werden. Ist die asynchrone Operation erfolgreich beendet, wird die Promise aufgelöst und eine entsprechende Callback-Funktion aufgerufen. Ähnliches gilt für eine fehlgeschlagene Operation, für die eine weitere Callback-Funktion definiert werden kann. Durch Promises können asynchrone Operationen also besser lesbar gestaltet werden. Für die Beispielapplikation bedeutet das, dass das Response-Handling im Controller verbleibt und nicht über eine Callback-Funktion in ein Model verschoben wird.

Funktionsfähiger Zwischenstand

Zu diesem Zeitpunkt ist die Applikation bereits voll funktionsfähig. Ein Benutzer meldet sich bei der Applikation an. Node.js liefert daraufhin sämtliche statische Dateien aus, also HTML, Stylesheets und den JavaScript-Quellcode für das Frontend. Sobald das Frontend geladen ist, wird eine weitere Anfrage an das Backend gestellt, um die anzuzeigenden Daten zu erhalten. Der Benutzer kann dann neue Projekte und Ressourcen anlegen und Zuordnungen von Entwickler zu Projekt vornehmen. Alle Daten kann der Benutzer im Frontend auch editieren und löschen. Die Aktionen resultieren in Ajax-Calls an das Backend, damit die Informationen auch in der Datenbank festgehalten werden.

Der Nachteil dieser Umsetzung besteht jedoch noch darin, dass die Applikation nicht von mehreren Nutzern gleichzeitig editiert werden kann. Greifen mehrere Anwender parallel auf die Applikation zu, erfahren sie nichts von eventuellen Änderungen der Anderen oder überschreiben diese im schlimmsten Fall gar. Für einen Parallelbetrieb muss die Single-Page-Applikation deshalb in einem letzten Schritt echtzeitfähig gemacht werden.

Realtime umsetzen

Zu diesem Zweck wird eine bidirektionale Kommunikation zwischen Client und Server benötigt. Das bedeutet, dass der Server dem Browser aktiv Nachrichten senden kann. Das HTTP-Protokoll eignet sich hierfür nur mit Anpassungen auf der Clientseite wie beispielsweise Long Polling. In diesem Fall baut der Client eine Verbindung zum Server auf, über die der Server bei Bedarf eine Nachricht zurücksenden kann. Diese Verbindung muss in regelmäßigen Abständen durch den Verbindungsabbruch von HTTP neu aufgebaut werden. Eine Alternative zu diesem Workaround bietet der Einsatz des Websocket-Protokolls, bei dem Client und Server gleichberechtigte Kommunikationspartner sind und beide Endpunkte Nachrichten an die Gegenseite senden können.

Für die Erweiterung der Applikation um die Kommunikation über das Websocket-Protokoll wird das NPM-Paket Socket.IO installiert. Socket.IO verwendet den Webserver von Node.js, um den Client-Quellcode auszuliefern. Das bedeutet, dass keine weiteren Bibliotheken heruntergeladen werden müssen. Durch die Unterteilung in Controller und Models, wobei der Controller die Kommunikation mit dem Client übernimmt, beschränken sich die Änderungen auf den Controller.

Der grundsätzliche Aufbau von Socket.IO sieht vor, dass sämtliche Interaktionen zwischen Client und Server innerhalb einer Callback-Funktion stattfinden. Für die Applikation bedeutet das, dass der komplette Quellcode, der für die Kommunikation benötigt wird, innerhalb einer Funktion geschrieben wird. Das verhindert eine Modularisierung und Aufteilung des Codes, durch die Implementierung eines Event-Systems lässt sich dieses Problem aber umgehen.

Jede Aktion, die eine Nachricht zu den Clients auslösen soll, verursacht ein Event auf einem speziellen Kommunikations-Model, das die Nachrichten über eine Websocket-Verbindung versendet. Jede dieser Aktionen, also beispielsweise das Erstellen einer neuen Zuordnung von Ressource zu Projekt zu einem bestimmten Zeitpunkt, erhält neben den Informationen noch die Art der Aktion, die über die Websocket-Verbindung an den Client weitergegeben wird. So kann der einzelne Client korrekt reagieren und dem Benutzer die geänderte Information in Echtzeit anzeigen.

Fazit

Mit Node.js und den NPM-Paketen lassen sich sehr schnell Applikationen umsetzen. Auch umfangreiche Anforderungen wie beispielsweise die Echtzeitfähigkeit einer Applikation können relativ problemlos implementiert werden. Das Node.js-Modulsystem unterstützt einen Entwickler bei der Strukturierung der Applikation, sodass gut wartbarer und erweiterbarer Quellcode entsteht. Unsere Erfahrung zeigt außerdem, dass sich Node.js sehr gut zur Entwicklung von Prototypen eignet.

Im hier vorgestellten Beispiel bildete Node.js die Grundlage für eine Applikation zur Ressourcenverwaltung. Durch den sinnvollen Einsatz von Frameworks entstand bei der Umsetzung viel weniger Quellcode auf Seite des Servers als auf Clientseite.

Sebastian Springer
Sebastian Springer

arbeitet seit mehreren Jahren beim PHP-Dienstleister Mayflower in München und ist dort derzeit als Projekt- und Teamleiter tätig. Sein Fokus liegt auf der Entwicklung und Qualitätssicherung von dynamischen Web-Applikationen mit JavaScript und PHP.

Bitte beachte unsere Community-Richtlinien

11 Reaktionen
Omid

Demnächst startet ein Dienst für Node.js hosting in Deutschland. Schaut euch mal http://sloppy.io

irgendeinem Spinner

Was mich an diesen „Apps“ stört ist, dass sie vorraussetzen, dass der Nutzer ständig online ist. Wenn ich schon solche Webapps baue, dann soll der Nutzer sie doch auch offline verwenden können. Ich fände einen Artikel zu Hoodie interessant, die setzen konsequent auf „Offline First“ (wie sie es nennen) und bauen ebenfalls auf Nodejs auf. Leider gibt es wohl noch keine stabile Version, aber die Entwicklung ist sehr aktiv.

cephei

2014, wo du nahezu überall auf dem Planeten ständig online sein kannst, ist "Offline first" wohl kaum mehr zeitgemäss.

web

"Offline first" wird immer wichtiger. Denn die Verbindungen sind keineswegs durchgehend stabil. Schlechte und langsame Verbindungen, Verbindungsabbrüche, Wechsel in das Wlan oder zwischen Wlans, …

"Offline first" bezieht sich nicht nur darauf, dass der Nutzer keine Internetverbindung hat, sondern dass auch zu einem späteren Zeitpunkt synchronisiert werden kann, oder dass keine Daten verloren gehen weil der Nutzer genau im Moment des Speicherns einen Verbindungsabbruch hat.

Und nein, LTE ist dabei keine Rettung, denn die konstante Verbindung gibt es auch damit nicht.

Tino

Ein super Projekt, dass fleißig weiter entwickelt wird. Best practise generator für Express und Angular mit Socket.io etc... richtig gut.

https://www.npmjs.org/package/generator-angular-fullstack

painschen

Lernt doch einfach so Apps entwickeln statt dauernd neue Techniken zu suchen mit denen es auch geht.. :) Eine App ist auch so schnell entwickelt!

macpat

Nicht unbedingt. Mit der Jiffbox von DF hast einen Cloudserver um max. 14 EUR im Monat. (kein sponsered Post).

tm:dev

Leider ist Node.js bei aktuellen Hostern noch nicht angekommen, sodass man schon große Pakete mit Root Zugriff benötigt.

cephei

uberspace <3 - kann ich allen empfehlen. Ist mit abstand der beste Anbieter den ich gefunden habe. Soweit ich weiss, sind aber 10GB Diskspace das Limit pro Account. Für Grossprojekte weicht man dann ja eher auf einen eigenen Server aus.

irgendeinem Spinner

Bei Uberspace bekommst du Nodejs und kannst selbst bestimmen wie viel dir das wert ist. Mindestens 1 Euro pro Monat musst du halt investieren.

Du musst angemeldet sein, um einen Kommentar schreiben zu können.

Jetzt anmelden