Best Practices im Umgang mit AngularJS

AngularJS done right
Kommentare

Egal in welcher Programmiersprache man sich bewegt, die Situation sieht immer ähnlich aus: Sie beginnen die Arbeit mit einem neuen Framework in den meisten Fällen mit einem Tutorial oder mit einer Einsteigerdokumentation. Nachdem Sie diese erste Hürde erfolgreich gemeistert haben, werden Sie gleich mit der Implementierung Ihrer ersten Applikation beginnen wollen. Und genau da liegt das größte Problem vieler Applikationen …

Den Entwicklern fehlt die Erfahrung mit dem Framework, Probleme schleichen sich im Design und der Architektur der Applikation ein und am Ende wartet der gefürchtete Legacy-Code, den jeder gerne löschen und neu schreiben möchte. Es ist also erstrebenswert, dass Sie Ihre Werkzeuge bereits zu Beginn des Projekts so gut kennen, dass Sie eine stabile, wartbare und erweiterbare Architektur für Ihr Projekt aufsetzen können. Das führt dazu, dass Sie niemals etwas Neues ausprobieren werden und es mit der Zeit furchtbar langweilig wird. Aber keine Sorge: Dieser Artikel versucht, das Problem speziell für AngularJS-1.x-Applikationen zu lösen, indem zum einen einige Best Practices vorgestellt werden und zum anderen gezeigt wird, wie Sie eine Applikation erstellen können, bei der Sie gewisse Teile relativ gefahrlos austauschen können.

Die Grundlage dieses Artikels ist vor allem der umfassende Styleguide für AngularJS von John Papa, der auf GitHub frei verfügbar und in zahlreiche Sprachen übersetzt ist.

Warum ist es jetzt speziell für AngularJS sinnvoll, sich über Best Practices zu unterhalten? Das ist ganz einfach erklärt: Das Einsatzgebiet von AngularJS liegt meist im Bereich umfangreicher Single-Page-Applikationen. Umfangreich heißt zahlreiche Features, komplexe Strukturen und viel Quellcode. All das bietet viel Potenzial für Fehler, die sich kurzfristig nicht bemerkbar machen, einem aber mittel- bis langfristig auf jeden Fall auf die Füße fallen. Außerdem ist die Einstiegshürde in das Framework recht hoch, da das Framework über viele Muster verfügt, die leider in der JavaScript-Community noch nicht ganz so etabliert sind. Beispiele hierfür sind Dependency Injection, Modularisierung, deklarative Entwicklung in den Templates und viele mehr.

Wie so häufig machen ein paar schlaue Ratschläge den Anfang, die relativ allgemeingültig sind und die Sie auch in Projekten anwenden können, die nicht auf AngularJS basieren.

Das erste Prinzip ist für Entwickler das schwierigste: Kiss – Keep it simple and stupid. Also kein Over-Engineering. Ursprünglich stammt dieses Prinzip aus dem Flugzeugbau und besagt, dass ein Triebwerk von einem durchschnittlichen Ingenieur im Feldeinsatz gewartet werden können muss. Gleiches sollte auch für die von Ihnen entwickelte Software gelten. Nicht nur Sie selbst als Autor einer Funktionalität sollten in der Lage sein, den Quellcode zu warten und zu erweitern, sondern auch jeder Ihrer Kollegen. Es spricht für die Qualität der Software, wenn sich ein Entwickler den Quellcode ansieht und nahezu auf Anhieb versteht, was eine gewisse Funktion tut. Das bedeutet nicht, dass der Quellcode nicht elegant umgesetzt werden darf. Der Fokus sollte auf der Lesbarkeit der Software liegen. Eines der häufigsten Anti-Patterns in diesem Bereich ist die Mikrooptimierung, also die übermäßige Optimierung einzelner Codestellen, bei der der Benefit so gering ist, dass die negativen Auswirkungen auf die Lesbarkeit überwiegen.

