Disy Tech-Blog

Reactive Programming, SpatiaLite, Reader Monad, JDeps

Reactive Programming,
SpatiaLite,
Reader Monad,
JDeps

Aarlaubstag Dezember 2015

09.12.2015

Bei Disy ist seit Jahren jeder erste Mittwoch im Monat „Aarlaubstag“. Wir nutzen ihn zur selbstständigen Weiterbildung, was bei den Entwicklern typischerweise das Herumexperimentieren mit neuen Tools, Techniken und Ansätzen bedeutet. Hier berichten wir euch vom letzten Aarlaubstag Anfang Dezember.


Functional Reactive Programming mit Bacon.js

Adrian Loer

Im Rahmen des Aarlaubstages wollte ich mir Functional Reactive Programming (FRP) in JavaScript anschauen. Ein sehr guter Einstieg in das Thema FRP findet sich hier.

Statt wie in dieser Einführung RxJS zu nutzen habe ich mich für Bacon.js entschieden, da es mir für den Anfang zugänglicher schien. Letztlich scheint es mehr oder weniger so, dass sich nahezu alle Beispiele, die man findet, Framework-unabhängig auf Events und Ajax beschränken.

Das ist nicht besonders aufregend und es musste daher als beispielhafte Anwendung etwas “mit mehr Streams” her. Ich habe daher ein Leap Motion zur Positionsbestimmung von Händen im dreidimensionalen Raum mitgebracht und die dabei anfallenden Daten in Streams genutzt.

Die entstandene Demo beschränkt sich auf die Berechnung der Distanzen zwischen den Fingerspitzen einer einzelnen Hand und erkennt eine einfache Geste (Hand gespreizt Ja/Nein). Diese wurde mit BrainJS trainiert, um die Demo überhaupt bedienbar zu machen. Eine Geste besteht dabei aus 4 Inputs (den Distanzen zwischen den Fingerspitzen) und einem Output (einer Wahrscheinlichkeit für die Spreizgeste).

Durch Bewegen der Hand kann, sofern sie gespreizt ist, eine Karte bewegt werden. Zeit für eine kurze Demo:

Zum Kennenlernen von FRP war das Projekt super. Die Vorteile gegenüber imperativem Code wurden klar ersichtlich und vielleicht werde ich es demnächst auch mal ganz im Sinne der offiziellen Beispiele (mit Events und Ajax) einsetzen können.


SpatiaLite im Browser

Viktorija Solovjova

Kürzlich haben wir SpatiaLite in Cadenza Mobile NG integriert. Darüber gab es an dieser Stelle auch schon zwei Posts (diesen und diesen). Wir verwenden dabei Cordova SpatiaLite Storage – unser Fork des Cordova Plugins Cordova SQLite Storage.

Da das im Moment nur auf mobilen Geräten funktioniert, muss die Entwicklung aufwändig auf dem Gerät gemacht werden. Lieber wäre uns die App einfach im Browser zu öffnen und als eine normale Web-App zu entwickeln. Deshalb wäre es für uns sehr hilfreich SpatiaLite auch im Browser zum Laufen zu bekommen.

sql.js

Am Anfang habe ich versucht eine JavaScript Bibliothek zu finden, die im Browser mit SpatiaLite arbeiten kann. Ich habe sql.js gefunden. Das ist eine JS Bibliothek, die vom echten SQLite-C-Code mit Emscripten nach JavaScript kompiliert wurde. Leider unterstützt sie die SpatiaLite-Extension nicht.

Also habe ich versucht, den SpatiaLite-C-Code mit denselben Empscripten nach JavaScript zu kompilieren. Das ist aber u.a. wegen der Projektgröße und der Abhängigkeiten sehr aufwändig. Schnell stellte sich heraus, dass man das in einem Aarlaubstag nicht schafft.

Eigener Webserver mit Python

Dann hatte ich noch eine Idee: Wir könnten einen einfachen Webserver haben, der mit der lokalen SQLite/SpatiaLite Datenbank kommuniziert. Von JavaScript aus könnten wir dann Ajax Requests mit SQL-Anfragen an diesen Server schicken und die Daten in Json zurückerhalten.

Python hat dafür alles was man braucht:

  • BaseHTTPServer – einen einfachen Webserver
  • pyspatialite – eine Bibliothek für SpatiaLite
  • json – ein Paket, mit dem man einfach Python-Objekte von und nach JSON konvertieren kann

Bei der Implementierung habe ich festgestellt, dass pyspatialite leider nur SpatiaLite Version 3.0.1 versteht. Und natürlich benutzen wir in unseren Anfragen neuere Funktionen – z.B. ST_EnvelopesIntersects aus Version 4.2.0.

Manuelles Nachladen von SpatiaLite

Auch hierfür gibt es eine Lösung. SQLite hat die Möglichkeit, dynamisch Extensionen zu laden. Deshalb habe ich pyspatialite gegen sqlite3 ausgetauscht, was allerdings kein SpatiaLite kennt. Dafür habe ich im Code nach dem Connect folgende Anfrage hinzugefügt, die SpatiaLite nachlädt:

select load_extension('libspatialite.so')

Das funktioniert! Es ist allerdings OS-abhängig und außerdem muss auf dem Rechner libspatialite installiert sein.


Reader Monad

Boris Terzic

Nach einem interessanten Vortrag über funktionale Programmierung in Java 8 von Nicole Rauch bei der JUG Karlsruhe ist mir wieder eingefallen, dass ich bei rein funktionaler Programmierung noch nie verstanden habe wie das Problem der Konfiguration “gelöst” wird. Mit Konfiguration meine ich Werte, die im Programmlauf als Konstanten behandelt, aber beim Start irgendwie definiert werden, zum Beispiel in einer Konfigurationsdatei.

Wenn meine Funktionen keine Seiteneffekte haben dürfen, kann ich in Pure Functions die Konfiguration nicht einfach aus einer Datei lesen. Dann bleibt, so dachte ich, nur noch die Möglichkeit die Konfiguration der Funktion als Parameter zu übergeben. Wenn ich das tue, muss ich allerdings allen Funktionen, welche die konfigurierbare Funktion aufrufen, auch diese Parameter mitgeben. Das sorgt für eine sehr fragile und instabile Architektur: Bei jeder Änderung muss ich die ganze Funktionskette mit anpassen.

Am Aarlaubstag habe ich mir dieses Problem ein bisschen näher angeschaut. Es wurde sofort klar, dass das “Problem” tatsächlich besteht und auch online diskutiert wird. Die meisten erwähnten Optionen, neben dem offensichtlichen Parameteransatz, fühlen sich schlecht an (Meta-Programming, unsafePerformIO, implicit Parameters) oder sind für Normalsterbliche nicht nachvollziehbar (Reflection).

Sehr oft kam die Empfehlung die Reader-Monade zu verwenden. Dieser Ansatz bedingt, dass man sein Programm, zumindest den Teil der Konfiguration braucht, “monadisch” schreibt. Das heißt im Falle der Reader-Monade, dass die Funktionen nicht mehr einfach einen Wert zurückgeben, sondern eine Reader-Monade. Diese beschreibt, dass die Funktion in einem Kontext ausgeführt werden soll, in dem die notwendige Konfiguration zur Verfügung steht.

Zum Beispiel, anstatt:

f :: Config -> Int -> Int
f (Config a) m = m + a

würde man dann schreiben:

f :: Int -> Reader Config Int
f m = do { Config a <- ask; return (m + a) }

Der Vorteil wird erst dann offensichtlich, wenn man eine Verkettung von Funktionen schreiben muss. Die kann man mit dem bind-Operator (aka >>=) so realisieren, dass die konkrete Konfiguration nicht überall auftaucht:

g :: Int -> Reader Config Int
g x = f1 x >>= f2 >>= f3

Das Interessante an der Reader-Monade ist, dass sie als genereller Ansatz taugt, um Abhängigkeiten zu externalisieren und Funktionen übergeben zu lassen – mit dem Nachteil, dass der Code “monadisch” geschrieben werden muss.

Vollständig haben wir Monaden auf jeden Fall noch nicht verstanden, aber wir arbeiten dran.


JDeps & Maven

Nicolai Parlog

Auch wenn das Java-9-Release vermutlich auf März 2017 verschoben wird, wollten wir schon mal schauen, was uns bei der – eventuell etwas holprigen – Migration erwartet. In einem ersten Schritt wollten wir unsere Abhängigkeiten auf JDK-interne APIs (also sun.* und vieles aus com.sun.*) evaluieren, denn sie werden nicht mehr verfügbar sein.

Mit jdeps ist das eigentlich sehr einfach, aber niemand hatte vor, es manuell auf die vielen hundert Module anzuwenden, aus denen z.B. Cadenza besteht. Deswegen haben wir es per JDeps Mvn in unseren Maven Build integriert.

Vom Ergebnis waren wir positiv überrascht. Während eine erste Textsuche über 200 problematische Abhängigkeiten ankündigte, mäkelte jdeps kaum zwei Dutzend an. Einige davon sehen wie verwechselte Imports aus und für andere gibt es einfache Alternativen. Aber ein paar werden wir uns in den kommenden Monaten genauer angucken müssen.

Damit wir die Migration schrittweise durchführen können, wollen wir Warnungen für die bekannten Abhängigkeiten bekommen, aber einen scheiternden Build bei anderen. Dazu verwenden wir JDeps Mvn‘s Regeln, die das Plugin automatisch aus den erkannten Abhängigkeiten erstellt. Jetzt können wir jedes Mal, wenn wir eine Abhängigkeit abräumen, die dazugehörige Ausnahme entfernen und so sichergehen, dass es keine versehentlichen Rückfälle gibt.


Das Titelbild heißt code.close() und wurde von Ruiwen Chua unter CC-BY-SA 2.0 veröffentlicht. Wir haben den Bildausschnitt verändert und verbreiten es ebenfalls unter CC-BY-SA 2.0.