Warum Elm? (Und wie man damit anfängt)

Avatar of James Kolce
James Kolce am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Wenn überhaupt über die größten Probleme in der Webentwicklung gesprochen wird, ist Komplexität zweifellos ein Thema. Zwischen der Verwendung von Dutzenden von Tools, Abhängigkeiten und der inhärenten Komplexität der Sprachen selbst ist Komplexität Teil des Jobs.

Moderne Webanwendungen erfordern neue Denkweisen, wie wir Prozesse handhaben. Das Problem, Funktionen ohne strenge Reihenfolge oder zu unerwarteten Zeitpunkten auszuführen – wie bei einem Klick auf einen Button oder einer eingehenden Nachricht über das Netzwerk – zwingt uns, verschiedene Techniken anzuwenden, von Callbacks und Promises bis hin zu ausgefeilteren Tools wie Reactive Extensions.

Es ist nicht ungewöhnlich, Systeme zu haben, die aus mehreren Tausend Codezeilen bestehen, und Dinge können in diesem Maßstab leicht außer Kontrolle geraten. Selbst die geringsten Änderungen könnten unbeabsichtigte Folgen haben. Laufzeitfehler sind bei JavaScript äußerst häufig, und wenn wir nicht aufpassen, können wir uns dabei erwischen, unmögliche Berechnungen durchzuführen, wie z. B. das Aufrufen von etwas, das nicht existiert, oder das Verarbeiten von etwas, das nicht mehr das ist, was man dachte.

Artikelserie

  1. Warum Elm? Und wie man damit anfängt (Sie sind hier!)
  2. Einführung in die Elm-Architektur und wie wir unsere erste Anwendung erstellen
  3. Die Struktur einer Elm-Anwendung

(Einige der) Vorteile der funktionalen Programmierung

Kontrollierter Zustand

In einer Sprache wie JavaScript können wir fast alles mit dem Zustand unserer Programme tun. Der Mangel an Kontrolle über den Zustand ist ein häufiger Vorläufer von Fehlern. Zum Beispiel der Versuch, mit einem Wert zu arbeiten, der sich unerwartet geändert hat.

Obwohl der Zustand nicht verschwinden kann, kann er kontrolliert werden; funktionale Sprachen versuchen, Werkzeuge bereitzustellen, um mit ihm auf organisiertere Weise zu arbeiten. Einige davon, wie Clojure, bieten Funktionen wie unveränderliche Datenstrukturen, aber andere gehen zum Äußersten und werden zu reinen funktionalen Sprachen wie Haskell, wo jedes einzelne Detail über den Zustand sorgfältig durchdacht werden muss.

Vorhersagbarkeit

Reine Funktionen sind ein Kernkonzept der funktionalen Programmierung und äußerst nützlich. Wir sagen, eine Funktion sei rein, wenn sie bei gleicher Eingabe immer dasselbe Ergebnis liefert und keine Seiteneffekte verursacht.

Da eine Funktion nichts weiter tun kann, als einen Wert entgegenzunehmen, diesen zu verarbeiten und das Ergebnis zurückzugeben – können wir vorhersagbarere Programme erhalten.

Beschreibe Was, nicht Wie

Funktionale Sprachen sind deklarative Sprachen, das heißt, wir können einen Prozess beschreiben, ohne uns um alle Details kümmern zu müssen, wie der Prozess abläuft. Die Konsequenzen einer klaren Sicht auf den Zweck unseres Codes können sehr positiv sein, da man leichter versteht, was das Programm tut, ohne den Implementierungsrauschen von wie es getan wird.

Modularität und Komponierbarkeit

Das Prinzip „Teile und Herrsche“ ist eine gängige Praxis in der funktionalen Programmierung. Wir zerlegen komplexe Probleme in mehrere einfache, erstellen für jedes eine Lösung und kombinieren sie dann, um das gesamte Problem zu lösen; Indem wir unsere Programme in kleine Funktionen aufteilen, können wir Wiederverwendbarkeit und Wartbarkeit erhöhen.