Damit nicht genug der Abkürzungen. Das nächste Prinzip, das Sie bei der Entwicklung Ihrer Applikation beherzigen sollten, lautet DRY – Don’t repeat yourself. Die wiederholte Implementierung des gleichen Blocks an Quellcode ist nicht erstrebenswert, auch wenn er noch so schön ist. Dieses Prinzip basiert nicht auf der Schreibfaulheit vieler Entwickler, sondern hat einen sehr praktischen Hintergrund. Tritt in einem Block ein Fehler auf, muss er nicht nur in diesem Block, sondern in all seinen Klonen behoben werden. Dabei vergisst man in der Regel mindestens eine Kopie, und der Fehler bleibt noch länger in der Software erhalten. Gleiches gilt im Übrigen auch für Verbesserungen, die dann an mehreren Stellen durchgeführt werden müssen. Im Normalfall lagern Sie Quellcode spätestens bei der zweiten oder dritten Verwendung in eine Funktion oder im Falle von AngularJS in einen Service aus. Unterscheiden sich die Implementierungen von Fall zu Fall leicht, kann die Lösung parametrisiert werden, um mit den Unterschieden umzugehen.

Eine Abkürzung habe ich noch für Sie: YAGNI – You ain’t gonna need it. Auch dieses Prinzip hat mit Einfachheit und Fokus zu tun. Konzentrieren Sie sich bei der Entwicklung vorrangig auf das aktuelle Problem und versuchen Sie nicht, bereits alle zukünftigen Probleme zu lösen. In den meisten Fällen wissen Sie nicht, ob die Problemstellungen auch wirklich in der erwarteten Form eintreten werden. Das einzige, das Sie machen dürfen, ist, Ihre Applikation offen für Veränderungen zu halten, damit Sie zu einem späteren Zeitpunkt flexibel reagieren können. Aber das war es auch schon.

Sobald Sie sich bei Folgendem ertappen, müssen Sie reagieren: „In einem Jahr könnte doch dieses und jenes Problem auftreten, wenn ich diese eine Zeile jetzt so schreibe, dann ist die Lösung viel einfacher.“ Sobald aus der einen Zeile plötzlich fünfzig Zeilen werden, sollten Sie auf der Stelle abbrechen. Das kostet Sie momentan nur unnötig viel Zeit und eventuell lösen Sie Probleme, die nie welche sein werden.

Von den eher abstrakten Prinzipien jetzt zu den konkret im Code umsetzbaren: Verwenden Sie AngularJS als Framework für Ihre Applikation, versuchen Sie bitte nicht, AngularJS als Wrapper um jQuery zu verwenden. Sobald Sie merken, dass Ihre Applikation mehr aus jQuery-Plug-ins als aus AngularJS besteht, sollten Sie nochmal über Ihre Architektur nachdenken. Im Idealfall verzichten Sie ganz auf den Einsatz von jQuery und setzen sämtliche DOM-Manipulationen über Direktiven und CSS um. Greifen Sie nur in Ausnahmefällen auf jQuery zurück.

In JavaScript kommen Sie um die Verwendung von Funktionen nicht herum. Erstellen Sie also Funktionen, tun Sie dies bitte immer benannt und nicht anonym. Das hat zwei große Vorteile: Das Debuggen von benannten Funktionen ist erheblich komfortabler, da Sie in den Stack-Traces den Namen der Funktion wiederfinden und nicht nur eine Reihe von „anonymous Function“ angezeigt wird. Außerdem sind benannte Funktionsdefinitionen atomare Statements, die von der Engine gehostet werden. Das bedeutet, dass die Funktion durch die Engine im aktuellen Scope nach oben gezogen wird und überall verfügbar ist.

Wenn Sie Software schreiben, geben Sie ihr sprechende Namen, auch wenn diese etwas länger sind. Der Name einer Funktion sollte aussagen, was diese Funktion tut. Wenn der Name zu lang wird, dann ist es naheliegend, dass die Funktion zu viel zu tun hat und vielleicht in kleinere und einfachere Funktionen unterteilt werden sollte.

Wo wir gerade bei Einheiten im Code sind. Wenn Sie Ihre Applikation einigermaßen zeitgemäß umsetzen, besteht sie nicht nur aus einem großen Block an Quellcode, in den Eingaben geworfen werden und aus dem auf magische Weise Ausgaben kommen, sondern Sie haben zahlreiche Module. AngularJS unterstützt Sie bei dieser Art der Entwicklung und bietet viele Hilfsmittel zur Strukturierung. Im Verlauf werden die Strukturen des Frameworks als Komponenten bezeichnet. Diese haben allerdings keinerlei Verbindung zu den Web Components oder den Components von AngularJS 2.0, sondern stehen vielmehr für Controller, Services, Direktiven und Filter.

