Kann JavaScript halten, was es verspricht?

Cloud-Anwendung mit JavaScript: Cutting-Edge-Technologie für die Kaninchenliebe

George Herczeg

@shutterstock/Dima Sidelnikov

Kann JavaScript halten, was es verspricht? Hat der aktuelle Hype um die Sprache einen begründeten Hintergrund? In diesem Artikel beleuchten wir mögliche Anwendungsbereiche JavaScript-basierter Technologien, um den Reifegrad der alten Skriptsprache darzustellen. Als Basis für unsere Überlegungen soll ein nicht ganz ernst gemeintes Cloud-Portal für Kaninchenfreunde dienen [1].

Wir planen, eine Kaninchenfanseite mit JavaScript-Technologien zu erstellen. Diese Fanseite soll alle populären Zielumgebungen und Plattformen abdecken. Sie soll auf einem Server in der Cloud Microservices bereitstellen, auf die browserbasierte Webanwendungen, Desktopprogramme sowie Smartphone-Apps zugreifen können.

Abb. 1: Die zentrale Position der Cloud-Anwendung mit REST-/JSON-API, das die Clients bedient

Abb. 1: Die zentrale Position der Cloud-Anwendung mit REST-/JSON-API, das die Clients bedient

Die Basis unseres Fanportals bildet die Node.js-Plattform, die aus Kostengründen in der Cloud bereitgestellt werden soll. Es gibt heutzutage eine Reihe von Cloud-Anbietern, die als PaaS (Platform as a Service) kostengünstig vorinstalliert Node.js anbieten. Die bekanntesten Anbieter sind unter anderem Modulus, OpenShift und Heroku. Wir haben uns für das Angebot von Red Hat (OpenShift) entschieden, da dieses auch das Aufsetzen von kostenlosen Webseiten erlaubt und eine Datenbank (MongoDB) out of the box anbietet. Ein weiterer Vorteil: Die Entwicklung und das Testen können auf dem lokalen Entwicklungsrechner mit einer lokalen Node.js-Installation erfolgen, da (fast) keine OpenShift-spezifischen proprietären Einrichtungsschritte erforderlich sind (Listing 1). In 15 Minuten hat man sich registriert und einen URL mit der gewünschten Serverumgebung reserviert. Die Verwaltung und spätere Aktualisierung der geplanten Webseite lässt sich mit gewohnten Mitteln wie Git erledigen.

 module.exports = {
  'ipaddress': process.env.OPENSHIFT_NODEJS_IP || 'localhost',
  'port'     : process.env.OPENSHIFT_NODEJS_PORT || 80,
  'database' : 'mongodb://myusername:mypassword@apollo.modulusmongo.net:27017/nihun8eM',
  'secret'   : 'mysecret'
};
 

Auf dem Server

Nach der Reservierung unserer Webadresse ist die nächste Herausforderung, die eigentliche JavaScript-Anwendung aufzusetzen. Hier können wir aus den Vollen schöpfen. Node.js als Plattform bietet zahlreiche Module, um die Entwicklung für Kaninchenfreunde zu erleichtern. Die meistgenutzten Module sind Express (als Middleware), Morgan (als Logger-Komponente) und Mongoose als Datenbankabstraktionsmechanismus.

