Überblick über die Entwicklung mit Clojure bei HEROLABS.
* Warum haben wir uns für Clojure entschieden? (Simplicity, Erweiterbarkeit, Java-Interop)
* Was heißt Funktionale Programmierung?
=> Man braucht ein anderes Mindset
* Was uns stört.
* Und wie entwickelt man mit Clojure (Ecosystem)?
Anlass war ein Talk bei mgm-tp.
Funktionale Programmierung und mehr mit Scalathoherr
Anhand von Beispielen werden einige Konzepte der funktionalen Programmierung im Allgemeinen und die objekt-funktionale Sprache Scala im Besonderen vorgestellt.
Vortrag von 42ways im Rahmen der IT-Weiterbildungsveranstaltungen bei der SwissLife AG, Niederlassung für Deutschland, München.
Überblick über die Entwicklung mit Clojure bei HEROLABS.
* Warum haben wir uns für Clojure entschieden? (Simplicity, Erweiterbarkeit, Java-Interop)
* Was heißt Funktionale Programmierung?
=> Man braucht ein anderes Mindset
* Was uns stört.
* Und wie entwickelt man mit Clojure (Ecosystem)?
Anlass war ein Talk bei mgm-tp.
Funktionale Programmierung und mehr mit Scalathoherr
Anhand von Beispielen werden einige Konzepte der funktionalen Programmierung im Allgemeinen und die objekt-funktionale Sprache Scala im Besonderen vorgestellt.
Vortrag von 42ways im Rahmen der IT-Weiterbildungsveranstaltungen bei der SwissLife AG, Niederlassung für Deutschland, München.
Funktionale Programmierung hat zu guter Letzt auch in Java Einzug gehalten. Es ist jetzt ganz normal, überall mit Lambdas oder mit map() und filter() zu arbeiten. Aber ist das wirklich funktionale Programmierung?
Wie sieht es aus, wenn man Java 8 mit einer althergebrachten funktionalen Programmiersprache vergleicht? Und was kann der Java-Programmierer, der aus der objektorientierten (OO) Entwicklung kommt, von funktionalen Sprachen lernen und in seinen Java-Alltag integrieren?
Auf diese Fragen ging Nicole Rauch in ihrem Referat ein. Ebenso stellte sie die grundlegenden Aspekte er funktionalen Programmierung vor und zeigte auf, was die funktionale Programmierung so besonders macht.
Gerne stellen wir Ihnen die Slides des Referats zur Verfügung.
Dev Day 2019: Mirko Zeibig – "Hallo " <> "Elixir"DevDay Dresden
Seit Prozessoren nicht mehr schneller sondern nur noch mehr werden, werden uns häufig Konzepte aus der Welt der funktionalen Programmierung als Lösung versprochen. Aber wer hat schon Lust, Quellcode zu schreiben, dessen zweite Hälfte aus schließenden Klammern besteht?
Funktional programmieren aber mit modernem Syntax und solidem Unterbau. Das verspricht die Programmiersprache Elixir.
Dieser Vortrag wird zum einen die Grundlagen der Sprache vorstellen und wo vorhanden Parallelen zum Java-Umfeld aufzeigen.
Zum anderen wird gezeigt, warum Anwendungen auf Basis von Elixir die Bezeichnungen „Serverless“ und „Microservices“ eher verdienen als andere.
Vortrag der OOP 2014
Überblick über die Vorteile der Programmiersprache Go für skalierbare Anwendungen sowie ein Einblick in hierbei zu beachtende Probleme und ihre Lösung.
Die Programmiersprache C++ gehört immer noch zu den wichtigsten Programmiersprachen überhaupt. Gerade im Embedded Bereich vollzieht sich langsam die Abkehr von C zu C++ und ist dort alternativlos. Es hatte jedoch jahrelang den Anschein, als würde diese Sprache seit Jahren nicht weiterentwickelt und von den Features und Ausdrucksmöglichkeiten hinter neueren Sprachen zurückzufallen. In diesem Vortrag zeige ich an Codebeispielen, welche Revolution tatsächlich seit C++11 stattgefunden hat und dass die Sprache keinesfalls mehr mit der zu vergleichen ist, die man vielleicht vor Jahren kennen (und vielleicht hassen) gelernt hat. Die Umgestaltung der Sprache ist dabei keineswegs abgeschlossen sondern zeigt weitere, vielversprechende Konzepte am Horizont.
Warum ECMAScript 6 die Welt ein Stückchen besser machtSebastian Springer
Wo die Neuerungen von ECMAScript 5 recht unspektakulär waren, sind die Features des neuen Sprachstandards umso interessanter. ECMAScript 6 versucht einige Anforderungen zu erfüllen, mit denen man als JavaScript-Entwickler täglich konfrontiert ist. Klassische Beispiele sind hier Promises zum Umgang mit asynchronen Funktionen, ein Module Loader zur Strukturierung der Applikation, Generatoren und Iteratoren oder aber ein neuer Gültigkeitsbereich für Variablen. Aber nicht nur große Änderungen, sondern auch sinnvolle Erweiterungen bestehender Objekte wie String und Array halten mit dem neuen Standard Einzug in den Browser. Problematisch wird die Situation jedoch, wenn man in den Genuss verschiedener Features kommen möchte, die aktuell noch von keinem Browser unterstützt werden. Hier schafft Traceur, der ECMAScript-6-Compiler von Google, Abhilfe.
MapStruct - der neue Stern am Bean-Mapping Himmel?!inovex GmbH
Speaker: Gerrit Brehmer
Event: W-JAX 2015
07.11.2015
weitere Vorträge von inovex: https://www.inovex.de/de/content-pool/vortraege
Bean Mapping ist kein Thema, mit dem man sich lange aufhalten möchte. Jedoch wird es häufig zum Mappen von internen Klassenstrukturen zu DTOs und wieder zurück benötigt. Wird der Mapping-Code selbst geschrieben, sind Flüchtigkeitsfehler an der Tagesordnung. Alternativen wie Dozer oder BeanUtils nehmen einiges an Arbeit ab, sitzen aber mit Reflection und XML-Konfiguration wie ein Fremdkörper in der Applikation und können die Performance beeinträchtigen.
MapStruct verspricht dagegen Typsicherheit, Schnelligkeit und Flexibilität. Der Vortrag zeigt die Stärken der Java-Only-Lösung, die (fast) den kompletten ungeliebten Boilerplate-Mapping-Code anhand von annotierten Interfaces zur Compile-Zeit generiert. Die übrig gebliebenen Sonderfälle übernimmt man dann gerne selbst.
Mit Java 8 haben endlich Lambdas in den Sprachumfang von Java Einzug gehalten. Mittels Lambdas lassen sich viele Probleme kurz und prägnant ausdrücken. Vorliegende Auskopplung aus Handouts zur Vorlesung Programmieren I führt Lambdas und Streams ein und erläutert den Einsatz an vielen kleineren Beispielen.
Funktionale Programmierung hat zu guter Letzt auch in Java Einzug gehalten. Es ist jetzt ganz normal, überall mit Lambdas oder mit map() und filter() zu arbeiten. Aber ist das wirklich funktionale Programmierung?
Wie sieht es aus, wenn man Java 8 mit einer althergebrachten funktionalen Programmiersprache vergleicht? Und was kann der Java-Programmierer, der aus der objektorientierten (OO) Entwicklung kommt, von funktionalen Sprachen lernen und in seinen Java-Alltag integrieren?
Auf diese Fragen ging Nicole Rauch in ihrem Referat ein. Ebenso stellte sie die grundlegenden Aspekte er funktionalen Programmierung vor und zeigte auf, was die funktionale Programmierung so besonders macht.
Gerne stellen wir Ihnen die Slides des Referats zur Verfügung.
Dev Day 2019: Mirko Zeibig – "Hallo " <> "Elixir"DevDay Dresden
Seit Prozessoren nicht mehr schneller sondern nur noch mehr werden, werden uns häufig Konzepte aus der Welt der funktionalen Programmierung als Lösung versprochen. Aber wer hat schon Lust, Quellcode zu schreiben, dessen zweite Hälfte aus schließenden Klammern besteht?
Funktional programmieren aber mit modernem Syntax und solidem Unterbau. Das verspricht die Programmiersprache Elixir.
Dieser Vortrag wird zum einen die Grundlagen der Sprache vorstellen und wo vorhanden Parallelen zum Java-Umfeld aufzeigen.
Zum anderen wird gezeigt, warum Anwendungen auf Basis von Elixir die Bezeichnungen „Serverless“ und „Microservices“ eher verdienen als andere.
Vortrag der OOP 2014
Überblick über die Vorteile der Programmiersprache Go für skalierbare Anwendungen sowie ein Einblick in hierbei zu beachtende Probleme und ihre Lösung.
Die Programmiersprache C++ gehört immer noch zu den wichtigsten Programmiersprachen überhaupt. Gerade im Embedded Bereich vollzieht sich langsam die Abkehr von C zu C++ und ist dort alternativlos. Es hatte jedoch jahrelang den Anschein, als würde diese Sprache seit Jahren nicht weiterentwickelt und von den Features und Ausdrucksmöglichkeiten hinter neueren Sprachen zurückzufallen. In diesem Vortrag zeige ich an Codebeispielen, welche Revolution tatsächlich seit C++11 stattgefunden hat und dass die Sprache keinesfalls mehr mit der zu vergleichen ist, die man vielleicht vor Jahren kennen (und vielleicht hassen) gelernt hat. Die Umgestaltung der Sprache ist dabei keineswegs abgeschlossen sondern zeigt weitere, vielversprechende Konzepte am Horizont.
Warum ECMAScript 6 die Welt ein Stückchen besser machtSebastian Springer
Wo die Neuerungen von ECMAScript 5 recht unspektakulär waren, sind die Features des neuen Sprachstandards umso interessanter. ECMAScript 6 versucht einige Anforderungen zu erfüllen, mit denen man als JavaScript-Entwickler täglich konfrontiert ist. Klassische Beispiele sind hier Promises zum Umgang mit asynchronen Funktionen, ein Module Loader zur Strukturierung der Applikation, Generatoren und Iteratoren oder aber ein neuer Gültigkeitsbereich für Variablen. Aber nicht nur große Änderungen, sondern auch sinnvolle Erweiterungen bestehender Objekte wie String und Array halten mit dem neuen Standard Einzug in den Browser. Problematisch wird die Situation jedoch, wenn man in den Genuss verschiedener Features kommen möchte, die aktuell noch von keinem Browser unterstützt werden. Hier schafft Traceur, der ECMAScript-6-Compiler von Google, Abhilfe.
MapStruct - der neue Stern am Bean-Mapping Himmel?!inovex GmbH
Speaker: Gerrit Brehmer
Event: W-JAX 2015
07.11.2015
weitere Vorträge von inovex: https://www.inovex.de/de/content-pool/vortraege
Bean Mapping ist kein Thema, mit dem man sich lange aufhalten möchte. Jedoch wird es häufig zum Mappen von internen Klassenstrukturen zu DTOs und wieder zurück benötigt. Wird der Mapping-Code selbst geschrieben, sind Flüchtigkeitsfehler an der Tagesordnung. Alternativen wie Dozer oder BeanUtils nehmen einiges an Arbeit ab, sitzen aber mit Reflection und XML-Konfiguration wie ein Fremdkörper in der Applikation und können die Performance beeinträchtigen.
MapStruct verspricht dagegen Typsicherheit, Schnelligkeit und Flexibilität. Der Vortrag zeigt die Stärken der Java-Only-Lösung, die (fast) den kompletten ungeliebten Boilerplate-Mapping-Code anhand von annotierten Interfaces zur Compile-Zeit generiert. Die übrig gebliebenen Sonderfälle übernimmt man dann gerne selbst.
Mit Java 8 haben endlich Lambdas in den Sprachumfang von Java Einzug gehalten. Mittels Lambdas lassen sich viele Probleme kurz und prägnant ausdrücken. Vorliegende Auskopplung aus Handouts zur Vorlesung Programmieren I führt Lambdas und Streams ein und erläutert den Einsatz an vielen kleineren Beispielen.
Code Days 2019, München: Vortrag von Johannes Weigend (@JohannesWeigend, Technischer Geschäftsführer bei QAware)
=== Dokument bitte herunterladen, falls unscharf! Please download slides if blurred! ===
Abstract:
Programmiersprachen für die Cloud - Java und Go im Vergleich
Java ist nach dem Tiobe Index 2018 unangefochten Platz 1 bei den weltweit eingesetzten Programmiersprachen. Java ist ausgereift, stabil und verfügt über ein immenses Open Source Ökosystem. Was will man mehr? Obwohl Java gerade für die Backend Entwicklung attraktiv ist, hat Google 2008 eine eigene Programmiersprache Open Source gestellt: Golang oder kurz Go. Der Vortrag beleuchtet die Stärken und Schwächen von Go gegenüber Java, gibt Hinweise für welche Projekte Go eine gute Alternative ist, und wie ein Best of Breed Ansatz aussehen kann. Interessant an Go ist, dass die Grundbausteine von Cloud Plattformen wie OpenShift oder die Google Container Plattform mit Go erstellt wurden. Docker, Kubernetes, Helm, Grafana oder Prometheus ‒ alles ist mit Go programmiert. Die Fragen aus der Sicht von Java-Experten sind: Was macht Go für die Cloud so interessant? Gibt es Funktionen, die Java Programmierer kennen sollten, und wenn ja, welche?
Funktionale Reaktive Programmierung mit SodiumTorsten Fink
Reaktive Programmierung hat sich über RxJS in der Web-Entwicklung als Standardentwicklungsmuster etabliert. RxJS selber ist zwar sehr mächtig aber gleichzeitig auch sehr komplex und damit anfällig für Fehler, die aus Unverständnis entstehen. Alleine die Unterscheidung zwischen heißen, kalten und lauwarmen Strömen können einen Entwickler bei dem ersten Kontakt mit dem Framework nachhaltig verwirren.
Die funktionale reaktive Programmierung (FRP) stellt eine Variante reaktiver Programmierung dar. Sie basiert auf einem vergleichsweise kleinen und stringentem Satz an Basisoperationen und Kombinatoren. Diese ermöglichen es, komplexe GUI-Logik modular zu implementieren und dabei typische Fehlerklassen bei der GUI-Entwicklung auszuschließen.
In diesem Vortrag wird FRP anhand des Open-Source Frameworks Sodiums vorgestellt.
nagiosplugin - eine Python-Bibliothek für Monitoring-Plugins Christian Kauhaus
Auch wenn in der letzten Zeit sehr viel Bewegung in die Monitoring-Szene gekommen ist (#monitoringsucks etc.), werden die Platzhirsche Nagios/Icinga und ihre Standards auf absehbare Zeit nicht verschwinden. Das Nagios-Plugin-API stellt eine sehr weit verbreitete Schnittstelle zur Anbindung einzelner Checks an Monitoring-Systeme dar. Obwohl das API in den Grundzügen sehr einfach ist, ist der Programmieraufwand für vollständig konforme Plugins erstaunlich hoch.
Die nagiosplugin-Bibliothek nimmt dem Entwickler viele Details ab, so dass er sich auf den Inhalt seiner Checks konzentrieren kann. Der Vortrag führt in das Schreiben von Nagios-kompatiblen Plugins ein, zeigt den typischen Aufbau von Nagios-Plugins und das Grundprinzip eigener Plugins. Die Konfiguration und der Betrieb von Monitoring-Systemen im Großen sollen nicht thematisiert werden.
Video: http://pyvideo.org/video/1460/nagiosplugin-eine-python-bibliothek-fur-monitor
Konferenzseite: https://2012.de.pycon.org/programm/schedule/sessions/45/
Projekt-Homepage: https://projects.gocept.com/projects/nagiosplugin/wiki
Leichtgewichtige Architekturen mit Spring, JPA, Maven und GroovyThorsten Kamann
Gute Software sollte sich an der entsprechenden Fachdomäne orientieren und nicht an der zugrundeliegenden Technologie. Um dies zu erreichen, wird allerdings eine Basis benötigt, die technisch ausgereift ist ohne Einschränkungen für die Entwicklung. Eine solche Basis kann mit dem Springframework geschaffen werden. Die Kombination von Spring, Annotations, Java Persistence (JPA) und Unit-Testing erlaubt eine flexible und modulare Architektur und könnte eine mögliche technische Basis für ein solches Softwaresystem sein.
Dieser Vortrag stellt einen Lösungsansatz anhand eines einfachen Beispiels vor. Die Aufbereitung der Inhalte orientiert sich dabei an einem typischen test-zentrierten Entwicklungsprozess. Folgende Themen werden angesprochen:
* Einleitung Spring und JPA, Maven, Groovy
* Projektstruktur
* Entwicklung der API (der Schnittstellen)
* Test-getriebene Entwicklung der Implementierung
* Spring-unterstützte Integrationstests
Ausblick:
* Spring 2.5 - mehr Annotations; Verwaltung von Entities mit Spring
* Webschicht - Anbindung einer Webanwendung mit Java Server Faces (JSF)
* Spring-Webservices - Contract-First Webservices mit Spring-WS 1.0
3. Agenda
Keine Einführung in Scala
Keine Einführung in Scalaz
("Haskell für Scala")
Motivation
Transaktionen mit Monads
Type classes bzw. Ad-hoc polymorphismus
ev. Arbeiten mit der Datenbank ohne* Seiteneffekte
ev. Dependency Injection
Funktionale APIs gestalten
* Fast ohne
4. Referential transparency
"An expression is said to be referentially transparent if it can be replaced with its value without
changing the behavior of a program." (d.h. keine Seiteneffekte)
def square(i: Int) = i * i
// Bad! Referenziert auch etwas anderes als Parameter
def now() = System.currentTimeMillis()
Keine Reassignment von Variablen
Keine Setter, keine Mutations
Keine Exceptions
Keine Konsolenein-/ausgabe
Keine Netzwerkkommunikation
...
5. Exceptions als Beispiel
def f(): Int = {
val y = g()
try {
y + y
} catch {
case e: Exception => 1337
}
}
def f(): Int = {
try {
g() + g()
} catch {
case e: Exception => 1337
}
}
def g(): Int = { throw new Exception("No!"); }
Checked vs. unchecked exceptions (etwas) irrelevant
Compiler versichert, dass Seiteneffekte behandelt werden
Besser: Sie treten gar nicht erst auf
Viel zu triviales Beispiel, ich weiß!
6. Exceptions als Beispiel (2)
class Cache
(cacheLoader: CacheLoader) {
def get(key: Key): Value = {
// ...
}
}
trait CacheLoader {
def load(key: Key): Value
// throws Exception!
}
class Cache
(cacheLoader: CacheLoader) {
def preload() {
// ...
}
def get(key: Key): Value = {
// ...
}
}
Refactoring mit oder ohne Seiteneffekte?
Exceptions bei preload: Falsch/teilw. initialisierter Cache, fehlendes
Exception-Handling*, etc.?
Exceptions bei get: Mühsam
* z.B: Applikation startet nicht mehr, weil unbenützter Cache Key nicht geladen werden kann, andere Initialisierungen
werden nicht eingeleitet, etc. - Autor von Cache hat keinen Einfluss darauf!
7. Call Stack Abhängigkeit
Es treten immer dann Probleme auf,
wenn wir den Call Stack irgendwie ändern.
Multi-threaded Umgebungen
Web Services
RMI oder sonstiges Remoting
generell jegl. Netzwerkkommunikation
...
8. "Do or do not. There is no scala.util.Try[A]." - Yoda
9. scala.util.Try[A]
import scala.util.{Try, Success, Failure}
def divide: Try[Int] = for {
dividend <- Try(Console.readLine("Dividend:n").toInt)
divisor <- Try(Console.readLine("Divisor:n").toInt)
} yield (dividend / divisor)
val result: Try[Int] = /* .. */
val resultInt = if (result.isSuccess) { result.get } else { 0 }
val resultInt = result.getOrElse(0)
val resultInt: Try[Int] = result.recover {
case e: Exception => 0
}
Nicht einfach nur ein Wrapper um Exceptions
Macht aus einer partiellen Funktion eine totale (d.h. gut!)
10. "... the meaning of RT expressions does not depend on context and may be reasoned about locally, while the
meaning of non-RT expressions is context dependent and requires more global reasoning." (FPiS)
11. Typsystem =
light-weight proof-system
I was eventually persuaded of the need to design programming notations so as to
1. maximise the number of errors which cannot be made,
2. or if made, can be reliably detected at compile time.
- Tony Hoare (ACM Turing Award Lecture)
Typsystem kann viel mehr beweisen als "x has method f"
Compile time = Build time, d.h. Unit Tests sind gut, aber nicht gut
genug
12.
13. Transaktionen - CMT/Annotations/XML
@Transactional
public void updateSomething() { /* ... */ }
@Transactional
public List<SomeType> querySomething() { /* ... */ }
Offene Transaktion? @Transactional/Interceptor vergessen?
Richtige Transaktion? Implizite Beziehung zwischen Transaktion und
EntityManager
Kopplung mit Transaktionsattributen (Propagation, Isolation, etc.), retry?
14. Transaktionen -
BMT/Templates
public void updateSomething(EntityManagerFactory emf) {
transactionTemplate.execute(emf,
new TransactionCallbackWithoutResult() {
protected void doInTransaction(EntityManager em) {
updateOperation1(em);
updateOperation2(em);
}
}
);
}
Wiederverwendung in anderer Transaktion?
Offene/richtige Transaktion? (teilweise ..)
EntityManager (o.ä.) müssen durchgereicht werden
15. Alternative: Transaktions Monad
Monad = Abstraktion zur sequentiellen Ausführung von einzelnen
Schritten in einem bestimmten Kontext (informell)
trait Tx[+A] {
// Um die Transaktion "auszuführen" und den Inhalt zu bekommen
def run(em: EntityManager): A
}
object Tx {
// DSL für Transaktionen (konvertiert Funktion in Tx[A])
def transactional[A](body: EntityManager => A) = new Tx[A] {
override def run(em: EntityManager) = body(em)
}
}
Das ist noch kein Monad, nicht einmal informell.
Ich habe unser Reiseziel nur vorweggenommen.
16. Tx[A]-"Hello World"
def findAllProductIds() /* : Tx[List[Int]] */ = transactional {
em /* : EntityManager */ => // ...
}
def findEmployee(employeeId: String) = transactional {
em => /* ... */
}
So einfach wie mit Annotations - type inference :)
Erstmal vollkommen ohne Abhängigkeiten/Seiteneffekte*
Unmöglich falschen EntityManager zu verwenden**
* Für Skeptiker unter uns: Wie etwas sinnvolles programmieren ohne Seiteneffekte?
** Tony Hoar wäre stolz auf uns!
17. Tx<A> mit Java 8
Tx<A> = Keine Proxies, keine Konfiguration, keine sonstige "Magie",
eigentlich nur ein TransactionCallback<T> mit Lambdas?
@FunctionalInterface
public interface Tx<T> {
public T run(EntityManager em);
// Nicht wirklich hilfreich, Return Type sparen wir uns nicht
public static <T> Tx<T> transactional(
Function<EntityManager, T> body) {
return body::apply;
}
}
public Tx<List<Integer>> findProductIds(String searchCrit) {
return transactional(em -> /* ... */);
}
public Tx<Employee> findEmployee(String employeeId) {
return em -> /* ... */;
}
18. Tx[A] Ausführung
def run[A](emf: EntityManagerFactory, tx: Tx[A]): A = {
val em = emf.createEntityManager
try {
em.getTransaction.begin()
val result = tx.run(em)
em.getTransaction.commit()
result
} finally {
// Rollback (eventuell) und clean-up
}
}
Fazit bisher: Lediglich BMTs aufgesplittet?
Interpretieren des Monads verursacht Seiteneffekte
Andere Form der Abstrahierung - eine Beschreibung, viele
Möglichkeiten diese zu interpretieren
19. Compiler kennt jetzt
Transaktionsklammern
// Oh! Wir haben @Transactional vergessen, sozusagen
def findEmployeeName(employeeId: String) =
findEmployee(employeeId).name // Wäre zwar nicht so schlimm ..
// ERROR:
// value name is not a member of ...Tx[...Employee]
// Wir sind aber auch vergesslich!
def findManagerForEmployee(employeeId: String) =
// Lazy loading kann hier aber schon zu Problemen führen!
findEmployee(employeeId).department.manager
// findEmployee(employeeId).run(em).department.manager
// ERROR:
// value department is not a member of ...Tx[...Employee]
Transaktionskontext benötigt, um Inhalt zu bearbeiten
(bzw. eine EntityManager Referenz ..)
20. Tx[A] Verarbeitung
(noch) unschön
def findManagerForEmployee(employeeId: String) = transactional {
em => findEmployee(employeeId).run(em).department.manager
}
public Tx<Employee> findManagerForEmployee(String employeeId) {
return em ->
findEmployee(employeeId).run(em).getDepartment().getManager();
}
Lesbarkeit eher suboptimal, etwas umständlich
EntityManager sollten wir nicht durchreichen müssen
Gesucht: Funktion mit Signatur Tx[A] => (A => B) => Tx[B]
21. Higher-order function: map
trait Tx[+A] { self => // Statt "Tx.this"
// ..
def map[B](f: A => B) = transactional {
em => f(self.body(em))
}
}
public interface Tx<T> {
// ..
default public <U> Tx<U> map(Function<T, U> f) {
return em -> f.apply(run(em));
}
}
Nicht nur bei Collections nützlich
Strukturerhaltende Verarbeitung von Elementen
22. Verwendung von map() (1)
def findManagerForEmployee(empId: String)/*: Tx[Employee] */ =
findEmployee(empId) map {
employee => employee.department.manager
}
public Tx<Employee> findManagerForEmployee(String empId) {
return findEmployee(empId).map(
employee -> employee.getDepartment().getManager());
}
Keine EntityManager, kein @Transactional - alles wird sozusagen
inferred
Erstmals wirklicher Unterschied zu der BMT Lösung
23. Verwendung von map() (2)
public Tx<Employee> findManagerForEmployee(String empId) {
return findEmployee(empId)
.map(Employee::getDepartment)
.map(Department::getManager);
}
def findDepartmentForEmployee(empId: String) = for {
employee <- findEmployee(empId)
} yield employee.department.manager
For comprehensions lediglich syntactic sugar
24. Verwendung von map (2)
def findProductIds(searchCrit: String) = transactional {
em => /* ... */
}
def findProductNames(productIds: List[Int]) = transactional {
em => /* ... */
}
def findProductNamesFor(searchCrit: String) = for {
productIds <- findProductIds(searchCriteria)
} yield findProductNames(productIds)
// od. einfacher:
def findProductNamesFor(searchCrit: String) =
findProductIds(searchCrit) map findProductNames
Kompiliert zwar, liefert aber Tx[Tx[List[String]
Wir suchen: T[x] => (A => Tx[B]) => Tx[B]
25. Higher-order function: flatMap
trait Tx[+A] { self =>
// ..
def flatMap[B](f: A => Tx[B]) = transactional {
em => f(self.run(em)).run(em)
}
}
public interface Tx<T> {
// ..
default public <U> Tx<U> flatMap(Function<T, Tx<U>> f) {
return em -> f.apply(run(em)).run(em);
}
}
Ergebnis von Tx[A] als Eingabe für Tx[B]
Tx[B] ersetzt sozusagen Tx[A], führt es aber auch aus
Garantiert die selbe Transaktion
Garantiert der selbe EntityManager
26. Vergleich mit Java 7
public Tx<List<String>>> findProductNamesFor(final String crit) {
return new Tx<List<String>>>() {
public List<String> run(EntityManager em) {
List<Integer> productIds =
findProductIds(crit).run(em); // self.run(em)
return findProductNames(productIds).run(em); // f(..).run(em)
}
};
}
Schwer zu lesen, aber nach wie vor nachvollziehbar(?)
Vergleich mit BMT: Suboperationen für sich verwendbar
27. Verwendung von flatMap
def findProductNamesFor(searchCrit: String) =
findProductIds(searchCrit) flatMap {
productIds => findProductNames(productIds)
}
def findProductNamesFor(searchCrit: String) =
findProductIds(searchCrit) flatMap findProductNames
def findProductNamesFor(searchCrit: String) = for {
productIds <- findProductIds(searchCrit)
productNames <- findProductNames(productIds)
} yield productNames
Zwei Datenbankqueries in der selben Transaktion
Wiederum weder EntityManager noch @Transactional (o.ä.) - Kontext
(hier Tx) wird wiederverwendet
28. Monad Definition für Scalaz
implicit val txMonad = new scalaz.Monad[Tx] {
def point[A](a: => A): Tx[A] = transactional {
// EntityManger wird nicht benötigt, kann ignoriert werden.
_ => a
}
def bind[A, B](fa: Tx[A])(f: A => Tx[B]): Tx[B] =
fa flatMap f
}
Essenz: Wir hatten die Implementierung praktisch schon
Gibt Zugriff zu nützlichen Monadic Functions
Monad Laws beweisen sparen wir uns momentan ..
29. Monadic Functions (1)
// Um die Signatur zu verdeutlichen:
def sequenceM[M[_] : Monad, T](ms: List[M[T]]): M[List[T]] =
ms.sequence
def zipM[M[_] : Monad, T, U](mt: M[T], mu: M[U]): M[(T, U)] = for {
t <- mt
u <- mu
} yield (t, u)
// In Bezug auf Transaktionen bedeutet das:
def joinTransactions[T](transactions: List[Tx[T]]): Tx[List[T]] =
sequenceM(transactions)
def joinTransactions[T, U](txT: Tx[T], txU: Tx[U]): Tx[(T, U)] =
zipM(txT, txU)
Kontext gibt dabei die jeweilige Semantik an
36. Fazit
Ziel einer jeden API: LEGO(tm) Baukasten
Seiteneffekte kann man sehr gut einschränken
Deferred Execution / Interpretation, wenn man Seiteneffekte benötigt
Der (Scala!) Compiler ist dein Freund!