Eine Datei pro Komponente

Im Umgang mit Komponenten hat sich eine Konvention stets bewährt: eine Datei pro Komponente. Das bedeutet, dass jeder Controller, jede Direktive und jede andere Komponente in ihrer eigenen Datei liegt. Wenn Sie sich jetzt Sorgen um die vielen Requests machen, die nötig werden, um die komplette Applikation zum Client zu bringen, seien Sie beruhigt. Die vielen kleinen Dateien sind hilfreich bei der Entwicklung. Für den Produktivbetrieb wird die Applikation gebaut und besteht zum Schluss nur noch aus einer Datei, die dann optimalerweise über eine gzip-komprimierte Verbindung zum Client geschickt wird. Wenn Sie schon einmal versucht haben, Ihre AngularJS-Applikation in einer einzigen Datei zu entwickeln, werden Sie bestätigen, dass es bessere Ideen dafür gibt, vor allem wenn die Applikation im Umfang wächst. Ab einem bestimmten Punkt kommt man aus dem Scrollen nicht mehr heraus und findet sich im Quellcode nicht mehr zurecht. Spätestens dann wird es Zeit für eine Aufteilung.

Ein weiterer Vorteil dieser Aufteilung ist, dass Sie die Dateien entsprechend ihres Inhalts benennen können, was Sie wiederum bei der Navigation im Projekt unterstützt.

Nichts bleibt für die Ewigkeit

Die Entwicklung einer Single-Page-Applikation ist ein sehr dynamischer Prozess. In den meisten Fällen erfolgt die Entwicklung nach agilen Prinzipien – und die sollten sich auch im Quellcode wiederfinden. Sorgen Sie dafür, dass Änderungen nichts Schlechtes für Sie und Ihren Quellcode bedeuten. Das hat den Vorteil, dass Sie schnell Entscheidungen treffen können, diese aber zu einem späteren Zeitpunkt – ausgestattet mit mehr Wissen – ändern oder korrigieren können. Eine AngularJS-Applikation sollte aus vielen relativ unabhängigen Modulen bestehen. Gestalten Sie jedes dieser Module so, dass Sie es relativ problemlos aus der Applikation herauslösen und an anderer Stelle einfügen können. Das erhöht sowohl die Wiederverwendbarkeit von Modulen und Komponenten, bietet Ihnen aber auch die Flexibilität, Module durch andere Implementierungen auszutauschen, ohne gleich die gesamte Applikation neu schreiben zu müssen. Der Kern dafür besteht darin, dass jedes Modul seine Abhängigkeiten selbst verwaltet und Sie so auf den ersten Blick erkennen, welche weiteren Module und Schnittstellen für die Lauffähigkeit des Moduls erforderlich sind.

Es geht nichts über Konventionen

Der große Vorteil von JavaScript und AngularJS ist die Flexibilität, die sowohl die Sprache als auch das Framework bietet. Der Nachteil an dieser Flexibilität ist, dass keinerlei Konventionen erzwungen werden. So haben Sie kaum Möglichkeiten, Datentypen festzulegen, geschweige denn Interfaces zu definieren. Schlimmer wird die Situation noch, wenn mehrere Entwickler gleichzeitig an einer Applikation arbeiten und man das dem Code auch ansieht. Aus diesem Grund sollten Sie schon zu Beginn Ihres Projekts Konventionen für Architektur und Design festlegen. Achten Sie darauf, dass diese Konventionen nicht in Stein gemeißelt sind, sondern im Laufe des Projekts immer wieder angepasst werden sollten, um den technologischen Fortschritt widerzuspiegeln. In der Praxis hat sich bewährt, dass Coding-Konventionen in regelmäßigen Abständen hinterfragt und entsprechend verbessert werden. Die Häufigkeit und die konkrete Vorgehensweise unterscheiden sich dabei von Projekt zu Projekt und sollten vom Team selbst festgelegt werden. Allerdings ist es immer sinnvoll, mit einem kleinen Regelsatz zu starten und diesen bei Bedarf zu erweitern, um Überregulierung zu vermeiden. Ihr Ziel sollte sein, dass sich jeder Entwickler überall im Quellcode möglichst schnell zurechtfindet und die Einarbeitung neuer Kollegen mit wenig Zeitaufwand verbunden ist.