Disziplin

Reine funktionale Sprachen motivieren Programmierer, besser über die Programme nachzudenken, die sie erstellen. Von einfachen Typannotationen und Mechanismen zur Steuerung von Seiteneffekten bis hin zu vollständigen Architekturen, wie in Elm.

Obwohl die anfängliche Entwicklungszeit bei solchen Einschränkungen zunehmen kann, können die Vorteile bei der Wartbarkeit den Aufwand ausgleichen.

Elm: Eine funktionale Programmiersprache für das Web

Elm ist eine relativ neue Programmiersprache zum Erstellen von Webanwendungen, die 2012 von Evan Czaplicki im Rahmen seiner Diplomarbeit über Concurrent FRP for Functional GUIs entwickelt wurde.

Da es für das Web bestimmt ist – und Browser nur eine begrenzte Anzahl von Sprachen verstehen –, wird der Code, den Sie in Elm schreiben, in HTML, CSS und JS kompiliert.

Von Natur aus unveränderlich

Alle Werte in Elm sind unveränderlich, was bedeutet, dass, sobald Sie etwas haben, es gleich bleibt, es sei denn, Sie erstellen ein neues etwas als Kopie.

Der einfachste Vorteil: Da wir Mutationen nicht im Kopf behalten müssen, wird das Lesen von Code viel einfacher; Wenn wir einen Wert sehen, können wir sicher sein, dass er gleich bleibt. Außerdem müssen Sie sich keine Gedanken über Laufzeitfehler im Zusammenhang mit unerwarteten Werten aufgrund von Mutationen machen.

Statische Typen

Statische Typen sind eine ausgezeichnete Möglichkeit, Systeme zu dokumentieren. Sie können schnell erkennen, was eine Funktion tut und ihre Domäne, indem Sie nur die Typdefinition betrachten. Typsysteme ermöglichen es uns, genau zu definieren, welche Art von Wert eine Funktion entgegennimmt und zurückgibt.

Aber Typen sind nicht nur nützlich, wenn sie von Entwicklern gelesen werden, sondern ermöglichen auch bessere Werkzeuge (wie Debugger und Tester), die die Korrektheit unseres Codes erhöhen. Außerdem hindern sie uns daran, unmögliche Berechnungen durchzuführen, und halten uns dadurch von vielen potenziellen Laufzeitfehlern fern.

Elm hat ein abgeleitetes Typsystem. Das bedeutet, dass Sie Typen nicht von Anfang an schreiben müssen und der Compiler versucht, den entsprechenden Typ für Ihre Funktionen abzuleiten, sodass Sie keine Produktivitätsverluste wie in anderen Mainstream-Sprachen mit Typen haben.

-- Function with its type annotation
square : Int -> Int
square n = n^2

-- This also works, because types are inferred
square n = n^2

Reine Funktionen

Reine Funktionen sind das Kernkonzept der funktionalen Programmierung und bieten einen enormen Vorteil beim Aufbau zuverlässiger und wartungsfreundlicher Systeme. Elm-Funktionen sind rein und empfangen Eingaben und erzeugen neue Werte als Ausgabe. Außerdem liefern sie für jede Eingabe immer dasselbe Ergebnis, ohne Seiteneffekte zu erzeugen.

Abonnements

Asynchrone Systeme erfordern einen anderen Programmieransatz, und Elm handhabt dies durch die Verwendung von Subscriptions. Da es bestimmte Dinge gibt, von denen wir nicht wissen, wann sie passieren werden – wie Benutzerinteraktionen oder Netzwerkantworten –, können wir diese Ereignisse abonnieren, was uns ermöglicht, zu handeln, sobald sie auftreten, ohne uns um Implementierungsdetails kümmern zu müssen.

Kontrollierte Seiteneffekte

Reine Funktionen sind gut, und wir können versuchen, überall reine Funktionen zu haben, aber irgendwann müssen wir Interaktionen unseres Programms mit der Außenwelt handhaben, und das können wir auf kontrollierte Weise mithilfe von Commands tun.

