Kolumne: The Good Parts

JavaScript-Tools im Teenager-Alter
Kommentare

Große JavaScript-Projekte sind heute keine Ausnahme mehr, sondern die Regel. Komplexe Systeme bestehen immer aus diversen unterschiedlichen Komponenten, deren Zusammenspiel ein großes Ganzes ergibt. Um einen reibungslosen Ablauf während der Entwicklung zu gewährleisten, ist es wichtig, die einzelnen Applikationsteile sowie das eingesetzte Tooling zu verknüpfen und unter Kontrolle zu halten.

In meinem Job habe ich tagtäglich mit diversen unterschiedlichen Build- und Infrastruktur-Setups zu tun. Diese sind nicht nur auf JavaScript beschränkt, sondern beziehen häufig weitere Sprachen und Technologien wie Datenbanken, Messaging-Systeme und Suchindizes mit ein. Wenn ich kein existierendes Setup verwende oder für Kunden erweitere, ist es meist meine Aufgabe, problemlösungsspezifische Setups zu entwerfen. Auch außerhalb meiner täglichen Arbeit benötige ich oft entsprechende Umgebungen für Prototypen und Open-Source-Projekte, an denen ich in meiner Freizeit arbeite. Um nicht in jedem dieser Fälle wieder bei Null beginnen zu müssen, habe ich mir eine Art Baukasten geschaffen, den ich – mit entsprechenden Anpassungen versteht sich – in nahezu jedem der zuvor beschriebenen Fälle einsetze. Eine derartige Grundlage spart mir viel Zeit bei der Entwicklung eines komplexeren Systems, ohne dabei auf meine gewohnte Toolchain verzichten zu müssen. Dieser Artikel beschreibt dieses Setup und die dafür über Jahre hinweg ausgewählten Technologien im Detail. Außerdem beleuchte ich einige der Hintergründe, die zu diesen Entscheidungen geführt haben. Das Ergebnis ist ein fast perfektes Build-System für die meisten JavaScript-Projekte – oder zumindest ein sehr solider Grundstock.

Problemstellung

In nahezu jedem Projekt werde ich mit den gleichen Problemstellungen konfrontiert:

  • Statische Codeanalyse (Linter, Coding-Style, Metriken …)
  • Testausführung (Unit Tests in einer Crossbrowser-Umgebung)
  • Externe Abhängigkeitsverwaltung (Libraries und Tools)
  • Interne Abhängigkeitsverwaltung (korrekte Reihenfolge projektinterner Pakete)
  • Paketierung für den Produktivbetrieb
  • Management aller dieser Aufgaben in einem übergreifenden Build-System

Natürlich existieren neben den genannten noch diverse weitere spezielle Aufgaben. Jedoch handelt es sich bei der aufgeführten Liste um Anforderungen, die sich für die Mehrheit aller Projekte wiederholen. Nachdem ich über die letzten Jahre verschiedenste Tools für jede der Problemstellungen im Einsatz hatte, haben sich nach dem aktuellen Stand ganz klar Favoriten herauskristallisiert.

Statische Codeanalyse

Der erste Schritt zur Entwicklung von qualitativ hochwertiger JavaScript-Software ist die Einhaltung bestimmter Grundregeln. JavaScript ist eine sehr flexible Sprache, die extrem viele unterschiedliche Konzepte und Variationen bei der Lösung eines Problems erlaubt. Leider ist es eben diese Flexibilität, die häufig auch zu Fehlern und Ungenauigkeiten führt. Die einfachste Möglichkeit, diesem Dilemma entgegenzuwirken, ist der Einsatz statischer Codeanalysetools, im Speziellen sog. Linter. Sie sind in der Lage, mögliche Fehler im Code noch vor der eigentlichen Ausführung zu identifizieren und so deren Konsequenzen zu verhindern. Zum jetzigen Zeitpunkt existieren drei große Vertreter dieser Kategorie von Analysetools: JSLint, JSHint und ESLint. Alle drei verfolgen das gleiche Ziel, benutzen hierbei jedoch unterschiedliche Herangehensweisen.

Aufmacherbild: a wrench as a tool on a computer keyboard von Shutterstock / Urheberrecht: Lisa S.

JSLint

