Stabilität und Superkräfte für JavaScript mit Reason

Stabilität und Superkräfte für JavaScript mit Reason

Hinter Reason verbirgt sich eine an JavaScript angelehnte, alternative Syntax für OCaml. Dadurch werden neben statischer Typisierung auch zusätzliche Funktionalitäten wie Typinferenz und Pattern Matching in JavaScript verfügbar. Reason hat das Potenzial, JavaScript-Projekte durch ungeahnte, nützliche Superkräfte zu erweitern.

Vortrag auf der enterJS 2018 in Darmstadt

8977eabcedbade28ba0ebe0062e41c68?s=128

Erik Behrends

June 20, 2018
Tweet

Transcript

  1. @behrends Stabilität und Superkräfte für JavaScript Erik Behrends

  2. @behrends Erik Behrends Prof @
 (Duale Hochschule Baden-Württemberg)
 
 App-Entwicklung,

    Programmieren, etc.
  3. @behrends ❤ JavaScript wird überall eingesetzt: Web (Browser, Server), Apps

    (React Native, ionic), … zu Beginn relativ einfach zu verwenden kann anspruchsvoll sein (funktionale Programmierung)
  4. @behrends Manchmal ist JavaScript " JavaScript wurde in 2 Wochen

    entworfen… ➞ die Sprache hat einige eigenartige Eigenschaften… [] + []; // ergibt ""
  5. @behrends Manchmal ist JavaScript # JavaScript wird interpretiert und ist

    dynamisch typisiert ➞ Laufzeitfehler kommen oft in produktiven Webapps vor undefined is not a function
 cannot read property 'xyz' of undefined
  6. @behrends Zwei Beispiele… " inkorrekter Code (ohne Fehler!) # Laufzeitfehler

  7. @behrends let user = { name: "John", role: "reader" };

    if (user.role = "admin") { // do something dangerous } // was ist das Problem mit diesem Code? " inkorrekter Code (ohne Fehler!)
  8. @behrends let user = { name: "John", role: "reader" };

    if (user.role = "admin") { // do something dangerous } // was ist das Problem mit diesem Code? // JS ERLAUBT ZUWEISUNG IN EINER BEDINGUNG!!?!?! // nur Boolean-Ausdrücke (true/false) machen Sinn " inkorrekter Code (ohne Fehler!)
  9. @behrends let user = { name: "John", role: "reader" };

    if (user.role = "admin") { // do something dangerous } // gültiges JavaScript (kein Syntaxfehler )!!! // kein Laufzeitfehler!!! // möglicherweise ungewollte Auswirkungen ;-) " inkorrekter Code (ohne Fehler!)
  10. @behrends let user = { name: "John", role: "reader" };

    if (user.role = "admin") { // do something dangerous } // könnte Teil einer größeren Code-Basis sein // auch bei erfahrenen Programmierern: // copy/paste, Tippfehler, Katze auf Tastatur, … " inkorrekter Code (ohne Fehler!)
  11. @behrends Statische Analyse zur Devtime (Linter) Fehler frühzeitig finden, Style-Guides

    erzwingen ESLint kann hierbei helfen
  12. @behrends let john = { name: "John" }; let jane

    = { name: "Jane", city: { name: "Rome" } }; console.log(john.city.name); // nicht erkannt von ESLint, erzeugt Laufzeitfehler // Uncaught TypeError: 
 // Cannot read property 'name' of undefined // (ggf. nicht so offensichtlich in großer Code-Basis) # Laufzeitfehler (TypeError)
  13. @behrends Laufzeitfehler in JS vermeiden… $ // Datenstruktur mit optionalen

    Feldern (null,"") ?? let john = { name: "John", city: null }; let jane = { name: "Jane", city: { name: "Rome" } }; // Abfrage von null-Werten (null guard) ??? if(john.city) console.log(john.city.name); // clevere logische Ausdrücke ??? console.log(john.city && john.city.name); JavaScript ist eben dynamisch typisiert…
  14. @behrends Statische Typisierung zur Hilfe! flow elm in Zukunft bestimmt

    noch mehr Auswahl…
  15. @behrends % Entscheidungslähmung? & JavaScript Fatigue?

  16. @behrends Wie wär's mit Reason? ' (ReasonML)

  17. @behrends Was ist Reason? 2016 von Facebook vorgestellt. Open Source.

    Neue Syntax und extra Werkzeuge für OCaml.
  18. @behrends Was ist OCaml? Funktionale Sprache mit pragmatischen imperativen Aspekten

    und objektorientierten Elementen. Hat ein ausgereiftes Typsystem mit mächtigen Features. Wird seit über 20 Jahren entwickelt. Aber nicht sehr verbreitet…
  19. @behrends Ungewohnte Syntax ( viel schwerer zugänglich als andere Sprachen

    let square x = x * x;; let sixteen = square 4;; if sixteen == 16 then let msg = "Everything ok!" in print_endline msg else print_endline "Something is wrong :-(";;
  20. @behrends Super Spracheigenschaften ) mächtiges Typsystem und weitere Features Ungewohnte

    Syntax ( viel schwerer zugänglich als andere Sprachen Ausführbarer Output * entweder Bytecode oder nativer Code OCaml „Stack“
  21. @behrends OCaml „Stack“ für JavaScript Reason Syntax ' wirkt vertraut

    auf JavaScript-Entwickler BuckleScript für JS-Output + generiert lesbares, optimiertes JavaScript Super Spracheigenschaften ) mächtiges Typsystem und weitere Features
  22. @behrends let square = x => x * x; let

    sixteen = square(4); if (sixteen === 16) { let msg = "Everything ok!"; print_endline(msg); } else { print_endline("Something is wrong :-("); }; Reason Syntax ' wirkt vertraut auf JavaScript-Entwickler
  23. @behrends Einige Ziele von Reason JS-Devs den Zugang zu maximaler,

    bequemer Typsicherheit (OCaml) durch eine vertraute Syntax (Reason) zu geben. Durch BuckleScript sehr gute Interoperabilität mit JavaScript (Code, Tooling, Abhängigkeiten mit npm/yarn). (Erstklassige Unterstützung für React beinhalten.) (Mächtige Features wie Varianten ermöglichen und verbreiten.)
  24. @behrends , Dazu nochmal die zwei Beispiele… Stabilität mit Reason

  25. @behrends Erstes Beispiel in JavaScript let user = { name:

    "John", role: "reader" }; if (user.role = "admin") { // do something dangerous } // Erinnerung: dies ist gültiges JavaScript! // es wird kein Laufzeitfehler erzeugt! // Bemerkung: TypeScript lässt dies auch zu!
  26. @behrends Erstes Beispiel in Reason ESLint wird im Prinzip durch

    compiler und refmt ersetzt.
 (refmt ist Inspiration für Prettier in JS)
  27. @behrends Zweites Beispiel in JavaScript let john = { name:

    "John" }; let jane = { name: "Jane", city: { name: "Rome" } }; console.log(john.city.name); // führt zu einem Laufzeitfehler // Uncaught TypeError: 
 // Cannot read property 'name' of undefined
  28. @behrends Zweites Beispiel in Reason

  29. @behrends Superkräfte mit Reason - Automatische Typinferenz . Varianten mit

    Pattern Matching ✊ (und einiges mehr)
  30. @behrends - Automatische Typinferenz Verringert syntaktischen Mehraufwand für statische Typen

  31. @behrends let pi = 3.14; let add = (a, b)

    => a + b; type person = { name: string, mutable role: string, }; let user = {name: "John", role: "reader"}; let makeAdmin = someone => someone.role = "admin"; Oft keine Typannotation nötig — Typen häufig automatisch ermittelt!
  32. @behrends CodeLens für Reason in VS Code. Typinformation wird inline

    dargestellt. Nicht Teil des Codes, siehe Zeilennummern! Typinferenz im Editor
  33. @behrends Typen in Reason/OCaml Typinferenz reduziert den syntaktischen Aufwand für

    statische Typen.
 (Typannotationen können oft weggelassen werden.) Das Typsystem sichert Korrektheit (Soundness) zur Laufzeit zu.
 Inkorrekt typisierte Programme werden nicht vom Compiler übersetzt.
 (Dadurch kommen ganze Kategorien von Fehler gar nicht erst vor.) Reason Code hat 100% Typabdeckung.
 (Code wird dadurch bereits dokumentiert; Supernützlich für Refactorings)
  34. @behrends . Varianten und Pattern Matching Reasons Dokumentation bezeichnet Varianten

    als „Kronjuwel der Reason-Datenstrukturen“
  35. @behrends Problem der Fallunterscheidungen type person = { name: string,

    role: string }; /* role kann beliebige Strings enthalten */ let user = {name: "John", role: "Reader"}; if (user.role == "Admin") { print_endline("now we do something dangerous"); }; Anstatt beliebige String-Werte in role zu erlauben, wäre es viel besser, ausdrücklich alle erlaubten Varianten zu definieren (Reader, Admin, etc.).
  36. @behrends type role = /* Variante mit nur zwei möglichen

    Werten */ | Reader | Admin; type person = { name: string, role, }; let user = {name: "John", role: Reader}; if (user.role == Admin) { print_endline("now we do something dangerous"); }; Der Typ role heißt Variante und besteht aus bestimmten Konstruktoren/Tags Jetzt können wir bloß Reader und Admin als Rollen einsetzen!
  37. @behrends let user = {name: "John", role: Reader}; let messageForUser

    = switch (user.role) { | Reader => "Go away!" | Admin => "Please enter..." }; print_endline(messageForUser); Pattern Matching mit Varianten type role = | Reader | Admin; type person = { name: string, role, };
  38. @behrends Compiler gibt uns freundliche und hilfreiche Warnungen. Supernützlich bei

    größeren Refactorings. type role = | Reader | Editor | Admin; type person = { name: string, role, }; Erweiterung der Varianten mit einer Editor-Rolle…
  39. @behrends option ist eine Variante, die null-Werte simuliert. Mit Pattern

    Matching gibt es keine null-Fehler in Reason! type role = | Reader | Editor | Admin; type person = { name: string, role: option(role) }; Wie kann die Rolle einer Person optional sein? let user = 
 {name: "John", role: Some(Reader)}; let user2 = {name: "Joe", role: None}; let messageForUser = user => switch (user.role) { | Some(Reader) => "Go away!" | Some(Editor) => "Your password?" | Some(Admin) => "Please enter..." | None => "How dare you asking..." };
  40. @behrends ✊ Weitere Superkräfte ✴Extrem schneller Compiler (Reason/OCaml kompiliert viel

    schneller als TypeScript) https://twitter.com/garybernhardt/status/1007690864909529088
  41. @behrends ✊ Weitere Superkräfte ✴Extrem schneller Compiler (Reason/OCaml kompiliert viel

    schneller als TypeScript) ✴Nativer Code kann erzeugt werden (evtl. React Native ohne JavaScript Bridge?) ✴Erstklassiger Support für React (ReasonReact: https://reasonml.github.io/reason-react/) ✴Module erster Klasse (first class modules):
 Jede Datei im Projekt ist ein Modul, require/import werden nicht benötigt ✴Super tooling (Codeformatierung mit refmt, REPL (rtop), freundliche Fehlermeldungen) ✴Interoperabilität mit JavaScript, Output ist lesbares JS mit dead code elimination ✴Fortgeschrittene und moderne Sprachfeatures zu lernen (GADT, Phantom Types,…)
  42. @behrends % Nachteile und Bedenken - Noch in Entwicklung, Syntax

    könnte sich ändern (es gibt ein Syntax-Upgrade-Tool) - Einige neue Konzepte sind zu lernen, daher kann es Missverständnisse geben - Flexibilität geht verloren (dieser Preis ist für statische Typisierung zu zahlen) - Es sollte nicht erwartet werden, dass der Code nun vollständig fehlerfrei ist! - Fragmentatierung der OCaml Standard-Bibliothek (dies ist Work In Progress) - Unicode nur teilweise unterstützt (Workaround mit BuckleScript möglich) - async/await noch in Arbeit (mit Js.Promise in BuckleScript umsetzbar)
  43. @behrends Reason in produktiven Apps Facebooks messenger.com wird mit Reason

    entwickelt: “Full rebuild of the Reason part of the codebase is ~2s (a few hundreds of files), incremental build (the norm) is <100ms on average.” “Messenger used to receive bugs reports on a daily basis; since the introduction of Reason, there have been a total of 10 bugs (that's during the whole year, not per week)!” https://reasonml.github.io/blog/2017/09/08/messenger-50-reason.html
  44. @behrends Zusammenfassung • Probleme im JavaScript-Code (Eigenarten, Laufzeitfehler, etc.) sollten

    zur Entwicklungszeit entdeckt und behoben werden. • Hilfreich sind ESLint und die vielen Ansätze für statische Typisierung. • Reason ist eine vielversprechende Lösung, die dies und noch mehr bietet: ✓mächtiges Typsystem (Inferenz, Korrektheit, Abdeckung zu 100%, …) ✓viele nützliche extra Features (Varianten, Pattern Matching, …) ✓relativ leichter Einstieg für JavaScript-Entwickler (Syntax, Interop, …)
  45. @behrends Nächste Schritte mit Reason ‣ Reason im Browser: https://reasonml.github.io/en/try.html

    ‣ Buch, online-Version umsonst: http://reasonmlhub.com/exploring-reasonml/ ‣ Artikel/Videos: https://reasonml.github.io/docs/en/articles-and-videos.html ‣ Reason in Teilen eines Javascript-Projekts einsetzen: ‣ Installation: https://reasonml.github.io/docs/en/global-installation.html ‣ JS konvertieren: https://reasonml.github.io/docs/en/converting-from-js.html
  46. @behrends Dankeschön! www.behrends.io twitter.com/behrends speakerdeck.com/behrends (Folien) 0