Da Eingabe und Ausgabe ebenfalls Seiteneffekte sind, können wir, wenn wir überall streng reine Funktionen verwenden, gar nichts tun. Stattdessen identifizieren wir Seiteneffekte und machen sie explizit, damit Elm sie für uns auf die richtige Weise handhaben kann.

Kompatibel mit Ihrem bestehenden Projekt

Sie müssen kein komplettes Projekt in Elm neu erstellen oder portieren – obwohl das schön wäre –, Sie können bestimmte Komponenten, die mit Elm erstellt wurden, in ein bestehendes Projekt integrieren.

Außerdem ist es möglich, bestehendes JavaScript innerhalb Ihrer Elm-Anwendungen zu verwenden und dabei alle schönen Dinge und Garantien der Sprache beizubehalten.

Einfach zu testen

Was erhalten wir mit statischen Typen? Fantastische Werkzeuge, einschließlich zufälliger Testgeneratoren, bei denen Funktionen gegen zufällige Eingaben getestet werden können, abhängig von der Domäne der Funktion (definiert durch die Typen).

Aber wahrscheinlich eines der aufregendsten Elm-Features in diesem Bereich ist die Tatsache, dass wir den vollständigen Zustand eines Programms exportieren können und damit Dinge tun können wie

  • Sie einem Bibliotheksentwickler senden, um einen Fehler zu reproduzieren.
  • Sie in einem anderen Browser oder Gerät laden, um zu sehen, wie sich die Dinge verhalten.

Und das alles geschieht auf sichere Weise, einschließlich Netzwerkanrufen, dank der kontrollierten Seiteneffekte mithilfe von Commands.

Eine bessere Architektur von Anfang an

Als die Leute begannen, Projekte mit Elm zu entwickeln, stellten sie fest, dass sich jedes Mal ein Muster abzeichnete. Das war der Beginn der Elm-Architektur, der De-facto-Weg zur Entwicklung von Elm-Anwendungen.

Eine solide Architektur für die Entwicklung unserer Projekte stellt sicher, dass wir auch bei zunehmender Komplexität des Programms die Kontrolle behalten. Außerdem haben wir den Vorteil, dass wir beim Übernehmen eines neuen bestehenden Projekts kein großes Problem damit haben werden, die Organisation des Codes zu verstehen.

Ein sinnvoller Paketmanager

Haben Sie jemals ein JavaScript-Paket aktualisiert und nach dem Start Ihrer Anwendung festgestellt, dass etwas nicht wie erwartet funktioniert oder gar nicht funktioniert? Nun, das ist ein nicht existierendes Problem in Elm; der Paketmanager verwaltet automatisch Versionsnummern je nach vorgenommenen Änderungen, sodass Sie bei einer Minor-Version niemals Breaking Changes erhalten werden.

Anfängerfreundlicher Compiler

Wir alle wissen, dass Compiler normalerweise unleserliche Meldungen produzieren, aber das ist bei Elm nicht der Fall. Jedes Mal, wenn Sie einen Fehler machen, wird Ihnen angezeigt, wo das Problem liegt, und eine Erklärung, wie Sie es beheben können.

Elm Compiler-Nachricht

Weitere Beispiele finden Sie im offiziellen Elm-Blog

Einrichtung unserer Entwicklungsumgebung

Leser Scott Phillips schrieb uns: „Elm 0.19 hat Breaking Changes ... aber die Kernbotschaft des Artikels bleibt gültig.“ Unser redaktioneller Rat wäre, sich für Installationen und spezifische Features auf die offizielle Dokumentation zu beziehen und diese Reihe als Einführung zu genießen, warum Sie Elm verwenden und auf Elm-ähnliche Weise denken sollten.

Installation der Elm-Plattform

Die Installation von Elm ist ein schneller Prozess. Nach der Installation von NodeJS können Sie Elm mit NPM direkt wie andere NodeJS-Pakete installieren.

npm install -g elm