JSLint, 2002 von Douglas Crockford geschrieben und veröffentlicht, war das erste Analysetool seiner Art. Crockford schrieb JSLint nahezu parallel zur Veröffentlichung seines Buchs „JavaScript: The Good Parts“. Darin beschreibt Crockford detailliert, welche Teile der Sprache gefahrlos eingesetzt werden können und auf welche besser verzichtet werden sollte, um etwaigen Problemen und Uneindeutigkeiten vorzubeugen. JSLint prüft den ihm übergebenen JavaScript-Code auf den Einsatz nahezu aller in Crockfords Buch beschriebenen Problemfälle und meldet sie. Hierbei lässt sich in begrenztem Umfang konfigurieren, welche der Überprüfungen durchgeführt werden sollen und welche nicht. Viele der angewendeten Kriterien sind jedoch fest in dem System verankert und lassen sich weder abschalten noch konfigurieren. Eben diese Hartnäckigkeit, mit der Douglas Crockford an vielen der Regeln festhält, hat 2010 zu einem Fork des Projekts geführt. Aus JSLint entstand JSHint.

JSHint

JSHint ging 2010 aus dem JSLint-Projekt hervor. Die Gründe waren hauptsächlich Uneinigkeit über die Konfigurierbarkeit einiger der Checks des Tools. Eine Gruppe um Anton Kovalyov wünschte sich mehr Einstellungsmöglichkeiten des Linters, die es ermöglichen sollten, auf Wunsch gegen einige der von Crockford formulierten Best Practices zu verstoßen. Da Crockford dies strikt ablehnte, entstand JSHint, ein direkter Fork der damaligen JSLint-Codebasis. Um JSHint hat sich mittlerweile eine nicht zu unterschätzende Community gebildet, welche neue Checks einbaut und die existierenden pflegt und dokumentiert. Aus diesem Grund ist JSHint momentan das Mittel meiner Wahl, wenn es um das Linten von JavaScript-Dateien geht. Ein Wort der Warnung ist jedoch angebracht: JSHint ist in seiner Ausgangskonfiguration sehr viel weniger strikt in der Überprüfung von möglichen Problemstellen im Sourcecode. Aus diesem Grund sollte dringend für jedes Projekt eine detaillierte Konfiguration vorgenommen werden, in der viele der standardmäßig deaktivierten Checks wieder eingeschaltet werden. Ein guter Ausgangspunkt kann die jshint.json in meinem zuvor referenzierten Basisprojekt sein.

ESLint

ESLint ist der jüngste Spross der Familie der Linter. Von Nicholas C. Zakas im Juni 2013 ins Leben gerufen, handelt es sich hierbei um ein neues Projekt, welches mit dem Ziel erschaffen wurde, nicht nur neueste Technologien und Bibliotheken zur Lösung des Problems einzusetzen, sondern ebenfalls einfach erweiterbar zu sein. Dass die Erweiterbarkeit eines der Hauptziele des Projekts ist, ist sehr schnell ersichtlich, wenn man einen Blick auf die Codebasis wirft. Jede einzelne Überprüfung ist in einem eigenständigen Modul implementiert und lediglich per Hook in den Kern des Linters eingehängt. Auch der Aufbau der sog. „Formatter“, die für die abschließende Ausgabe der gefundenen Ergebnisse zuständig sind, zeigt deutlich die Modularität des ganzen Systems.

ESLint erlaubt recht eindrucksvoll, auf einfache Art und Weise eigene Regeln in das System zu integrieren, die anschließend bei der Ausführung ebenfalls überprüft und protokolliert werden. Auch wenn es sich auf dem besten Weg befindet, in meinen Projekten JSHint abzulösen, so ist es momentan dennoch mehr ein zusätzlicher Schritt bei der Analyse als ein echter Ersatz. Die Gründe hierfür sind einfach: Erstens ist die IDE-Integration von ESLint noch nicht so perfekt, wie es mit JSHint der Fall ist. Zweitens muss sich das Projekt noch etwas länger bewähren, bis ich es als Ersatz eines etablierten Tools zum Einsatz bringe. Es befindet sich allerdings auf dem besten Weg, die Nummer eins zu werden und ist daher sicherlich mehr als nur einen Blick wert.

Metriken und Coding-Style

Tools zur Berechnung sinnvoller Metriken auf JavaScript-Codebasen sind leider noch Mangelware. Erste Gehversuche auf diesem Gebiet machen Applikationen wie plato. Hier muss sich jedoch noch so einiges tun, bis wir in JavaScript auf dem Niveau anderer Sprachen angekommen sind. Zur Validierung des Coding-Styles bietet sich das zuvor angesprochene ESLint mit einigen projektspezifischen Regeln an. Des Weiteren habe ich viel Gutes über JSCodeSniffer gehört. Ein Blick auf dieses Tool schadet also bestimmt ebenfalls nicht.