Die Verzeichnisstruktur

Der erste Kontakt mit dem Projekt erfolgt auf Dateisystemebene. Die erste Frage ist hier ja schon geklärt. Jede Komponente erhält ihre eigene Datei. Aber wie werden diese benannt? Eine gute Konvention hierfür ist zunächst der beschreibende Name der Komponente, dann der Typ, gefolgt von der Endung „js“, getrennt jeweils durch Punkte. Ein ListController, der für die Anzeige einer Liste zuständig ist, liegt beispielsweise in der Datei list.controller.js. Der Vorteil dieser Variante ist, dass auf den ersten Blick klar wird, welche Komponente in dieser Datei liegt. Wenn Sie nun von einer mittelgroßen Angular-Applikation mit einer zwei- bis dreistelligen Anzahl an Komponenten ausgehen, stellt sich als nächstes die Frage, wie Sie diese Dateien am besten organisieren. Hier gibt es natürlich die unterschiedlichsten Ansätze. Sie sollten allerdings versuchen, die Verzeichnisstruktur Ihrer Applikation möglichst flach zu halten. Ein gutes Messkriterium ist dabei die Anzahl der Dateien pro Verzeichnis. Solange Sie sich hier bei maximal fünf bis zehn Dateien bewegen, ist alles noch in Ordnung. Werden es allerdings mehr Dateien, sollten Sie die Dateien in Unterverzeichnissen anordnen. Die beste Variante ist dabei die Dateien pro Feature anzuordnen. Sprich: Sämtliche Komponenten, die zu einem Feature gehören, liegen in einem Verzeichnis, das den Namen des Features trägt. Allgemeingültige Komponenten oder solche, die nicht eindeutig einem Feature zugeordnet werden können, liegen wiederum in separaten Verzeichnissen. Sie sollten diese Variante der Anordnung wählen, weil Sie sich dann bei der Entwicklung eines Features in einem Verzeichnis bewegen. Die Variante, alle Komponenten in Verzeichnissen mit der Bezeichnung des jeweiligen Typs unterzubringen, skaliert erfahrungsgemäß nicht bei größeren Applikationen. Das Problem dabei ist: Wenn Sie ein Verzeichnis haben, das sämtliche Controller aufnimmt und hier eine große Zahl von Controllern existiert, wird das Verzeichnis sehr schnell unübersichtlich. Außerdem müssen Sie in mehrere verschiedene Unterverzeichnisse, wenn Sie alle Controller, Services und Direktiven eines Features bearbeiten müssen.

Module

Das A und O einer erfolgreichen und langlebigen Applikation ist eine sinnvolle Aufteilung der Komponenten. Dabei sollten Sie auf eine Gruppierung nach Features achten. Ein solcher modularer Aufbau einer Applikation macht es erst möglich, einzelne Teile auszugliedern oder bei Bedarf zu ersetzen. Diese Flexibilität ist gerade bei Applikationen wichtig, bei denen der gesamte Funktionsumfang noch nicht zu Beginn feststeht. AngularJS verfügt über ein eigenes Modulsystem, das Ihnen den Aufbau einer modularen Applikation ermöglicht. Leider greift dieses Modulsystem nicht weit genug, da es sich lediglich um die Integration von Komponenten aus anderen Modulen kümmert, nicht jedoch um das automatische Auflösen von Abhängigkeiten oder das Laden von Dateien. Möchten Sie dieses Problem lösen, bleibt nur der Griff zu einem der zahlreichen Modul Loader wie RequireJS, Browserify oder SystemJS. Jeder dieser Modul Loader weist verschiedene Vor- und Nachteile auf. Möchten Sie jedoch auf das Modell mit der größten Zukunftssicherheit setzen, sollten Sie das native JavaScript-Modulsystem des aktuellen JavaScript-Standards einsetzen und es mit SystemJS als Polyfill emulieren, bis es von den gängigen Browsern unterstützt wird. Mit der Kombination aus Modul Loader und AngularJS-Modulsystem müssen Sie zwar Abhängigkeiten jeweils einmal pro System angeben, Sie müssen sich jedoch dann nicht mehr um das Laden und Auflösen von Abhängigkeiten kümmern. Außerdem gibt es Build-Systeme, die dafür sorgen, dass aus den vielen kleinen Dateien eine große Datei entsteht, die dann schließlich im Produktivbetrieb ausgeliefert werden kann.