Aber was sind eigentlich die Vorteile der Node.js-Umgebung im Vergleich zu traditionellen serverbasierten Lösungen? Wir wollen ja nicht aufgrund eines möglicherweise unbegründeten Hypes unsere Entscheidung über die grundlegende Technologie treffen. Es gibt eine Reihe von Argumenten, die für JavaScript auf der Serverseite sprechen:

  1. Die asynchrone Ausführung ist wohl der wichtigste Vorteil. Der überwiegende Teil der API-Aufrufe in Node.js-Anwendungen ist asynchron. Als Konsequenz muss sich der Entwickler nicht mehr um die Verteilung und Synchronisation der Businesslogik in verschiedene Threads kümmern. Die Plattform macht das automatisch.
  2. Die Zyklen der Entwicklung, die Schreib-Test-Fix-Arbeitsläufe können entscheidend beschleunigt werden, da die traditionellen Build- und Deploy-Schritte (möglicherweise gefolgt von einem Applikationsserver-Restart) entfallen.
  3. Server- und clientseitiger Code kann geteilt werden. Da auch Domainobjekte und Validationslogik in JavaScript vorliegen, können diese auf beiden Seiten unserer Anwendung verwendet werden. Die Server- und Browserseite kann auf die nur einmal entwickelte Logik verlinken.
  4. Native Unterstützung für JSON, das faktische Standarddatenaustauschformat im Webumfeld.
  5. Die Geschwindigkeit steht nicht der der kompilierten Sprachen nach, dem Browserkrieg sei Dank. Die in Node.js verwendete, von Google entwickelte V8 Engine ist dieselbe, die auch im Chrome-Browser läuft und mit exzellenter Performance besticht.
  6. Glaubenskriege über die beste Entwicklungsumgebung gehören der Vergangenheit an. Alle modernen schwergewichtigen IDEs unterstützen JavaScript hervorragend. Aber auch einfachere Editoren wie Notepad++ oder Sublime Text sind zur Entwicklung geeignet.
  7. Schluss mit der Dependency Hell. Da Node.js es erlaubt, Abhängigkeiten der Abhängigkeiten in mehreren Versionen gleichzeitig geladen zu halten, ist es kein Problem mehr, wenn mehrere verwendete Node.js-Module von demselben Modul in unterschiedlicher Version abhängen.

Natürlich ist nicht alles Gold, was glänzt

Wir dürfen die möglichen Nachteile dieser noch jungen Servertechnologie nicht verschweigen. Da der Kompilierschritt entfällt, kann es vermehrt zu Fehlern während der Ausführung kommen. Deshalb ist die testbasierte Entwicklung (TDD) sehr empfehlenswert. Statische Analyseschritte (z. B. Lint) sind Pflicht. Außerdem ist die asynchrone Callback- und Promises-basierte Programmierung für Oldstyle-Entwickler oft gewöhnungsbedürftig. Hier können Frameworks wie Koa Abhilfe schaffen, die asynchrone Logik elegant in seriell geschriebenen Code verpacken. Sehnt man sich zu typisierten Sprachen zurück, die auch eine hervorragende IntelliSense-Unterstützung der IDEs ermöglichen, wie Java oder C#? Hier kann die populäre Erweiterung TypeScript helfen.

Es ist empfehlenswert, eine serverseitige Anwendung zu bauen, die JSON-Microservices für beliebige Clients bereitstellt. So sind wir zukunftsorientiert und ermöglichen es, später mehr Zielplattformen aus derselben Quelle zu bedienen. In unserem Beispiel stellt die Node.js-Anwendung den Clients ausschließlich folgende Ressourcen bereit: Statische Ressourcen wie HTML- und CSS-Dateien sowie Bilder, businessrelevante Daten und Logik via definierte REST-URLs und WebSocket-Aufrufe werden zwischen den Clients durchgeroutet. Hierdurch wird der Server entlastet, da clientseitige Logik die Webanwendung füllt und rendert. Mit einem überraschend kurzen Code (Listing 2) können wir die Verteilung der Requests auf die Hauptkomponenten fertigstellen.

 app.use(express.static(__dirname + '/public'));
//serve static files

var apiRoutes = require('./app/routes/api')(app, express);
//handle the JSON API
app.use('/api', apiRoutes);

app.get('*', function(req, res)
//serve the main html file
{
  res.sendFile(path.join(__dirname + '/public/app/views/index.html'));
});

var server = app.listen(config.port, config.ipaddress);
//start the server

ws.doio(server, logger);
//handle websocket calls
 

Im Browser