Automatisierte Testausführung

Automatisierte Tests sind bei der Agilität und Geschwindigkeit heutiger Softwareentwicklung oft nicht mehr wegzudenken, um Codequalität zu gewährleisten. JavaScript-Entwickler werden hierbei außerdem noch vor ein weiteres Problem gestellt: Die schiere Menge unterschiedlicher Zielsysteme der Software macht manuelle Tests nahezu unmöglich. Würde man ein Softwareprodukt während der Entwicklung kontinuierlich auf allen unterschiedlichen Browsern, Betriebssystemen und Mobilplattformen testen, die man seiner eigenen Browsermatrix nach unterstützen möchte, so käme man zu nichts anderem mehr. Hierbei spreche ich nicht von etwaigen QA-Abteilungen, die vor einem Release nochmals händisch die Kompatibilität mit allen geforderten Plattformen sicherstellen. Nein, ich beziehe mich darauf, während eines Refactorings oder der Entwicklung neuer Features schnell und unkompliziert sicherstellen zu können, dass die gemachte Änderung keine unvorhergesehenen Nebeneffekte hat und die Software den definierten Parametern entsprechend funktioniert. Während es natürlich unterschiedlichste Arten von Tests gibt, um diesem Problem Herr zu werden, so sind Unit Tests meist der erste Ansatz zur Lösung des genannten Dilemmas. Die Anzahl unterschiedlicher Testrunner, Testframeworks und Assertion-Bibliotheken scheint in JavaScript nahezu endlos. Ein Setup, das sich für mich sehr gut bewährt hat, ist eine Kombination aus dem Karma-Runner und Jasmine unter Zuhilfenahme des einen oder anderen zusätzlichen Plug-ins wie jasmine-jquery und Sinon.JS.

Crossbrowser Unit Tests leicht gemacht

Karma-Runner ist ein Framework zur Ausführung von Unit Tests in Browsern, das als Bestandteil von AngularJS durch Google entwickelt wurde. Es verfolgt einen Client-/Serveransatz, dessen Grundstein vor geraumer Zeit mit JsTestDriver gelegt wurde und sich bewährt hat. Karma-Runner nutzt im Vergleich zum in die Jahre gekommenen JsTestDriver jedoch moderne Technologien und ist diesem mittlerweile auch in puncto Stabilität überlegen.

Die Idee hinter beiden Laufzeitumgebungen ist die gleiche: Es wird ein HTTP-Server eingesetzt, um beliebige Browser mit der Testumgebung zu verbinden. Nach dem Aufruf einer entsprechend präparierten Seite übernimmt der Testserver die Kontrolle über den Zielbrowser. In dieser Umgebung können nun Tests zur Ausführung gebracht und deren Ergebnisse zurück an den Server übermittelt werden. Durch diese Technik ist es möglich, beliebige Testframeworks in unterschiedlichen Browsern parallel zur Ausführung zu bringen und die Ergebnisse gesammelt bereitzustellen. Die Ergebnisse können anschließend in einer IDE angezeigt, vom Continous-Integration-System verarbeitet oder auf sonstige Art und Weise dargestellt werden. Da es sich bei der Verbindung zwischen Testserver und Browser lediglich um standardisiertes HTTP handelt, kann die Verbindung auch über das Netzwerk erfolgen. Es ist somit problemlos möglich, das Verhalten der Applikation auf unterschiedlichen Betriebssystemen oder Mobilgeräten zu testen.

Natürlich muss eine Abwägung vollzogen werden, wie viele unterschiedliche Umgebungen durch den Entwickler selbst direkt während der Entwicklung getestet werden und welche letztlich erst während eines Continous-Integration-Zyklus oder vor einem Release vollzogen werden. In den meisten Projekten hat es sich für mich bewährt, während der Entwicklung lediglich in einem PhantomJS oder Chrome zu testen; vor dem Merge eines neuen Features nochmals in einer Internetexplorer-VM und anschließend durch das Continous-Integration-System in der gesamten zu unterstützenden Browsermatrix.

Ist das Problem der Testausführung und Verteilung durch den Karma-Runner gelöst, so bleibt immer noch die Frage nach einem Testing-Framework, das die Strukturierung und Durchführung der Tests übernimmt, denn Karma-Runner ist eine reine Implementierung einer Laufzeitumgebung. Das eigentliche Testen überlässt der Runner anderen, wie Jasmine, QUnit oder Mocha.