Wie bereits erwähnt, sollten Sie pro Feature ein Modul erstellen. Sie sollten für Ihre Module ein eindeutiges Präfix verwenden, um anzuzeigen, dass es sich um Ihre eigenen Module handelt, und um Namenskonflikte mit Modulen von Drittanbietern zu vermeiden. In einer Applikation heißt dann das Hauptmodul Ihrer Applikation, das für die Integration aller anderen Module verantwortlich ist, beispielsweise „app“. Haben Sie dann ein Modul, das sich um das Account-Handling kümmert, benennen Sie dieses am besten „app.accounts“ und so weiter. Diese Submodule verfügen dann im Dateisystem Ihres Projekts über ein eigenes Verzeichnis mit dem Namen des Features und beinhalten sämtliche Komponenten, die zu diesem Feature gehören. Möchten Sie dann dieses Modul in Ihre Applikation integrieren, reicht es aus, wenn Sie den Namen des Moduls als Abhängigkeit in das Hauptmodul eintragen und dafür sorgen, dass alle benötigten Dateien korrekt geladen werden. Das sieht dann in etwa so aus:

angular.module('app', ['app.list', 'app.admin']);

Bei der Verwendung des AngularJS-Modulsystems generieren Sie das Modul beim ersten Aufruf unter Angabe der Abhängigkeiten. Im Weiteren können Sie sich über den Modul-Getter immer wieder eine Referenz auf das Modul holen und es um zusätzliche Komponenten erweitern. Die Verwendung von Variablen, in denen die Referenz gespeichert wird, wird nicht empfohlen, da Sie auf jede unnötige Variable verzichten sollten, um den globalen Scope sauber zu halten.

Dependency Injection

Eines der wichtigsten Konzepte von AngularJS neben dem Two-Way Data Binding ist die Dependency Injection. Dieses Konzept ist so bedeutend, weil es eine gute Testbarkeit der Applikation erlaubt, indem die einzelnen Bestandteile voneinander entkoppelt werden. Leider gibt AngularJS auch hier nicht nur einen Weg vor, sondern Sie können als Entwickler aus drei Varianten wählen. Hier sollten Sie sich für die expliziteste Variante mit der $inject-Eigenschaft entscheiden. Sie bietet Ihnen die Möglichkeit, dass Sie die drei Schritte der Definition, Registrierung und Dependency Injection sauber trennen und Ihre Applikation dennoch gefahrlos durch einen Minifier schicken können. Der folgende Ausschnitt zeigt, wie das am Beispiel eines Controllers aussieht:

angular.module('app').controller('ListController', ListController);
ListController.$inject = ['articleService'];
function ListController(articleService) {
  ...
}

Zunächst registrieren Sie den Controller im Modul und geben lediglich eine Referenz auf die Funktion an. Danach sorgen Sie dafür, dass sämtliche Abhängigkeiten korrekt injiziert werden. Schließlich müssen Sie nur noch die Controller-Funktion definieren. Diese ist durch das Funktions-Hoisting im gesamten Scope verfügbar.

Neben diesen eher allgemeinen Best Practices gibt es auch für die verschiedenen Komponenten noch Muster und Methoden, die sich bei der Umsetzung von Applikationen etabliert haben.

Controller

Ein Controller in AngularJS hält das View Model und ist für die Behandlung von Benutzereingaben zuständig.