Man könnte sich leicht zur Aussage „JavaScript im Browser ist doch ein alter Hut“ hinreißen lassen. Aber weit gefehlt. Moderne Anwendungen mit komplizierter Logik und dynamischer Oberfläche erfordern eine strukturiertere Entwicklung als die altbekannte jQuery-basierte Spaghettikodierung. Da wir eine moderne SPA-Anwendung entwickeln möchten, die auf Page Refresh verzichtet und hierdurch auf Benutzereingaben schneller reagieren kann, ist der gesamte clientseitige Anwendungscode in einer einzigen Webseite konzentriert.

Die modulare Organisation des Codes für die einzelnen Formulare der Webseite soll mithilfe des populären AngularJS-Frameworks erreicht werden. Alternativen könnten React oder Backbone.js darstellen. AngularJS ist ein flexibles MVW (Model-View-Whatever-)Framework, das auch Dependency Injection (DI) bereitstellt. Direkte DOM-Manipulation ist in der AngularJS-Community verpönt, stattdessen wird Data Binding bevorzugt, dessen Grundlage eine spezielle Auszeichnung in HTML ist. Deswegen wirbt das Framework mit dem Spruch „AngularJS ist, was HTML wäre, wenn es für Anwendungen konzipiert worden wäre“. Die hervorragende Unterstützung für Forms macht es ideal, Validationslogik deklarativ in der View (eine HTML-Datei) zu definieren. Die Anzeige der Werte, deren Validierung und die Anzeige möglicher Fehlermeldungen wird komplett vom Framework übernommen. Zudem ist die Unterstützung für JSON-basierte Backend-Services durch bereitgestellte AngularJS-Services erstklassig. In unserer Anwendung konnte der komplette Zugriff auf das JSON-API für die Verwaltung der Kaninchenfreunde in 32 Zeilen implementiert werden (Listing 3).

 angular.module('userService', [])

.factory('User', function($http)
{
  var userFactory = {};

  userFactory.get = function(id) {
    return $http.get('/api/users/' + id);
  };

  userFactory.all = function() {
    return $http.get('/api/users/');
  };

  userFactory.create = function(userData) {
    return $http.post('/api/users/', userData);
  };

  userFactory.update = function(id, userData) {
    return $http.put('/api/users/' + id, userData);
  };

  userFactory.updateLastPlayed = function(name, userData) {
    return $http.put('/api/userlastplayed/' + name, userData);
  };

  userFactory.delete = function(id) {
    return $http.delete('/api/users/' + id);
  };

  return userFactory;
});
 

Unsere Fanpage soll die Kaninchenliebhaber begeistern, deswegen implementieren wir neben den üblichen Verdächtigen, wie Benutzer- und Kommentarverwaltung, weitere Cutting-Edge-Technologien (natürlich mit JavaScript). Bereits mit AngularJS-Hausmitteln und Plug-ins ist es möglich, die Webseite viel ansprechender zu gestalten. Das ngAnimate-Plug-in und ein paar Zeilen CSS machen aus dem simplen Seitenwechsel unserer SPA-Anwendung einen animierten Übergang. Weitere Plug-ins wie Angular Carousel und ngInfiniteScroll erlauben es uns, die Kaninchenbilder in einem Karussell oder einer unendlich scrollenden Liste anzuzeigen.

Ein weiteres Goodie ist die Anzeige der letzten Bilder, die auf Flickr zum Thema Kaninchen hochgeladen wurden, auf einer Weltkarte geografisch anzuordnen. Hierzu empfiehlt es sich, die JavaScript-Bibliothek von OpenLayers zu verwenden. OpenLayers 3 erlaubt es uns, eine navigierbare Weltkarte in unsere Webanwendung einzubauen, die sich frei zoomen und navigieren lässt. Auf dieser Karte platzieren wir die Bilder, die der Web Service von Flickr im JSON-Format mit geografischen Koordinaten versehen liefert.

Um unsere Besucher beeindrucken zu können, erobern wir auch die dritte Dimension mit JavaScript. Mithilfe der Bibliothek Three.js, die die Entwicklung auf Basis von WebGL erleichtert, ist es möglich, unsere Kaninchen in 3-D zu präsentieren. Mehr noch: Frei navigierbare, virtuelle 3-D-Umgebungen und Spiele sind möglich, in denen sich Objekte (in unserem Fall Hasen), die in ein 3-D-Mesh überführt wurden, erkunden lassen. Ich darf in diesem Zusammenhang die Probleme der Technologie nicht verheimlichen: Da aktuelle 3-D-Scan-Technologien riesige Dateien (über 25 MB pro Kaninchen) erzeugen, sind die Ladezeiten großer 3-D-Szenen erheblich.

Weitere JavaScript-Technologien, die von aktuellen Browsern unterstützt werden, sind Real-Time-Kommunikation sowie Server-Push-Technik zwischen Server und Client. Hierbei benachrichtigt der Server den Browser im Falle von Statusänderungen, ohne dass der Browser unsere Cloud-Anwendung ständig pollen müsste. Durch die WebSocket-Technologie ist es möglich, die Liste der aktuell online befindlichen Kaninchenliebhaber auf der Webseite aufzulisten. Die Besucherliste kann die Statusänderungen der Gäste fast zeitgleich anzeigen. Wir binden die Socket.IO-Bibliothek auf der Server- und der Clientseite ein [2], um die Besucherliste in Realtime zu aktualisieren. Eine Erweiterung für Chats wäre die logische Fortentwicklung der Gästeliste.

Auf dem Desktop

Nachdem wir unsere Kaninchenliebhaber im Browser begeistern konnten, sollten wir uns auf eine andere Benutzergruppe konzentrieren: Die Nutzer, die sich mit Desktopapplikationen komfortabel fühlen oder deren Browser für die Cutting-Edge-Technologien zu alt ist. Wir haben Glück. Da wir uns für JSON-basierte Microservices aus der Cloud entschieden haben, ist es möglich, diese auch aus Desktopapplikationen zu nutzen. Aber wir haben uns auch zum Ziel gesetzt, möglichst viel Code in den einzelnen Anwendungen unseres Fanportals wiederzuverwenden. Können wir mit Unterstützung von JavaScript Desktopanwendungen bauen? Zwar können Node.js-Anwendungen als Standalone-Apps unter anderem mithilfe von NW.js implementiert werden, aber die Technologie und das API wirken noch nicht ausgereift.

Wir entscheiden uns für eine Umgebung, die es uns erlaubt, JavaScript-Code mit nativen Komponenten zu mischen: das Qt-Framework. So können wir mittels C++-Code direkt auf das API des Betriebssystems zugreifen und sind schnell, da unser Code zu nativem Binary kompiliert wird. Auf der anderen Seite sind wir durch Nutzung der (Java-)Scripting-Fähigkeit und QML flexibel im Aufbau des GUI und können direkt auf die JSON-Microservices zugreifen. Die Anzeige von Karten oder 3-D-Szenen wird auch unterstützt. Sollten wir uns aber dafür entscheiden, direkt HTML einzubinden, ist es mit dem vom Framework mitgebrachten WebKit-Browser auch möglich. Ein weiterer Vorteil des Frameworks: Die entstehende Anwendung kann für alle führenden Desktopbetriebssysteme wie Windows, Linux oder Mac kompiliert werden. Der JavaScript-Code in Listing 4 zeigt den Zugriff auf den JSON-Web-Service und den Aufbau eines ListModels für die Anzeige in QML.

 function getFans(token, listModel)
{
  var ajaxRequest = new XMLHttpRequest();
  ajaxRequest.onreadystatechange = function()
  {
    if(ajaxRequest.readyState === XMLHttpRequest.DONE)
    {
      var status = ajaxRequest.status;
      wait.visible = false;

      if (status !== 200)
      {
        messageDialog.informativeText = "The server returned an error while trying to log in: "+ajaxRequest.responseText;
        messageDialog.title = "Error "+status+" logging in...";
        messageDialog.visible = true;
        return;
      }
      var data = JSON.parse(ajaxRequest.responseText);
      if (data.message)
      {
        messageDialog.informativeText = "Error fetching the fans.\n"+data.message;
        messageDialog.title = "Error";
        messageDialog.visible = true;
        return;
      }

      data.sort(function(a, b){return a.username > b.username});

      for(var i=0;i<data.length;i++)
      {
        var o = {};
        o.avatar    = "../../res/user_blue.png";
        o.title     = data[i].username;
        o.detail    = data[i].name + (data[i].lastplay ? "  (last played: "+(new Date(data[i].lastplay))+")" : "");
        listModel.append(o);
      }
    }
  }
  var url="http://bunny-bunnyandcloud.rhcloud.com/api/users?token="  + encodeURIComponent(token);
  ajaxRequest.open("GET", url, true);
  ajaxRequest.send(null);
}
 

Auf mobilen Endgeräten
Dieser Abschnitt kann erfreulicherweise kurz und schmerzlos gehalten werden, da alle bis jetzt erwähnten Technologien Smartphones und Tablets unterstützen. Wir müssen keinen neuen Code bzw. keine neue Anwendung entwickeln, wenn wir die Web- und Desktop-Apps mit Sorgfalt und nach den Prinzipien des responsiven Designs entworfen haben. Unsere Webanwendung ist mithilfe von Bootstrap aufgebaut. Die mit diesem CSS-Framework erstellten Webseiten passen sich automatisch an die Zielgeräte an. Im Beispiel unserer Kaninchenfanpage wird das obere Menü auf Desktopbrowsern horizontal gestreckt angezeigt, auf Geräten mit kleinerem Display werden die Menüeinträge vertikal angeordnet. Außerdem sind die Standardbedienelemente wie Buttons und Listen out of the box mit einem ansehnlichen Standardstyle versehen, dessen Attribute sich natürlich ändern lassen. Die für die Desktopsysteme aufbereitete Qt-Anwendung kann ebenso für die mobilen Plattformen ohne Codeänderung bereitgestellt werden: Die Hauptakteure Android, iOS und Windows Phone werden unterstützt.

Fazit

Ich hoffe, mit dieser (immer noch bei Weitem nicht vollständigen) Liste JavaScript-basierter Technologien Sie überzeugt zu haben, bei Ihrem nächsten Projekt auch eine der hier erwähnten Bibliotheken in Betracht zu ziehen. Es gibt kaum ein Szenario, für das keine JavaScript-basierte Lösung existiert. Außerdem ist die JavaScript-Community sehr lebendig und wird von schwergewichtigen Unternehmen wie Google und Microsoft tatkräftig unterstützt.

Noch eine „Eigenschaft“ von JavaScript, die nicht vernachlässigt werden sollte, ist der Spaßfaktor. Es macht einfach Spaß, in einer sich beeindruckend aktiv entwickelnden Umgebung mitzuwirken [3], effektiv und schnell ansehnliche Apps auf die Beine zu stellen.
Haben Sie noch Vorschläge oder Ideen für ein weiteres cooles Feature der Kaninchenfanpage? Zögern Sie sich nicht, mich zu kontaktieren und lassen Sie uns eine neue Funktion zur Begeisterung der Kaninchenliebhaber entwickeln!

Verwandte Themen:

Geschrieben von
George Herczeg
George Herczeg
George Herczeg ist bei der Nagarro AG in München tätig. Mit mehr als zehn Jahren Erfahrung als C++-, Java-, Perl-, ASP- und PHP-Entwickler unterstützt er die Integration von Softwarekomponenten in unterschiedlichen Sprachen.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu: