Advertisement
Advertisement

More Related Content

Advertisement

Recently uploaded(20)

Funktionale Reaktive Programmierung mit Sodium

  1. Funktionale reaktive Programmierung mit Sodium Torsten Fink torsten.fink@akquinet.de http://viralpatel.net/blogs/lambda-expressions-java-tutorial/
  2. Zu meiner Person • 2003: Promotion an der FU zum Thema SW-Architekturen und Verteilte Systeme • Ab 2004: Berater bei der akquinet • technischer Architekt in J2EE-Projekten • Projektleitung • Betriebsführung, Wartung • klassische Beratung und Schulungen • 2006-2010: Leiter des JBoss-Competence-Centers bei der akquinet • Ab 2011: Geschäftsführer der akquinet tech@spree
  3. Meine Firma
  4. Funktionale GUIs – ein Oxymoron ??
  5. Funktionale GUIs – ein Oxymoron? „Reine funktionale Sprachen (z.B. Haskell) §haben keine Seiteneffekte §=> f(x) ist für festes x konstant „Problematisch sind damit, z.B. leseDateneingabeVomBenutzer() leseAktuelleMausposition() leseFormularfelder()
  6. Dann kam... „Erste Version: 0.1.0.0 – März 2011 „Aktuelle Version: 1.1.0.1 – Mai 2016 „Nur GUI-Logik, ohne GUI-Anbindung => Im Prinzip fertig „three-penny-gui: Browser als GUI Reactive Banana
  7. Für Haskell coole GUIs ..
  8. Problem gelöst? „Prinzipiell schon, aber.. §Framework für Nicht-Haskell-Experten nicht leicht zugänglich „Aus einem Tutorial How? variation in time as first-class value type Behavior a = Time → a type Event a = [(Time, a)] key data types are Behavior and Event. vior corresponds to a „value that varies in time“. t corresponds to „events that occurr at certains points in time“. Behavior API instance Applicative Behavior Functor instance Functor Behavior
  9. Subjektive Bewertung „GUI-Problem für funktionale Sprachen damit prinzipiell gelöst. „Stringente Architektur mit einfachen Primitiven, §die komplexe §interaktive und aktive §Oberflächen ermöglicht.
  10. Parallel/leicht verzögert entwickelte sich ... „The Reactive Manifesto (V1.0 – 2013, V2.0 - 2014) https://www.reactivemanifesto.org §Architekturprinzipien für antwortbereite (responsive), widerstandsfähige (resilient), elastische, nachrichtenorientierte Systeme „Reactive Extensions (Rx) §Erweiterung von LINQ (Abfragesprache für .NET) für Ereignissteuerung ohne Rückrufmethoden basierend auf Observer-Muster http://reactivex.io/intro.html (vor 2012 entwickelt, konstante Weiterentwicklung)
  11. Und auch dieses hier... „Von Stephen Blackheath, Anthony Jones; 2016 „FRP als Architekturstil mit Schwerpunkt auf Sodium => eigenes Framework „IMHO: Erfahrene GUI-Pragmatiker entdecken FRP im Reactive-Umfeld neu (späterer Abgleich mit Reactive Banana)
  12. Worum geht es hier? „Framework §mit theoretisch beweisbaren Eigenschaften §um Fehlerklassen zu eliminieren, §die bei klassischer Callback-basierten GUIs auftreten §unabhängig von GUI-Framework. „... klingt erstmal nach Elfenbeinturm
  13. Die 6 Plagen der Listener Aus dem FRP-Buch von S. Blackheath, A. Jones entnommen
  14. Unpredictable Order of Events „Ausführungsreihenfolge von Listenern hängt ab von Registrierungsreihenfolge „bei FRP: §Reihenfolge der Bearbeitung ist nicht relevant, §da unabhängige Berechnungen sich nicht „sehen“ §aufgrund von unveränderbaren Daten und GUI-TX
  15. Missed First Events „Problem, dass Events verschickt werden, bevor alle Listener registriert sind (z.B. in der Initialisierungsphase) „Bei FRP: Zuerst werden alle “Listener“ konfiguriert, bevor Events verschickt werden
  16. Messy State „Listener-basierter Code orientiert sich üblicherweise an Zustandsmaschinen (z.B. Entität unverändert/verändert, Feld gültig/ungültig) „Dieser ist mit Zustand und Zustandsübergängen im Code sehr verteilt und wird schnell unwartbar „Bei FRP: Funktionales Ordnen von Zuständen und Übergängen
  17. Threading Issues „Gefahr von Deadlock in einem Multihreading-System „Bei FRP §keine inhärenten Listener, sondern Event-Ströme, die sich nicht in die Quere kommen können §+ Immutable State, so dass keine Synchronisierung notwendig ist (innerhalb des FRPs)
  18. Leaking Callbacks „Speicherlöcher durch nicht deregistrierte Listener „Registrierung von Listenern ist schon schwierig, umso mehr die Deregistrierung „Bei FRP keine Listener, sondern Event-Ströme, die in Gänze aus dem Scope fallen und aufgeräumt werden
  19. Accidental Recursion „Die Reihenfolge, in der Zustand verändert wird und Events ausgelöst werden, ist wichtig, Fehler können zu Endlosschleifen und Inkonsistenzen führen. „Bei FRP: §komplette Analyse der Eventströme §+ Transaktionsmodell §= keine Rekursion/Zyklen, keine Inkonsistenzen
  20. Ich will Code !!!
  21. Die zwei Basiselemente von Sodium „Zellen (Cell<T>) §Speichern/Verwalten von Zustand, der sich über Zeit ändert (alle anderen Daten/Objekte sind unveränderbar) §Hält ein Element vom Typ T „Ströme (Stream<T>) §Verwalten von Aktivitäten §Überträgt ein Ereignis vom Typ T Zelle Strom
  22. Der Taschenrechner „War zu optimistische Übungsaufgabe in Java „Fähigkeiten §Eingabe von Zahlen §Mehrstufige Additionen und Subtraktionen §Abschluss einer Berechnung „GUI in Java FX „Der Code: https://github.com/akquinet/sodiumcalculat or
  23. Die (grobe) Architektur „CalculatorView §Erzeugt GUI §Delegiert Aktionen an den Controller §Angemeldet an der DisplayCell für die Darstellung der Anzeige „CalculatorController §GUI – Status §GUI – Logik
  24. Ankopplung von FRP mit Sodium „ Registrieren an einer Zelle in der GUI // Bibliothek für Hilfsfunktionen außerhalb FRP Operational // Konvertiert Cell in Strom von Zuständen .updates(controller.getDisplayCell()) // registriert Listener .listen(v -> displayTF.setText("" + v)); „ Senden von Ereignissen außerhalb FRP void pressDigit(Long digit) { clickedDigitS.send(digit); } „ Achtung: Dies hier ist außerhalb von FRP, die 6 Plagen existieren hier.
  25. Feature 1: Die Anzeige „Zelle Display – hält den Wert, der angezeigt werden soll „Klick auf Taste dig: display -> display*10+dig “3“ “2“
  26. In FRP als Diagramm – Schritt 1 „Anwender drückt eine Zahl 3, diese wird von außen reingegeben „TX startet, 3 wird propagiert displayC clickedDigitS updatedEnteredNumberS 3 3
  27. In FRP als Diagramm – Schritt 2 „Nächster Strom bekommt die 3, holt sich den aktuellen Zustand aus Display, verknüpft beide über eine Berechnung displayC clickedDigitS updatedEnteredNumberS 3 0 0*10 + 3 3
  28. In FRP als Diagramm – Schritt 3 „Ende der Transaktion, Ergebnis wird in Zelle gespeichert „Externe Listener werden benachrichtigt displayC clickedDigitS updatedEnteredNumberS 3
  29. Berechnung als programmatische Konfiguration „updatedEnteredNumberS = clickedDigitS.snapshot(displayC, (digit, display) -> display * 10 + digit); displayC clickedDigitS updatedEnteredNumberS display * 10 + digit
  30. In Gänze mit Schleife „displayC = new CellLoop<>(); updatedEnteredNumberS = ...; // vorherige Folie displayC.loop(updatedEnteredNumberS.hold(0L)); displayC clickedDigitS updatedEnteredNumberS displayC ist immer definiert
  31. Feature 2: Mehrfaches Plus „Ist nur mit Display nicht möglich „IMHO: 2 Register 123 + 2 +
  32. Mit zwei Register: Main und Back 123 + 2 + m=0 b=0 m=123 b=0 m=0 b=123 m=2 b=123 m=0 b=125
  33. In FRP als Diagramm displayC clickedDigitS updatedEnteredNumberS clickedPlusS mainC backC :CombinedState updateStateFromPlusS Das hier ist die fachliche Komplexität des halben Rechners => Er ist tatsächlich nicht so einfach.
  34. Lift: Abgeleitete Zustände „class CombinedState { final Long display; final Long back; final Long main; CombinedState(Long display, Long main, Long back) {...} } „final Cell<CombinedState> calculatorStateC = displayC.lift(mainC, backC, CombinedState::new); displayC mainC backC :CombinedState
  35. Die Berechnung bei Plus „final Stream<CombinedState> updatedStateFromPlusS = clickedPlusS.snapshot( calculatorStateC, (unit, state) -> { Long result = state.main + state.back; return new CombinedState(result, 0L, result); }); clickedPlusS calculatorStateC:CombinedState updateStateFromPlusS
  36. Anpassung des Hintergrundregister „backC.loop( updatedStateFromPlusS .map(s -> s.back) .hold(0L)); backCcalculatorStateC updateStateFromPlusS
  37. Anpassung der Anzeige „displayC.loop( updatedEnteredNumberS .orElse(updatedStateFromPlusS .map(s -> s.display)) .hold(0L)); displayC clickedDigitS updatedEnteredNumberS updateStateFromPlusS Analog das Main-Register
  38. Finale Ausbaustufe „Mit §zusätzlicher „-“ Operation § „=“ Taste für Abschluss von Berechnungen „Code hier mal ausgelassen (als Übung für den interessierten Zuhörer :-)
  39. Vergleich der LOCs pro Ausbaustufe „Gemessen wurde der Controller nicht die GUI (86 LOC) „LOCs steigen „vernünftig“ mit der fachlichen Komplexität (Anstieg zwischen „Addition“ und „Finale“ ist erstaunlich gering) „Code lässt sich IMHO gut refactoren bei neuen Anforderungen 0 20 40 60 80 100 120 LOC Anzeige Addition Finale
  40. Testen lässt es sich auch „@Test void pressDigit123() { calculatorController.pressDigit(1L); calculatorController.pressDigit(2L); calculatorController.pressDigit(3L); assertEquals(Long.valueOf(123L), getDisplay()); } „private Long getDisplay() { return calculatorController .getDisplayCell().sample(); }
  41. Was soll ich mit JavaFX?
  42. ... Ich will Web! „Sodium ist Framework-unabhängig. „Hier der Taschenrechner mit §Typescript + Sodium + Angular https://blog.akquinet.de/2018/06/24/functional-reactive- programming-with-angular-and-sodium/ (etwas komplexer, um Komponententauglichkeit zu evaluieren.)
  43. Ok, genug Code ... Vielleicht noch ein paar allgemeine Dinge
  44. GUI Transaktionen
  45. Meistens ist es einfach....
  46. Manchmal aber nicht ...
  47. Nebenläufige Verarbeitung Unbestimmte Reihenfolge der Bearbeitung
  48. Auf welchen Modellen? Nichtdisjunkte Operationen => Fehler
  49. Was sieht der Nutzer? Evtl. Flackern, Falsches finales Modell
  50. Jetzt mit Transaktionen in Sodium
  51. Jetzt mit Transaktionen in Sodium Ausführungs- reihenfolge irrelevant, weil ...
  52. Operationen greifen auf altes Modell zu Ergebnisse anderer Operationen werden nicht gesehen
  53. ... und festschreiben ... Reihenfolge egal, durch Zusammenfüh- rung von Ereignissen
  54. Was der User sieht .... Kein Flackern, deterministischer Zustand
  55. Transaktionen in der GUI - Kommentare „Start von Transaktionen §Automatisch, wenn extern ein Ereignis erzeugt wird §Oder händisch über Transaction Bibliotheksklasse „Zusammenfassung über Events durch: // Kombinationsfunktion, falls beide Streams einen Event anbieten s1.merge(s2, (l,r) -> l) // Kurzschreibweise für oben s1.orElse(s2)
  56. Threading
  57. Geschenke durch Funktionale Programmierung „Referenzielle Transparenz reduziert Threading- Probleme „FRP §analysiert Abhängigkeiten §arbeitet diese sequenziell ab §und hat daher keine Nebenläufigkeitsprobleme
  58. Herausforderungen der Nicht-FP-Welt „Einstieg in FRP über send() void pressDigit(Long digit) { clickedDigitS.send(digit); } Aus welchen Threads ist der Aufruf erlaubt? „Ausstieg aus FRP über Listener Operational .updates(displayC) .listen(displayListener); Was dürfen die Listener und in welchem Thread laufen sie?
  59. Die Regeln „Sodiums Threading-Eigenschaften § send() kann aus (fast) jedem Kontext ausgeführt werden, ohne zu blockieren § Ausführung der Listeners auf dem Thread, der send() ausgeführt hat „Regeln von Sodium für (externe) Listeners § Kein Aufruf von send() § Keine blockierende Operation (muss an anderen Thread delegiert werden) „Zusammengefasst: Externer Code kümmert sich um Threading (z.B. Mit klassichen Workern)
  60. Was ist mit RX?
  61. RX ist überall „Kontinuierliche Weiterentwicklung „Z.B. direkt in Angular eingebaut. „Aus unserer Erfahrung häufig verwirrend, z.B. § Hot (Event-Weiterleitung) vs. Cold (Kapselung eines Stream-Erzeugers) § Life-Cycle-Callbacks (next(), error(), complete()) § Menge an Funktionalitäten RX-Subject (~ 125 Methoden) vs. Sodium-Stream (~25 Methoden)
  62. RxJs und FRP „Keine klare Trennung zwischen der „reinen“ FRP Welt und dem Rest des Codes => keine FRP-Kompositionseigenschaften (man verliert leicht schöne Eigenschaften, s. die 6 Plagen) „RxJs bietet viele unterschiedliche Dinge, insb. I/O Unterstützung, Threading aber auch Rechenfunktionalität (Listenverarbeitung über Cold-Observables) „RxJs hat kein Transaktionskonzept und keine erzwungene Zusammenführung für gleichzeitige Ereignisse „Mit einem Subset von Rx lässt sich FRP-ähnlich entwickeln. (Stream = Hot Observable, BehaviorSubject = Cell)
  63. Kommentare zu Sodium
  64. Der äußere Eindruck „Bescheidener Webauftritt (altertümliches, aber gut funktionierendes Forum +GitHub)
  65. Unterstützte Sprachen: „C#, Typescript aktive Weiterentwicklung „Java, Clojure Wartungsmodus „Haskell, Rust, C++ keine Weiterentwicklung „Rust, C , Kotlin experimental
  66. Persönliche Bewertung „Nach § Einigen explorativen Fingerübungen (JavaFX, Angular/TS) § Einem Swing-Portal für eine Mikroservicearchitektur „Gefühl § Ausgereiftes, abgeschlossenes Framework => kein aufgetretenes Problem lag an Sodium § Einarbeitung benötigte kurzes Umdenken, dann war es einfach. (Vorbedingung: Grundlagen funktionaler Programmierung) § Trennung von konkretem GUI-Framework fühlte sich gut an. Dennoch: Eine Integration könnte den Komfort erhöhen.
  67. Alles gut? Mal zusammengefasst
  68. Die letzte Folie „Functional Reactive Programming ist ein stringentes Programmiermodell für GUIs mit schönen Eigenschaften „Sodium hat bis jetzt einen stabilen und vollständigen Eindruck und Spaß gemacht. „Listeners sind out. „Und, ja, wir sind auch auf der Suche nach neuen Kollegen :-)
Advertisement