Jasmine

Jasmine ist eine Kombination aus einem Testframework und einer Assertion-Bibliothek. Mit dieser Komponente lassen sich sowohl die Testausführung strukturieren als auch Eigenschaften der Software sicherstellen. Jasmine setzt hierbei eine BDD-ähnliche Syntax ein, die sich JavaScripts funktionale Konzepte stark zu eigen macht. Aus diesem Grund eignet es sich ausgezeichnet für den Einsatz in modernen Testumgebungen. Darüber hinaus existiert eine Integration für Jasmine mit dem Karma-Runner, die sich leicht nutzen lässt.

Jasmine hat sich in meiner täglichen Arbeit gut bewährt. Außerdem wird die eingesetzte Syntax von Jasmine nach kurzer Einarbeitungszeit von den meisten Entwicklern als strukturiert und für JavaScript-Tests als gut geeignet wahrgenommen.

Ich persönlich setze Jasmine gerne in Kombination mit dem Plug-in jasmine-jquery ein, da mir dieser Zusatz alles Nötige liefert, um in Kooperation mit dem Karma-Runner HTML-Fixtures zu laden und zu verwalten sowie saubere Assertions über den DOM zu formulieren.

Sinon.JS

Sinon.JS darf ebenfalls in keinem meiner Projekte mehr fehlen. Hierbei handelt es sich um eine Bibliothek zur Erstellung von Spies, Stubs und Mocks, geschrieben von Christian Johansen. Noch nie war es so einfach, einzelne Bereiche der Applikation voneinander zu isolieren, um strukturierte und saubere Unit Tests zu schreiben. Auch die Funktionalität zur Überwachung von Callbacks in asynchronen Umgebungen möchte ich nicht mehr missen.

Ein absolutes Highlight stellt die Möglichkeit dar, eine Applikation von XMLHttpRequests zu entkoppeln oder den Fluss der Zeit innerhalb der Applikation präzise und vor allem synchron zu kontrollieren.

npm und Bower für externe Abhängigkeiten

Auch wenn Softwareentwickler zu der Gattung Mensch gehören, die das Rad häufig gerne neu erfinden möchten, so ist es doch meist viel pragmatischer und bringt ein Projekt schneller voran, wenn bereits existierende Ressourcen effizient genutzt werden. Dies gilt natürlich auch für bereits existierende Implementierungen von Problemstellungen innerhalb eines Projekts. Sind diese identifiziert, fehlt lediglich noch ein sauberer Weg, sie in das eigene Projekt einzubinden und auch in Zukunft zu verwalten. Zu diesem Zweck haben sich zwei große Paketverwaltungssysteme etabliert: npm und Bower.

Bei beiden handelt es sich um in JavaScript geschriebene Kommandozeilenwerkzeuge, die den direkten Zugriff auf eine enorme Anzahl von Paketen zur weiteren Verwendung bereitstellen. npm stammt hierbei aus dem Node.js-Umfeld und bietet somit eher Pakete für den Servereinsatz, wohingegen sich Bower auf Pakete für das Browserumfeld spezialisiert hat. Natürlich existieren große Überschneidungen zwischen den beiden Paketdatenbanken, da viele Bibliotheken sowohl auf dem Server als auch im Browser Einsatz finden können. Meiner Erfahrung nach hat sich eine Trennung zwischen den beiden jedoch als sehr sinnvoll erwiesen. Für den Browser relevante Pakete versuche ich über Bower zu installieren, wohingegen ich QA-, Build-Tools und Serverbibliotheken über npm verwalte. In vielen Situationen erleichtert mir diese Trennung die Arbeit, da einige npm-Pakete speziell für Node.js angepasst wurden und sich somit der Einsatz im Browser komplizierter als nötig gestaltet.

Die Verwendung von package.json– und bower.json-Manifesten ist hierbei Pflicht. Sie beschreiben Sinn und Zweck des eigenen Projekts sowie alle benötigten Abhängigkeiten. Wichtig ist es, hierbei alle genutzten Abhängigkeiten mit konkreten Versionsnummern zu versehen. Auf diese Art und Weise müssen diese nicht mit in das Versionskontrollsystem eingecheckt werden und sind doch stets abrufbar und auf jeder Entwicklungsmaschine identisch. Ein Lockfile, das ebenfalls die Versionen der Abhängigkeiten einfriert, fehlt beiden Paketmanagern leider noch. Hier kann man jedoch gespannt sein, was die Zukunft bringt.

Interne Abhängigkeitsverwaltung

Die Tage, an denen monolithische Quelltextdateien existierten, in denen aberwitzige Mengen Code standen, sind auch in JavaScript vorüber. Struktur und Modularität müssen bei aktuellen Projekten Priorität genießen. Natürlich geht dieser Wunsch mit zusätzlichen Anforderungen einher. Während der Entwicklung sollen die einzelnen Teile des Quelltexts vorzugsweise automatisch geladen und integriert werden, sodass ohne einen zusätzlichen Build-Prozess das Ergebnis direkt im Browser betrachtet werden kann. Für den Produktivbetrieb ist jedoch ein entsprechender Build-Prozess gewünscht, der nicht nur alle Abhängigkeiten in der richtigen Reihenfolge miteinander kombiniert, sondern außerdem nach Möglichkeit auch direkt noch einen geeigneten Minifizierungsprozess durchläuft und das fertige Endergebnis bereitstellt. Zusätzlich muss sich der gesamte Prozess natürlich möglichst transparent mit der Testing-Infrastruktur integrieren.

Ist all dies vielleicht zu viel verlangt? Nein, denn mit RequireJS, r.js und almond existiert eine Toolchain, die alle zuvor geforderten Bedingungen erfüllen kann – und noch mehr. Tatsächlich hat sich die Kombination dieser drei Werkzeuge und Bibliotheken bisher sehr gut für alle meine Anwendungsfälle bewährt. Hier und da ist etwas Feintuning oder die Entwicklung eigener Plug-ins vonnöten, um auch komplexer Szenarien Herr zu werden; bequem und sauber bleibt dieser Ansatz aber allemal.

RequireJS ist die Umsetzung des sog. Asynchronous-Module-Definition-API (kurz AMD), eine Spezifikation, welche den dynamischen Einsatz einzelner Module für den Browser beschreibt. Die Bibliothek erlaubt den Einsatz des definierten Systems für alle eigenen Applikationsteile sowie die einfache Integration mit externen Bibliotheken. Hierbei müssen externe Komponenten das AMD-API nicht direkt unterstützen, sondern können durch Konfiguration eines sog. Shims integriert werden. RequireJS kümmert sich während der Entwicklung darum, die einzelnen Teile der Applikation möglichst effizient, aber dennoch in der korrekten Reihenfolge zu laden und zur Ausführung zu bringen.

Für einen produktiven Build der Software kommt schließlich r.js zum Einsatz. Hierbei handelt es sich um ein Tool, welches mittels statischer Codeanalyse die Abhängigkeiten aller verwendeten AMD-Module bestimmt und diese in korrekter Reihenfolge zusammensetzt. Anschließend wird dem ganzen mit almond (<2 KB) ein minimales Interface vorangestellt, um eine entsprechende RequireJS-Umgebung zu simulieren. Bei Bedarf kann die Applikation ebenfalls in mehrere größere Module unterteilt werden, sollte sie für einen einzelnen Ladezyklus zu groß sein. Ein dynamisches Nachladen der einzelnen Blöcke kann hierbei wieder automatisiert mittels RequireJS erfolgen.

Minifizierung und Größenoptimierung

Die Optimierung der Größe ist bei heutigen JavaScript-Applikationen ein wichtiger Bestandteil des Build-Prozesses. Die übliche Herangehensweise ist die Umbenennung von funktionsinternen Variablen in möglichst kurze Identifikatoren (a, b, c, …). Hierdurch wird Platz eingespart, ohne die Semantik des Quelltexts zu verändern. Heutige Minifier gehen hierbei noch einige Schritte weiter und verwenden zusätzlich weitere Optimierungen der Größe und teilweise auch Ausführungsgeschwindigkeit. Das Tool meiner Wahl zur Minifizierung von JavaScript-Quelltext ist UglifyJS, aktuell in Version 2. In Gegenüberstellungen mit anderen Tools lieferte UglifyJS nahezu immer die besten Ergebnisse, bei vergleichsweise geringerer Durchführungszeit. Einzig der Google-Closure-Compiler im „Advanced Optimization“-Modus konnte hier nochmals merklich kleinere Ergebnisse liefern. Der Nachteil bei dessen Einsatz besteht leider darin, dass sich der Quelltext des Projekts und aller externen Abhängigkeiten einem speziellen Coding-Standard unterwerfen muss, damit der Closure-Compiler seiner Tätigkeit nachgehen kann, ohne die Semantik des bestehenden Codes zu zerstören.