Optional können Sie Elm auch über die Installer für Mac oder Windows installieren. Die Links sind im Abschnitt **Installieren** auf der Website Eine Einführung in Elm verfügbar.

Einen Texteditor besorgen

Obwohl Elm eine relativ neue Sprache ist, gibt es bereits großartige Werkzeuge, um damit zu arbeiten, insbesondere für Atom mit dem Paket Elmjutsu.

Aber Atom ist nicht der Einzige, die folgenden Editoren werden ebenfalls unterstützt

Sie können den wählen, den Sie am meisten mögen. Der Installationsprozess für diese Editoren liegt außerhalb des Rahmens dieses Artikels; ich empfehle, die jeweiligen Websites zu konsultieren.

Einführung in die Elm-Plattform

Die Elm-Plattform: vier Werkzeuge, die für die Entwicklung unserer Elm-Projekte unerlässlich sein werden. Ein REPL, um kleine Codefragmente zu testen. Reactor, ein Server, der es uns ermöglicht, unsere Projekte sofort im Browser anzuzeigen. Make, ein Werkzeug zum Erstellen unserer Projekte, und der Paketmanager, der uns Zugang zu Modulen verschafft, die von anderen Leuten geschrieben wurden. Sehen wir uns diese Werkzeuge an, um zu sehen, was wir damit tun können.

Die Read–Eval–Print-Schleife

Das Elm REPL ist ein Werkzeug zur Auswertung einfacher Elm-Codeschnipsel direkt in der Kommandozeile, ohne eine Datei erstellen zu müssen. Wie der Name schon sagt, liest es zuerst die Eingabe, wertet sie dann aus und gibt schließlich das Ergebnis aus. Dieses Werkzeug kann sehr nützlich sein, um die Sprache zu erkunden oder schnell ein kleines Stück Code auszuführen.

Um das REPL zu verwenden, öffnen Sie einfach ein Terminal und führen Sie den folgenden Befehl aus

elm-repl

# Update: `elm repl` now

Sie sollten etwas Ähnliches wie das hier erhalten

---- elm-repl 0.18.0 -----------------------------------------------------------
 :help for help, :exit to exit, more at <https://github.com/elm-lang/elm-repl>
--------------------------------------------------------------------------------
>

Wir können Elm-Code neben dem Symbol > schreiben. Als einfachen Test versuchen wir, eine square-Funktion zu erstellen, um das Ergebnis der Multiplikation einer Zahl mit sich selbst zu erhalten. Das können wir tun, indem wir Folgendes schreiben und Enter drücken.

square n = n * n

Jetzt haben wir eine square-Funktion im aktuellen Umfeld verfügbar, die wir für zukünftige Auswertungen verwenden können. Versuchen Sie zum Beispiel, Folgendes einzugeben

square 5

Und es sollte 25 : number zurückgeben. Der erste Teil ist unser Ergebnis und der Rest ist der Typ des Ergebnisses, nämlich eine number.

Sie können auch komplexeren Code schreiben. Schreiben wir eine einfache Fakultätsfunktion

factorial number = \
  if number == 0 then 1 \
  else number * factorial(number-1)

Um mehrere Zeilen zu schreiben, müssen Sie am Ende jeder Zeile ein \ hinzufügen, um dem Interpreter mitzuteilen, dass Sie mehr schreiben möchten.

Nachdem Sie die erste Zeile eingegeben und Enter gedrückt haben, erscheint ein | Zeichen, dann können Sie die nächste Zeile Ihres Codes schreiben. Achten Sie auf die Einrückung, sonst erhalten Sie einen Fehler. Sie müssen mindestens ein Leerzeichen hinzufügen.

Es gibt vier Befehle, die Sie direkt verwenden können, wenn das REPL aktiv ist

  • :help Zeigt alle verfügbaren Befehle an.
  • :flags Sie können Optionen für den Elm-Compiler ändern. Update: flags existiert nicht mehr.
  • :reset Startet Ihre aktuelle Sitzung neu, ohne dass Sie das REPL schließen und wieder öffnen müssen.
  • :exit Schließt das REPL, ohne dass Sie das Kommandozeilenfenster schließen müssen.

Elm Reactor

Elm-reactor ist ein interaktives Entwicklungswerkzeug, das die Entwicklung von Elm-Programmen erleichtert. Es erstellt einen Server, der Ihren Elm-Code im Handumdrehen kompiliert, und Sie können das Ergebnis direkt im Browser sehen.

Sehen wir uns an, wie wir Reactor mit einem Beispielprojekt verwenden würden. Dazu können Sie das Elm Architecture Tutorial mit Git klonen und sobald Sie sich im Projektverzeichnis befinden, den folgenden Befehl ausführen

elm-reactor

# Update: `elm reactor` now

Ein Server wird erstellt, und Sie können ihn unter https://:8000 in Ihrem Webbrowser aufrufen.

Sie sehen eine Navigationsseite, die die Dateien im Projektverzeichnis enthält. Gehen Sie zu examples/01-button.elm und warten Sie einen Moment, während die Datei kompiliert wird. Sobald dies abgeschlossen ist, sehen Sie ein kleines Widget zum Erhöhen und Verringern einer Zahl mit zwei Schaltflächen.

So können wir unser Projekt sehen, ohne die endgültigen Dateien zu produzieren, sehr nützlich für den Entwicklungsprozess.

Zwei nützliche Flags können mit dem Befehl elm-reactor verwendet werden. Um die vollständige Liste zu sehen, können Sie elm-reactor --help ausführen.

  • -a Legt eine benutzerdefinierte Adresse für den Server fest.
  • -p Legt einen anderen Port für den Server fest (standardmäßig :8000).

Zum Beispiel:

elm-reactor -a 0.0.0.0 -p 3000

# Update: `elm reactor` now

Obwohl Reactor ein sehr nützliches Werkzeug für die Entwicklung von Elm-Anwendungen ist, werden Sie schließlich an den Punkt gelangen, an dem Sie Ihr Projekt in Produktion bringen wollen. Dafür gibt es ein Werkzeug, das in der Elm-Plattform enthalten ist: Make.

Elm Make

Sobald Ihr Projekt bereit für die Welt ist, müssen Sie den Elm-Code in etwas übersetzen, das Browser verstehen: HTML, CSS und JavaScript. Wir verwenden dafür ein Werkzeug namens elm-make. Es nimmt Elm-Dateien entgegen und erzeugt native Dateien für das Web.

Versuchen wir zum Beispiel, das Beispiel aus dem vorherigen Abschnitt zu kompilieren. Gehen Sie in das Verzeichnis examples im Projekt Elm Architecture Tutorial und führen Sie den folgenden Befehl aus

elm-make 01-button.elm --output=01-button.html

# Update: `elm make` now

Wenn Sie diesen Befehl ausführen, werden Sie aufgefordert, die Installation einiger Pakete zu genehmigen. Geben Sie Y ein und drücken Sie Enter. Warten wir nun, bis die Kompilierung abgeschlossen ist.

Dies kompiliert unsere Datei 01-button.elm in eine 01-button.html, die direkt im Browser geöffnet werden kann. Wenn Sie in das Verzeichnis gehen, in dem sich die Datei 01-button.elm befindet, finden Sie auch die neue HTML-Datei. Sie können diese Datei mit Ihrem Browser öffnen, und Sie sehen dasselbe Ergebnis wie im vorherigen Abschnitt, aber diesmal können wir es sehen, ohne ein Elm-Werkzeug verwenden zu müssen; es ist reines HTML und JavaScript.

Jetzt können wir diese Datei verteilen, wie wir wollen, und jeder Webbrowser kann sie öffnen.

Der Elm-Paketmanager

Wenn Sie anfangen, nicht-triviale Anwendungen zu entwickeln, werden Sie bald feststellen, dass es unpraktisch ist, alles selbst zu schreiben. Normalerweise finden Sie für die häufigsten Aufgaben bereits von anderen geschriebene Pakete, die Sie in Ihren Projekten verwenden können. Dafür verwenden wir den Elm-Paketmanager, ein Werkzeug zum Installieren und Veröffentlichen von Elm-Paketen.

Wie wir im vorherigen Abschnitt gesehen haben, als wir versucht haben, unsere Elm-Datei zu kompilieren, fragt uns der Compiler, ob wir die fehlenden Pakete installieren möchten. Das ist die Aufgabe des Paketmanagers in der Praxis.

Dieses Werkzeug ist als elm-package in Ihrer Kommandozeile verfügbar, und um ein Paket zu installieren, können Sie Folgendes ausführen

elm-package install 

# Update: package manager integrated into `elm` command now

Weitere Befehle sind

  • publish: Fügt das Paket zum zentralen Katalog hinzu.
  • bump: Aktualisiert die Versionsnummer des Pakets je nach Änderungen.
  • diff: Ein Dienstprogramm zur Anzeige der Unterschiede zwischen Paketversionen.

Elm Format

Elm Format ist kein Teil der Elm-Plattform, aber es ist ein unglaublich nützliches Werkzeug, das es wert ist, erwähnt zu werden. Es formatiert Ihren Quellcode nach dem Standard-Styleguide. Außerdem können Sie Ihren Editor so einrichten, dass er dies automatisch tut, jedes Mal, wenn Sie eine .elm-Datei speichern.

Sie können Elm Format auf seinem Github-Repository finden.

Einen Vorgeschmack auf Elm bekommen

Erstellen Sie einen neuen Ordner irgendwo auf Ihrem Computer und öffnen Sie ihn mit Ihrer IDE oder Ihrem Texteditor. Wir erstellen eine Datei namens first-application.elm, in die wir folgenden Code einfügen werden

import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)

main =
  Html.beginnerProgram { model = model, view = view, update = update }

-- MODEL

type alias Model = Int

model : Model
model =
  0

-- UPDATE

type Msg = Increment | Decrement

update : Msg -> Model -> Model
update msg model =
  case msg of
    Increment ->
      model + 1

    Decrement ->
      model - 1

-- VIEW

view : Model -> Html Msg
view model =
  div []
    [ button [ onClick Decrement ] [ text "-" ]
    , div [] [ text (toString model) ]
    , button [ onClick Increment ] [ text "+" ]
    ]

Machen Sie sich vorerst keine Sorgen über die Bedeutung dieses Codes; wir werden ihn nur verwenden, um unser Setup zu testen.

Das erste, was wir überprüfen sollten, ist, ob wir Syntaxhervorhebung in unserem Editor erhalten. Wenn Sie nur einfachen Text sehen, überprüfen Sie den entsprechenden Abschnitt dieses Artikels erneut.

Als nächstes testen wir die Kompilierung von Elm-Code mit Reactor. Wechseln Sie im Terminal in das Projektverzeichnis und führen Sie den folgenden Befehl aus

elm reactor

Eine Meldung sollte mit etwas wie diesem erscheinen

elm-reactor 0.18.0                                                                                                                                                                   
Listening on https://:8000/  

Das bedeutet, dass es funktioniert und wir einen Webserver haben, der auf Port 8000 auf localhost lauscht. Wenn wir diese Adresse in unserem Webbrowser öffnen, sollten wir einen Dateinavigator sehen. Klicken Sie auf die Datei first-application.elm, und unser Projekt wird kompiliert. Sobald es fertig ist, sehen wir eine Seite mit einem kleinen Widget, das eine Zahl und zwei Schaltflächen anzeigt. Das ist das Ergebnis unseres Codes.

Elm-Beispiel: Zahlenzähler

Fazit

Wir haben einige der Vorteile der funktionalen Programmierung und der Elm-Sprache erkundet und sind nun mit der Plattform vertrauter, die wir zum Erstellen unserer Projekte verwenden werden.

Weitere detaillierte Informationen über Elm finden Sie im Buch An Introduction to Elm von Evan Czaplicki.