Seit AngularJS 1.2 gibt es zusätzlich zum $scope-Objekt, das bis dahin das View Model dargestellt hat, die alternative ControllerAs-Syntax, die Sie mittlerweile bevorzugt einsetzen sollten. Sie spiegelt den Charakter der Controller besser wider, handelt es sich dabei doch um Instanzen, die die Daten und Funktionen für die View vorhalten. Außerdem ist der Kontext in verschachtelten Controllern besser zu verwalten, da sie explizit auf den Namen des Controllers zugreifen und Sie sich nicht umständlich über die $parent-Eigenschaft des Scopes die Hierarchie nach oben hangeln müssen. Mit der ControllerAs-Syntax definieren Sie Eigenschaften und Funktionen direkt mit this auf dem Controller. Das wirft allerdings ein Problem auf, wenn Sie mit Callback-Funktionen arbeiten, da diese über einen anderen Kontext verfügen. Sie können diese Callbacks entweder mit der bind-Methode in den korrekten Kontext binden, oder Sie erstellen im Controller eine Variable, die eine Referenz auf den Controller beinhaltet. Den Namen der Variablen können Sie natürlich beliebig wählen, die Bezeichnung vm für View Model hat sich aber mittlerweile etabliert. Ein Beispiel für einen solchen Controller sehen Sie in Listing 1.

Listing 1: Controllerstruktur

function ListController(articleService) {
  var vm = this;
  vm.articles = [];
  vm.onEdit = onEdit;

  function activate() {
    ...
  }

  function onEdit(id) {
...
  }
}

In diesem Listing sehen Sie außerdem noch eine weitere Konvention. Sämtliche Eigenschaften und Funktionen, die Ihnen in der View zur Verfügung stehen, finden Sie am Anfang der Funktion. Die konkreten Implementierungen der jeweiligen Funktionen erfolgen später im Controller. Damit können sich Entwickler, die den Code lesen, einen schnellen Überblick verschaffen und müssen sich nicht erst durch die Implementierungen kämpfen. Außerdem ist empfehlenswert, die Logik, die bei der Erstellung eines Controllers abläuft, in eine separate Funktion zu kapseln. Typischerweise sollten Sie eine solche Funktion init oder activate nennen.

Ihr vorrangiges Ziel sollte es sein, Ihre Controller möglichst schlank zu halten und wenig Logik im Controller direkt zu implementieren, da dies die Struktur nur unübersichtlich macht. Sobald ein Controller beginnt, umfangreicher zu werden, sollten Sie dazu übergehen, die Logik in Services auszulagern.

Services

Services werden verwendet, um Quellcode innerhalb einer Applikation zu teilen.

Services kapseln also Quellcode. Und wieder gibt es unterschiedliche Ausprägungen. Da wären Services, Factories und Provider. Wobei ein Service eine Factory ist und eine Factory wiederum eine Spezialform eines Providers. Für einfache Fälle sollten Sie Factories verwenden. Sie sind, wie alle anderen Services in AngularJS, Singletons und liefern ein Objekt zurück. Services sind Konstruktorfunktionen, die instanziiert werden, und Provider schließlich sind vorkonfigurierbare Services.

Bei der Erstellung einer Factory sollten Sie, ähnlich wie auch schon bei den Controllern, dafür sorgen, dass das öffentliche API, also das, was Sie nach außen geben, ganz oben steht. Durch das Hoisting benannter Funktionen entstehen Ihnen dabei auch keine Probleme. Sie selbst, wie auch andere Entwickler, erhalten dann aber schon auf den ersten Blick eine Übersicht über die Schnittstellen, ohne dass Sie sich näher mit der Implementierung auseinandersetzen müssen.

Filter

Filter formatieren Daten für die Ausgabe.

Manchmal sind Services jedoch zu schwergewichtig, gerade, wenn es um einfache Formatierungen zur Ausgabe in Templates geht. Hier kommen Filter zum Einsatz. Dabei handelt es sich um einfache Funktionen, die aus einer Eingabe eine definierte Ausgabe erzeugen und durch Parameter beeinflusst werden können. Sie sollten jedoch darauf achten, nicht zu tief verschachtelte Objektstrukturen durch einen Filter zu schicken, da sich dies negativ auf die Performance auswirken kann. In diesem Fall sollten Sie lieber zu einem Service greifen.

Direktiven

Direktiven sind Marker im DOM, die den Sprachschatz und die Fähigkeiten von HTML erweitern.

Sobald es darum geht, das DOM zu manipulieren, kommen Direktiven zum Einsatz. Wo immer es möglich ist, sollten Sie entweder auf bereits existierende Direktiven wie beispielsweise ng-show oder ng-hide zurückgreifen oder CSS verwenden. Reicht all dies nicht aus, können Sie sich Ihre eigenen Direktiven schreiben.

Wenn Sie sich dazu entscheiden, Ihre eigenen Direktiven zu erstellen, sollten Sie diese mit einem eindeutigen Präfix kennzeichnen. Das erlaubt es Ihnen, sie später schnell zu lokalisieren. Außerdem beugt eine eindeutige Benennung Namenskonflikten vor.

Sie können Direktiven an HTML-Elemente und Attribute, aber auch an Kommentare und Klassen binden. Es werden jedoch nur die ersten beiden Methoden empfohlen. Kommentare können beispielsweise versehentlich vom eigentlichen Element getrennt werden und wirken sich dann plötzlich auf ganz andere Elemente aus. Klassen sollten Sie zum Lokalisieren von Elementen und zum Stylen verwenden, nicht aber für Applikationslogik.

Jede Direktive kann über einen Controller verfügen. Für diese Direktivencontroller gelten dieselben Regeln wie für normale Controller auch. Sie sollten ebenfalls die ControllerAs-Syntax nutzen. Normalerweise werden die Eigenschaften, die aus dem isolierten Scope der Direktive kommen, an das Scope-Objekt der Direktive gebunden. Mit der Option BindToController können Sie dafür sorgen, dass Sie direkt über das Controllerobjekt auf die Eigenschaften zugreifen können.

Kommunikation

In einer Webapplikation geht es primär um Kommunikation. Der Benutzer kommuniziert über Eingaben mit der Applikation, die Applikation kommuniziert mit einem Backend. Aber auch die einzelnen Komponenten und Module innerhalb einer Applikation müssen miteinander kommunizieren und genau das wird zum Problem, wenn man versucht, eine möglichst lose Kopplung der Komponenten zu erreichen. Eigentlich sollte die Applikation so gestaltet sein, dass jede Komponente für sich stehen kann. Eine etablierte Lösung ist, dass Sie Services zur Kommunikation zwischen den einzelnen Komponenten benutzen. Diese Lösung ist ein Kompromiss aus Kommunikationsmöglichkeit und loser Kopplung. Sie erstellen einen Service, an dem Sie Callbacks für Events registrieren können, und eine Möglichkeit, mit der Sie diese Events triggern können. Mit dieser Implementierung müssen die einzelnen Komponenten nichts voneinander wissen, sondern nur den Kommunikationsservice als Abhängigkeit registrieren und sich an die jeweiligen Events binden.

Neben dieser Möglichkeit der Kommunikation können Sie beispielsweise bei Direktiven auch die scope-Eigenschaft und deren Data-Binding-Möglichkeiten nutzen, um Informationen und Funktionsreferenzen in eine Direktive hineinzureichen. Das Ziel dabei besteht darin, dass eine Direktive so unabhängig wie möglich von der Struktur ist, in die sie eingebettet wird, um eine maximale Wiederverwendbarkeit zu erreichen.

Ausblick

Die hier vorgestellten Best Practices und Vorschläge sind nur ein kleiner Ausschnitt der Möglichkeiten, die Ihnen zur Verfügung stehen, wenn Sie mit AngularJS entwickeln. Wichtig ist, dass Sie stets die Wartbarkeit und Erweiterbarkeit Ihrer Applikation im Auge haben; und das erreichen Sie nur, wenn Sie und Ihr Team Hand in Hand arbeiten und ein gemeinsames Verständnis über die Architektur und das Design Ihrer Software haben. Aus diesem Grund sollten Sie sich möglichst früh im Projekt auf gemeinsame Konventionen einigen und einen einheitlichen Programmierstil verfolgen.

Windows Developer

Windows DeveloperDieser Artikel ist im Windows Developer erschienen. Windows Developer informiert umfassend und herstellerneutral über neue Trends und Möglichkeiten der Software- und Systementwicklung rund um Microsoft-Technologien.

Natürlich können Sie den Windows Developer über den entwickler.kiosk auch digital im Browser oder auf Ihren Android- und iOS-Devices lesen. In unserem Shop ist der Windows Developer ferner im Abonnement oder als Einzelheft erhältlich.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -