Die Entwicklung zeitgemäßer Webanwendungen, so scheint es, erfordert den Einsatz komplexer JavaScript-Logik auf Seiten des Browsers. Dabei hat die Renaissance von JavaScript in den letzten Jahren und die damit einhergehende Erweiterung von Browser-APIs die Möglichkeiten zur Verbesserung von Funktionen und Benutzerfreundlichkeit um ein Vielfaches erweitert. Entwickler stehen jedoch vor der Frage, wie sich diese effektiv und wartbar einsetzen lassen und wie die jeweiligen Verantwortlichkeiten auf Server und Client verteilt werden sollten.

Traditionell liegt das Gewicht klar auf Seiten des Servers: In den Urzeiten des Web war clientseitige Verarbeitung entweder nicht oder nur rudimentär möglich, sodass der Server nahezu alle Aufgaben übernahm. Spätestens seit der AJAX-Revolution verschiebt sich das Gewicht jedoch zunehmend auf die Clientseite, indem der Browser des Nutzers zunehmend mehr Aufgaben mit JavaScript übertragen bekommt.

Im Extremfall – meist in Form sogenannter Single Page Applications (SPAs) – dient der Server lediglich noch als Lieferant von Daten, üblicherweise in JSON-Form (JavaScript Object Notation). Diese Datenstrukturen werden durch Templates oder manuelle DOM-Manipulation in entsprechende UI-Elemente umgewandelt. Nutzereingaben werden direkt im Browser überwacht und die jeweiligen Datenstrukturen entsprechend unmittelbar aktualisiert. Somit übernimmt der Client alles vom Aufbau der UI bis hin zur Validierung von Nutzereingaben.

Diese Verschiebung der Verarbeitung in den Browser hat deutliche Vorteile: So lassen sich Reaktionszeiten durch die Vermeidung von Serveranfragen beziehungsweise durch deren Ausführung im Hintergrund massiv reduzieren. Weiterhin ermöglicht der Einsatz von JavaScript, Standardelemente der Benutzeroberfläche um- oder neu zu gestalten.

Allerdings bestehen auch ernstzunehmende Nachteile, wenn sich Entwickler in hohem Maße auf den Browser des Nutzers verlassen. Die Grundvoraussetzung ist hierbei die Unterstützung von JavaScript. Zwar stellt das in heutigen Mainstream-Browsern nur selten ein Problem dar, jedoch gibt es eine Vielzahl potenzieller User Agents, die JavaScript nicht oder nur bedingt unterstützen. Hierzu gehören die meisten Suchmaschinen, was die Indizierung von Inhalten – ein wichtiger Aspekt sowohl im Internet als auch in Intranets – bedeutend erschwert. Zudem ist für die clientseitige Verarbeitung der entsprechende Anwendungscode zunächst an den Client zu übertragen. Damit erhöht sich das anfängliche Datenaufkommen, was zumindest den initialen Seitenaufbau bedeutend verlangsamen kann. Ein nicht zu vernachlässigender Aspekt ist auch, dass sich JavaScript im Vergleich zu HTML weitaus weniger fehlertolerant gibt, sodass unerwartete Interferenzen – ob Programmierfehler, Fehler beim Datentransfer (etwa durch Kompression bei Mobilverbindungen) oder Sicherheitsfilter – die Anwendung zum Stillstand bringen können. (Die Erfahrung der letzten Jahre zeigt, dass Letzteres nicht nur ein theoretisches Risiko darstellt: Auch große Konzerne wurden mehrfach von derartigen Problemen heimgesucht.)

Keines der beiden Extreme ist wünschenswert: Der reine Serveransatz genügt zweifellos nicht mehr den Ansprüchen zeitgemäßer Webanwendungen, aber auch der exzessiv clientlastige Ansatz stellt nach unserem Verständnis eine Überreaktion auf die neuen Möglichkeiten dar. Somit liegt, wie so oft, der optimale Weg irgendwo zwischen den Polen.

Aufbauend auf einem soliden Verständnis für die Architektur des Web sowie in Bezug auf etablierte Best Practices haben eine Reihe erfahrener Webentwickler, darunter die Autoren, einige Empfehlungen verfasst und unter dem Namen “Resource-oriented Client Architecture” (ROCA) veröffentlicht. Hierbei handelt es sich ausdrücklich weder um revolutionäre Erkenntnisse noch um die einzig akzeptierte Wahrheit. Stattdessen beschreibt ROCA einen bestimmten Ansatz bei der Webentwicklung.

Partnerschaft für sukzessiven Fortschritt

Grundlage des ROCA-Ansatzes ist ein klares Bekenntnis zu den vier Basistechniken des Web:

Es handelt sich hierbei um strukturell völlig unterschiedliche Schichten, die klar voneinander abgetrennt sind und aufeinander aufbauen. Um ein reibungsloses Zusammenspiel zu ermöglichen, verkörpern diese Techniken die Prinzipien des Progressive Enhancement, also der sukzessiven Erweiterung von Features um einen stabilen Kern.

Dieses Fundament bilden bei Webanwendungen immer die mit HTML-Strukturen beschriebenen Inhalte. Das umfasst auch die Beziehungen zwischen den Teilaspekten der Anwendung, die in der Regel durch Links und Formulare ausgedrückt werden und somit die Interaktionsmöglichkeiten beschreiben. Optionale Erweiterungen mit CSS und JavaScript setzen auf diesem Grundgerüst auf, ohne dabei die Kernaspekte im Wesentlichen zu verändern.

Somit bleiben die Grundfunktionen nicht nur für die gesamte Bandbreite potenzieller Nutzer und User Agents des Web zugänglich, sondern es entsteht eine klare Aufteilung in unterschiedliche, voneinander weitgehend unabhängige Komponenten, die auch außerhalb eines spezifischen Kontexts verwendbar sind.

Hinzu kommt die Forderung nach bewusster Trennung der Verantwortlichkeiten von Server und Client. Der ROCA-Stil verlangt dabei eindeutig, dass die Hoheit über essenzielle Anwendungslogik allein beim Server liegt, jedoch mit besonderem Fokus auf den Erhalt größtmöglicher clientseitiger Flexibilität unter Wartungs- und Aufwandsaspekten.

Der Artikel beleuchtet im Folgenden die tragenden Komponenten in diesem Zusammenspiel.

ROCA-Basistechnik 1: Server

In letzter Zeit lässt sich eine gewisse Rückbesinnung auf die – wenig überraschende – Erkenntnis beobachten, dass es sinnvoll ist, bei der Entwicklung von Websystemen der Architektur des Web zu folgen. Diese ist mit REST umfassend beschrieben. Im Geiste der Eingliederung anstelle der Bekämpfung von Webprinzipien und -Techniken geht ROCA davon aus, dass die Ressourcen des Servers “RESTful”, also entsprechend dem REST-Architekturprinzip, gestaltet und umgesetzt werden.

So ist eine, wenn nicht die wichtigste Idee des REST-Prinzips, dass jede bedeutsame Ressource des Systems durch einen URI (Uniform Resource Identifier) identifiziert wird. Nimmt man noch die Anforderung nach statusloser Kommunikation zwischen Client und Server hinzu, erlaubt das den Nutzern, jederzeit und mit beliebigen Clients direkt zu einer Ressource zu springen oder zu ihr zurückzukehren. Dies bedeutet, dass die Verarbeitung einer Anfrage nicht mehr Kontext verwenden darf, als direkt im jeweiligen HTTP-Request angegeben. Das schließt insbesondere serverseitigen Zustand (“session state”) aus, der bei der Verarbeitung einzelner Requests beigemischt wird. Bei Beachtung dieser beiden REST-Grundregeln ermöglicht man beliebige Links – etwa durch Lesezeichen oder den Austausch zwischen Nutzern – sowie die uneingeschränkte Nutzung der Vor-, Zurück- und Neuladen-Schaltflächen des Browsers. Aber auch für die Indizierung der Inhalte durch Web-Crawler oder für die Integration verschiedener Anwendungen sind diese Punkte von großer Bedeutung.

Neben dieser REST-Architektur fordert ROCA zudem, dass jegliche Funktionen durch den Server vorgegeben werden. Somit darf es keine Anwendungslogik geben, die nur rein clientseitig implementiert ist. Das liegt nicht nur darin begründet, dass die Anwendung ohne den Einsatz von JavaScript lauffähig sein soll, sondern auch darin, dass lediglich der Server die notwendige Autorität haben sollte, um Nutzereingaben und Interaktionen endgültig zu bewerten.

ROCA-Basistechnik 2: HTML

Wie angedeutet, bildet HTML die Schnittstelle zwischen Server und Client. Dieses sollte sich nach Möglichkeit auf strukturierte, semantische, layout- und verhaltensunabhängige Beschreibung der Inhalte beschränken (häufig auch als “Plain Old Semantic HTML” oder POSH bezeichnet).

Eine objektive Betrachtung von HTML zeigt, dass es sich hierbei um ein ausdrucksstarkes Datenformat handelt, dessen Semantik standardisiert, gut verstanden und weit verbreitet ist. Wichtig hierbei ist jedoch die Trennung von Inhalten und präsentationsspezifischen Informationen. So sollte HTML frei von Layout-Fragmenten wie Formatierungsanweisungen sein. Letztere sollten stattdessen in CSS-Dateien ausgelagert werden. Gleiches gilt für Präsentationslogik, die ausschließlich in JavaScript-Dateien vorhanden sein sollte. Der HTML-Code sollte niemals direkt CSS oder JavaScript enthalten, sondern lediglich die entsprechenden Dateien referenzieren. Diese Trennung der Zuständigkeiten (Inhaltsstruktur, Layout und Präsentationslogik) dient vor allem der besseren Wartbarkeit und Wiederverwendbarkeit der entsprechenden Code-Fragmente.

ROCA-Basistechnik 3: JavaScript

Trotz der Forderung, dass der Server die Anwendungslogik verantwortet, ist es aus Gründen der Ergonomie sowie zur Reduzierung der Reaktionszeiten wünschenswert, möglichst viele Aufgaben bereits auf Clientseite zu verarbeiten. Dabei sollte jedoch Duplizierung der Anwendungslogik auf Clientseite, also die Reimplementierung bestimmter Kernteile in JavaScript, unbedingt vermieden werden. So bedeutet derartige Duplizierung zum einen potenziell höheren Wartungsaufwand. Zum anderen birgt das aber auch die Gefahr, dass die verschiedenen Implementierungen derselben Fachlichkeit sich unterschiedlich verhalten. Neben den offensichtlichen Problemen der doppelten Implementierung, womöglich in der Verantwortung verschiedener Personen oder gar Teams, kann das einfache technische Gründe haben, etwa unterschiedliche Interpretationen von Zahlenwerten oder regulären Ausdrücken in der Server-Programmiersprache und in JavaScript.

Der in ROCA geforderte Verzicht auf doppelte Implementierung von Applikationslogik im Client bedeutet jedoch keinesfalls, dass ROCA-konforme Anwendungen Ergonomie und Nutzerfreundlichkeit opfern. Ziel ist vielmehr, die JavaScript-Logik so zu gestalten, dass der Server durch entsprechende Annotationen im ausgelieferten HTML die notwendigen Aspekte deklarativ an den Client übertragen kann. Dadurch entstehen auch hier generische Komponenten, die in der Regel keine direkte Fachlichkeit implementieren, sondern jeweils nur eine bestimmte Frontend-Logik.

Will man beispielsweise mit AJAX Informationen dynamisch nachladen oder aktualisieren, bedient man sich hierbei direkt der vom Server bereitgestellten Links sowie der dahinter liegenden HTML-Ressourcen. Dafür wird beispielsweise mit der JavaScript-Komponente pjax das vorliegende HTML nach entsprechenden Links durchsucht, diese per AJAX vom Server geladen und das Resultat (bzw. Teile daraus) direkt in die Seite eingesetzt. Auf ähnliche Weise lassen sich Formularinteraktionen abfangen und die entsprechenden Teilinhalte dynamisch ersetzen.

Zwar ist es derzeit populärerer, den AJAX-Datenaustausch auf JSON-Strukturen zu beschränken und diese auf Clientseite in das gewünschte HTML zu transformieren, jedoch handelt es sich hierbei meist um Duplizierung bestehender Logik, da eine serverseitige HTML-Struktur oft auf Clientseite nachgebaut wird. Zudem hat sich etwa am Beispiel von Twitter gezeigt, dass diese Art des Seitenaufbaus in der Regel keinen bedeutenden Geschwindigkeitsvorteil bringt.

Auch Validierungen lassen sich mit generischen Komponenten auf Clientseite vornehmen, ohne dass konkrete Fachlogik doppelt zu implementieren ist: Der Server annotiert die entsprechenden Eingabeelemente dafür mit entsprechenden Validierungsmustern – etwa, ob das jeweilige Feld zwingend notwendig ist oder welches Format die Eingaben annehmen sollen. Eine clientseitige Komponente kann diese generisch verarbeiten und somit die Validierung ohne Serverinteraktion durchführen. Im Falle komplexer algorithmischer Validierungen funktioniert das natürlich nicht mehr. Hier kann man ebenfalls auf AJAX setzen und sich einer Komponente bedienen, die die aktuellen Formulareingaben periodisch vom Server im Hintergrund validieren lässt und die fehlerhaften Eingaben dann entsprechend hervorhebt.

Der Ansatz, bestimmte Frontend-Logik in einzelne JavaScript-Komponenten zu kapseln, entspricht generell sehr gut dem Prinzip des Progressive Enhancement: Die Logik beziehungsweise die entsprechende Komponente wird nur geladen oder angewandt, wenn der Browser die Grundlagen dafür unterstützt. Wenn nicht, lässt sich die Anwendung trotzdem weiter verwenden, da die eigentliche Fachlichkeit serverseitig komplett abgedeckt wird (zumindest, wenn man dem ROCA-Ansatz folgt). Außerdem werden andere Komponenten, deren Anforderungen vom Browser erfüllt werden, trotzdem geladen. Dieses Vorgehen wird auch oft als “Unobtrusive JavaScript” bezeichnet, wonach die essenziellen Aspekte der Website auch ohne JavaScript-Unterstützung funktionieren sollen.

Fazit

Der ROCA-Ansatz bildet einen Gegenpol zum Trend, Logik auf den Client zu verlagern. Er beschreibt den Einsatz bewährter Methodiken, welche die Entwicklung zeitgemäßer, ergonomischer, robuster, skalierbarer und wartbarer Webanwendungen unterstützt. Dabei wird das Ökosystem des Web effektiv genutzt und somit auch vermieden, dass etwa bestehende Funktionen des Browsers unnötig neu implementiert werden.