Integration in ein Build-System

Wir haben nun alle benötigten Tools und Infrastrukturen zusammengestellt, um die anfänglich aufgelisteten Problemstellungen zu lösen. Um alle diese Tools miteinander zu integrieren, fehlt uns noch ein Build-System. Meine aktuelle Wahl fällt hierbei auf Grunt. Ein JavaScript-Taskrunner, der sich durch seine große Anzahl an Plug-ins für nahezu jedes JavaScript-betreffende Tool auszeichnet. Die Integration aller genannten Komponenten ist somit ein Leichtes, da für alle ein entsprechender Task existiert, der nur noch mittels npm installiert und konfiguriert werden muss.

Um die Integration jedes der genannten Tools mit Grunt im Detail zu betrachten, sei jedem ein Blick in die Datei Gruntfile.js des in der Einleitung erwähnten Repositorys ans Herz gelegt.

Alternativ zu Grunt existiert seit kurzer Zeit ein Konkurrent, der einen völlig anderen Ansatz der Konfiguration und Ausführung verfolgt: Gulp. Hierbei handelt es sich um einen streambasierten Ansatz, welcher Grunt in einigen Gebieten voraus ist, so z. B. Parallelität bei der Ausführung sowie Abhängigkeitsverwaltung bei der Taskausführung bietet. Auch wenn sich Gulp mit rasanter Geschwindigkeit entwickelt, ist dennoch nicht abzusehen, wann und ob sich dieses System zu einer echten Alternative entwickeln wird.

Grunt in guter Gesellschaft

Große Projekte bestehen zumeist nicht nur aus einem Teil, sondern setzen sich aus vielen Einzelteilen zusammen. Hier besteht oft die Notwendigkeit, nicht nur unterschiedliche Sprachen miteinander zu integrieren, sondern auch unterschiedliche Build-Systeme in einem integrierten Prozess zu vereinen. Meine Build-Umgebung für diesen Zweck ist Ant. Bisher wurde ich noch nie von diesem System enttäuscht und bin von seiner Plattformunabhängigkeit überzeugt. Daher setze ich es sowohl in JavaScript- wie auch in PHP-Projekten ein, verwalte damit einige interne Workflows und automatisiere mit seiner Hilfe auch Deployment-Szenarien. In größeren Projekten integriere ich Grunt mit Ant, indem ich den Build-Ablauf und die einzelnen nötigen Schritte mit Ant modelliere und umsetze. Für alle Aufgaben, die einen JavaScript-Task benötigen, lasse ich diesen von Ant aus durch den Aufruf von Grunt zur Ausführung bringen. Um meine Konfiguration nicht unnötig unübersichtlich werden zu lassen, setze ich für diesen Zweck diverse kleine Ant-Makros ein, die mir die Arbeit erleichtern. Ich erhalte somit das Beste aus beiden Welten: Auf der einen Seite Ant, ein robustes und bewährtes Build-System mit einer Vielzahl von Möglichkeiten zur Umsetzung komplexer Workflows. Auf der anderen Seite Grunt, einen Taskrunner mit vorgefertigter Integration nahezu jedes erdenklichen JavaScript-Tools.

Fazit

Das in diesem Artikel beschriebene Zusammenspiel unterschiedlichster Komponenten und Werkzeuge zeigt, wie es um aktuelle JavaScript-Entwicklungsprozesse steht. Wir sind definitiv auf dem richtigen Weg und haben bereits eine weite Strecke zurückgelegt. Im Vergleich zu anderen Sprachen, wie Java oder selbst PHP befindet sich JavaScript jedoch erst im Teenageralter und hat noch viel vor sich. Die wilden Jahre sind noch lange nicht vorbei und es wird noch viel Arbeit kosten, bis JavaScript zur Ruhe kommt. Dies gilt sowohl für die Sprache selbst als auch für seine Entwicklungswerkzeuge. Bis zu diesem Zeitpunkt ist es wichtig, auch weiterhin am Ball zu bleiben, ohne dabei die Stabilität eingesetzter Werkzeuge aus den Augen zu verlieren. Die hier vorgestellten Technologien bieten einen guten Ansatzpunkt, um auch für die Zukunft gerüstet zu sein.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -