Podcast

Play!

Das Full Stack Web-Framework auf der JVM

In seinem zweiten innoQ Podcast spricht Tobias Neef mit Stefan Tilkov über das Web-Framework Play. Tobias stellt die wesentlichen Features des Frameworks vor und beschreibt deren Einsatz. Er diskutiert den alternativen Einsatz von Play mit Java oder Scala und geht auf die Hauptunterschiede zwischen Play 1 und 2 ein.
Weitere Episoden anhören

Shownotes & Links

Transkript

Transkript ausklappen / einklappen

Stefan Tilkov: Hallo und herzlich Willkommen zu einer neuen Episode unseres innoQ-Podcasts. Heute mit Tobias Neef zum Thema Play. Tobias, du warst schon einmal bei uns in der Show, aber ich bitte dich trotzdem, dich einfach nochmal ganz kurz vorzustellen.

Tobias Neef: Ja, hallo Stefan. Wie gesagt, meine Name ist Tobias Neef, ich arbeite hier bei innoQ als Entwickler und Berater und bin momentan viel im Bereich der Scala- und Play-Entwicklung in Projekten unterwegs und mache in dem Bereich auch Schulungen.

Stefan Tilkov: Ok und wir reden heute über Play. Die letzte Episode mit dir war zum Thema Scala. Heute wollen wir über das Play-Framework sprechen. Gibt doch mal so einen ganz kurzen Überblick, was Play denn überhaupt ist.

Tobias Neef: Also, Play ist ein Framework, was auf die JVM zugerichtet ist. Auf die JVM zugerichtet heißt, verschiedene Sprachen auf der JVM sollen vom Play-Framework unterstützt werden. Momentan ist es so, dass Scala und Java vom Play-Framework nativ unterstützt werden. Das ganze funktioniert so, dass das Play an sich hauptsächlich in Scala geschrieben ist, aber eine dedizierte Java-API bereit gestellt wird, für Entwickler, die eher mit Java entwickeln wollen. Und bei Play handelt es sich um ein Full-Stack-Framework, also das Framework nimmt einem schon gewisse Entscheidungen ab, was die Wahl gewisser Technologien oder Ansätzen angeht. Und damit muss man sich eben zurecht finden oder nicht.

Stefan Tilkov: Was meinst du damit, was für Entscheidungen nimmt es einem ab?

Tobias Neef: Naja, also es wird einem z.B. gesagt, dass eine bestimmte JSON-Library mit in das Framework kommt oder es wird einem gesagt, dass man eine gewisse Auswahl von Persistenz-Mechanismen hat oder einen mitgelieferten Mechanismus, wie man mit Web-Services kommuniziert. Das sind alles Dinge, die das Framework schon standardmäßig mit liefert und sagt “Ja, das ist ein gutes Paket, das ist stark miteinander integriert, das passt alles irgendwie zusammen.” Und wenn sich das mit den eigenen Vorstellungen deckt, dann ist Play eine gute Wahl, sonst vielleicht eher nicht.

Stefan Tilkov: Lass uns vielleicht zwei Dinge aus dem Weg kriegen. Das erste ist “Play1 vs. Play2”. Da gibt es so eine gewisse Debatte, es ist ein großer Unterschied. Vielleicht kannst du uns da ein bisschen Hintergrundinformationen geben.

Tobias Neef: Ja. Also Play1 ist aus dem Kontext entstanden, dass die Entwickler hinter Play ganz normal Java-Entwicklung im Web-Bereich gemacht haben. Und damit waren sie nicht so ganz zufrieden, wie das damals gelaufen ist, weil man hatte die klassischen J2EE- und Spring-Frameworks zur Verfügung. Und das ganze unterscheidet sich halt vom Entwicklungsworkflow deutlich von Dingen wie Ruby on Rails, die halt sehr entwicklergetrieben sind, von der Art, wie man mit diesen Frameworks interagiert. Und deswegen wurde Play1 entworfen, um erstmal ein bisschen in die Richtung “Ruby on Rails” in der Java-Welt zu gehen. Davon hat man sehr viel Inspiration genommen.

Stefan Tilkov: Play1 ist auch komplett in Java entwickelt gewesen.

Tobias Neef: Genau, Play1 ist auch komplett in Java entwickelt gewesen, damit ist das ganze entstanden. Nun ist man nach eineinhalb Jahren zu dem Entschluss gekommen, dass man mit der Architektur von Play1 nicht so ganz weiter kommt, vor allem wenn wir mit neuen Herausforderungen umgehen müssen, wie Skalierung von Services, Verteilung von Services. Und aber auch mit dem bestehenden Technologie-Stack, da war man nicht so ganz glücklich. Und deswegen hat man dann gesagt, nimmt man da nochmal einen neuen Architekturansatz, nimmt die ganze Erfahrung, die man aus Play1 genommen hat, bricht auch im Kern nicht mit den Prinzipien, die man da hatte, was die Entwicklerproduktivität angeht und entwickelt halt Play2.

Stefan Tilkov: Und interessant ist vielleicht, dass es durchaus Leute gibt, die nicht so ganz glücklich damit sind, wie sich Play2 entwickelt hat. Insbesondere nicht ganz glücklich damit sind, dass Play2 eben eine komplette Neuentwicklung in Scala ist, weil das schon ein Bruch ist. Also es gibt durchaus eine Front, eine Fraktion – auch bei uns übrigens –, die Play1 ganz prima findet und eigentlich sehr traurig ist, dass es nicht weiter entwickelt, sondern durch was ganz anderes ersetzt wurde.

Tobias Neef: Genau. Also ich denke, da gibt es zwei Aspekte zu. Also zum einen hat man natürlich den typischen “Ich finde das gut, was ich kenne”-Aspekt. Das hat man bei jeder Major-Version von Ruby, gefühlt. So hat man das aber auch in…

Stefan Tilkov: Rails vor allem. Weniger Ruby, mehr Rails.

Tobias Neef: Natürlich, in Rails. Das ist das eigentlich auch, was ich auch sagen wollte. Das kann man natürlich nicht synonym verwenden.

Stefan Tilkov: Ist natürlich das gleiche, Ruby und Rails, genau.

Tobias Neef: Das hat man in anderen Welten auch und so ist das eben auch hier. Die gewissen Benutzungs-Patterns/-Muster haben sich geändert und deswegen mag man es vielleicht nicht. Die andere Sache ist, wie du schon erwähnt hast, Play2 ist im Kern in Scala geschrieben. Deswegen kann es halt durchaus mal sein, dass man bei Stack-Traces halt eben Scala-Meldungen bekommt und sich etwas damit auseinander setzen muss. Aber wie bei anderen Frameworks auch, ist es eigentlich selten, dass ich in die Stack-Traces des Frameworks all zu tief rein debugge und von daher hat sich für mich, der jetzt beide Seiten kennt – sowohl Play-Java als auch Play-Scala aus Projekten – hat sich bei mir noch nie die Problematik irgendwie so raus gestellt.

Stefan Tilkov: Es ist vielleicht auch interessant zu sagen, wir haben tatsächlich alle drei Varianten, also Play1-Java, Play2-Java… Jetzt für den Rest heute reden wir nur über Play2, aber den Unterscheid Scala-Java machen wir nicht so großartig. Ich glaube der Rest, über den wir sprechen, hat nicht so wahnsinnig viel damit zu tun oder ist nicht so stark davon abhängig.

Tobias Neef: Genau, ganz richtig. Also es gibt ein paar Bereiche des Frameworks, wo Unterscheidungen gemacht werden zwischen Play-Java und Play-Scala, die jetzt über die API-Ebene hinaus gehen, weil man einfach sagt, die ideomatische Nutzung innerhalb dieser Programmiersprache ist an den Stellen etwas anders. Deswegen treffen wir da andere Entscheidungen für den Benutzer. Aber so explizit, wenn man auf einer Übersichtsebene über das Framework redet, muss man da eigentlich keine Unterscheidung machen.

Stefan Tilkov: Ok. Dann lass uns doch mal eine Stufe tiefer einsteigen und darüber sprechen, aus welchen Teilen Play denn besteht und wodurch sich das auszeichnet. Kannst du einfach mal einen kleinen tieferen Überblick geben?

Tobias Neef: Genau. Also das erste, mit was man zu tun hat, wenn man sich mit einem Web-Framework auseinander setzt, ist ja ganz oft: Wie geht man mit HTTP um? Weil ich meine, das macht ein Web-Framework aus, man redet irgendwie über HTTP und jetzt ist die Frage, was für ein Modell man anbietet, um mit HTTP umzugehen. Und eine Möglichkeit ist es jetzt, irgendwie ein Abstraktionsmodell über HTTP zu legen, wo ein gewisser Zustand abstrahiert wird. Das kennt man ganz oft in der Java-Welt, dass man einen gewissen Session-State hat, daran Informationen des User packt und damit auch arbeitet. In Play ist es so, dass man zustandslos arbeitet und entsprechend auch kein großes Abstraktionsmodell über HTTP hinaus anbietet. Also im Kern definiert man in Play Funktionen, die einen Request entgegen nehmen und eine Response erstellen und auf der Ebene arbeitet man auch ganz explizit mit den Mechanismen, die HTTP bereit stellt.

Stefan Tilkov: Das ist also ganz interessant, der Java-Code, den ich gesehen habe, hat ein Charakteristikum, dass die Methoden alle in Controllern angesiedelt sind, aber alles statisch ist. Was einem am Anfang erstmal etwas verblüfft, warum man sowas macht.

Tobias Neef: Ja genau. Aber wenn man natürlich HTTP kennt und weiß, dass es natürlich im Kern statuslos ist, ist das eigentlich nur eine konsequente Abbildung. Ich denke mal, man spielt dann auch so ein bisschen mit dem psychologischen Effekt, dass man gleich ein schlechtes Gefühl hat, wenn man in Klassen, die nur statische Methoden haben, irgendwelche Zustandsvariablen rein packt. Da kriegt man gleich ein schlechtes Gefühl und das ist vielleicht so nicht gegeben, wenn man da mit Singletons gearbeitet hätte, in der Java-Welt.

Stefan Tilkov: Was ist noch drin im Framework? Was gehört noch dazu neben dieser HTTP-Integration oder -Abstraktion?

Tobias Neef: Genau. Also neben der HTTP-Abstraktion wurde hier sehr viel Wert gelegt auf die Integration der Frontend-Entwicklung in Anführungszeichen. Also in Java-Projekten – klassischerweise – gibt es einen Ordner, ganz tief in der Baumstruktur, wo die ganzen Javaskript-Dateien, CSS-Dateien, Bilder etc. drin versteckt sind. Nun wird diese Rolle des “Irgendwo im Dateisystem versteckten” nicht ganz dem Gewicht von Frontend-Code in heutigen Projekten gerecht, denn sowohl CSS als auch Javascript sind wichtige Elemente in einer Entwicklung, wenn man eine anspruchsvolle Webanwendung entwickelt. Und deswegen ist da das Ziel, dass man den Entwicklungsprozess hier auch integriert in den Gesamtworkflow. Auch also, wenn man z.B. an einer Javascript-Datei editiert und man hat einen syntaktischen Fehler in der Javascript-Datei, bekommt man eine zugehörige Fehlermeldung im Browser. Man kann sogar noch weiter gehen und kann sagen, ich setze als Präprozessor für die Javascipt-Verarbeitung sowas wie Coffeescript ein, würde dann hier auch Syntaxfehler bekommen für das Javascript. Zudem werden auch CSS-Präprozessoren wie Less oder Sass integriert und auch hier hat man eine integrierte Fehlermeldung im Browser, die sich auch über das ganze Framework erstreckt. Also das ist so ein Crosscutting-Feature über alle Komponenten. Der Versuch, das man Fehlermeldungen nicht in proprietären Formaten der einzelnen Technologien bekommt, sondern, dass man sie unifiziert in einer einheitlichen Oberfläche innerhalb des Browsers bekommt. Jedenfalls im Entwicklungsmodus.

Stefan Tilkov: Das klingt so, als würde man den Browser bei der Entwicklung quasi ständig benutzen, als Teil der IDE sozusagen.

Tobias Neef: Genau. Also man muss sich das so vorstellen: man schreibt das Stück Code und das ganze wird dann neu kompiliert, wenn man F5 im Browser drückt. Dann wird geschaut, was die Abhängigkeiten sind, die sich geändert haben. Das zu Grunde liegende Build-System löst das auf, rekompiliert das, tut die Präprozessoren wie Less neu laufen lassen und anschließend sieht man das Ergebnis im Browser oder man bekommt eben eine Fehlermeldung, wenn irgendwas falsch gelaufen ist.

Stefan Tilkov: Heißt das, dass du gar nicht mit einer IDE arbeitest, wenn du Play benutzt und immer nur mit einem Texteditor Textdateien editierst und vom Browser den Compile-Prozess anstoßen lässt?

Tobias Neef: Ja. Das könnte man durchaus tun. Meine persönliche Präferenz ist es nicht. Hier kann einem eine IDE durchaus helfen. Ich persönlich verwende IntelliJ für den Zweck. Aber es ist jetzt nicht zwingend erforderlich, weil das schöne an Play ist, dass diese ganze Funktionalität, dieser Framework-spezifische Funktionalität nicht ausgelagert ist, in irgendwelche Generatoren, die in der IDE versteckt sind, wie man es ganz oft irgendwie in der Java-Welt sieht, sondern alle Funktionalität, was so Code-Generierung und solche Dinge angeht, sind Teil des Build-Prozesses und damit Teil des Build-Tools. Also solange man das Build-Tool über die Konsole bedienen kann, hat man da erstmal alle Funktionalitäten, die man braucht. Alles darüber hinaus ist convenience.

Stefan Tilkov: Also, was haben wir an Features? Wir haben gesagt die HTTP-Integration. Du hast schon erwähnt: Präprozessoren und ähnliches. Man hat so ähnlich wie bei Rails so eine Asset-Pipeline, so einen Mechanismus.

Tobias Neef: Genau.

Stefan Tilkov: Eine Folge zu Präprozessoren haben wir auch schon gemacht, die ein wenig erklärt, wofür man sowas braucht. Wie sieht es mit Templating aus? Wie werden View-Templates, wenn die da so heißen, realisiert in Play?

Tobias Neef: Ja, ja. Das ist so, dass egal ob man Play mit Java oder Play mit Scala entwickelt, grundsätzlich die Zielstellung hat, dass für Templates, Root-Files und des restlichen Programmcode die statische Typisierung von Scala oder eben Java genutzt wird. Deswegen sind die View-Templates, wie du sie jetzt nennst, sind ganz normale…

Stefan Tilkov: Heißen die da anders?

Tobias Neef: Ja, also Templates, einfach.

Stefan Tilkov: Templates, ok.

Tobias Neef: Die Templates sind da ganz normale Scala-Funktionen. Und das ist ganz angenehm, weil ein Template einfach so definiert ist, dass es eine ganz normale Funktion ist mit Parametern, die am Ende Text raus rendert. Also das, was man erwarten würde. Was ganz angenehm ist, wenn man das Template-Rendering Unit-Testen will. Man brauchst dazu keinen großen Kontext, sondern man ruft einfach diese Funktion raus, bekommt einen Content und kann entsprechend checken, ob das drin ist, was man erwarten würde.

Stefan Tilkov: Und wie schreibt man darin dann sowas wie HTML? Man schreibt dann offensichtlich nicht textuell HTML mit escaped Sequenzen, die Code aufrufen, sondern man nutzt eine DSL oder wie sieht das dann aus?

Tobias Neef: Doch, im Grunde genommen sieht es genau so aus. Also man hat…

Stefan Tilkov: Also das, was heraus kommt… Also dieses Template selber ist von der Syntax her kein Scala-Code, sondern benutzt Scala-Fragmente innen drin.

Tobias Neef: Nee, es ist Scala-Code, was hervor gehoben ist, durch ein @ vor den Scala-Sprachelementen. Das funktioniert deswegen ganz gut, weil – in der Scala-Episode hatten wir das schon mal erwähnt – in Scala jede Expression einen Wert zurück gibt. Und dementsprechend ist dann halt der Wert der einzelnen Expressions – wie z.B. if-then-else-Statements – ist halt eben ein Text-HTML-Fragment, was verwendet wird.

Stefan Tilkov: Ich glaube du hast mich nur irritiert. Du hast gesagt, dass das Template eine Funktion ist. Das Template, das man hinschreibt sieht aber schon so aus, wie z.B. HTML und da wo man dynamische Elemente haben will, schreibt man Scala-Code hin.

Tobias Neef: Ganz genau, ja.

Stefan Tilkov: Ok und insgesamt wird das ganze dann sozusagen als Funktion aufgerufen. Also ich könnte das nicht in meiner IDE als Scala-Code öffnen, es ist also keine Scala-basierte interne DSL oder so.

Tobias Neef: Ja.

Stefan Tilkov: Alles klar. Gut, dann habe ich es verstanden.

Tobias Neef: Genau.

Stefan Tilkov: Danke. Gut, dann haben wir Templates, HTTP. Wie sieht es in Richtung Backend aus, was bringt Play da mit?

Tobias Neef: Also da gibt es, würde ich sagen, drei interessante Bereiche. Die Kern-Abstraktion im Backend, auf die Play aufbaut, ist das sogenannte Akka-Framework. Akka ist eine Event-basierte Middleware, die quasi das aus Erlang bekannte Aktor-Modell in die JVM-Welt transportiert. Und das kann als Mechanismus verwendet werden, um nebenläufige Prozesse innerhalb der Anwendung zu beschreiben und zu modellieren und ist auch das Primitive, das man einsetzt, um die Verteilung innerhalb der Anwendung zu erreichen. Also zumindestens verbreitet, wird dafür gerne Aktor genommen, um dann zwischen Systemen Nachrichten zu versenden und so mehrere Play-Systeme miteinander zu verbinden.

Stefan Tilkov: Benutzt Play Akka auch intern für die Realisierung der Basisfunktionalität oder ist Akka nur eine optionale Komponente?

Tobias Neef: Nein, also Akka ist absolut Teil des Frameworks, also innerhalb des Standard-HTTP-Processing wird Play verwendet.

Stefan Tilkov: Akka verwendet.

Tobias Neef: Äh, richtig. Wird Akka verwendet, um die bereit zu stellen. Aber auch wenn man eigene Funktionalität hinzufügen will, gerade wenn sie in Richtung Fehlerresistenz geht oder Verteilung des Systems, kann hier Akka eingesetzt werden.

Der zweite Aspekt, der interessant ist und auch gut dazu passt, ist der Bereich “Aufrufe von Webservices”. Aufrufe von Webservices ist ein Thema, was heute normal ist – also wenn man einen User-Request hat, werden ganz oft externe Informationen eingeblendet, die von anderen externen Servern kommen, die entweder irgendwie intern bereit stehen, eine interne API oder eben externe Services, die dann irgendwie das News-Feed oder einen Nachrichten-Ticker mit in die Seite integrieren. Das Problem an dem ganzen ist, dass oft mehrere Quellen gleichzeitig aufgerufen werden, pro Benutzer-Request und man deswegen – um das ganze noch performant bereit zu stellen – hier das ganze gern parallel ausführt. Nun, wenn man das ganze jetzt aber parallel ausführt, hat man wieder das Problem, wie kriegt man diese unabhängig voneinander laufenden, parallel Aufrufe wieder zusammen, weil man sie möglicherweise verbinden will oder weil man sie in die View rein rendern will. Es gibt Abhängigkeiten zwischen diesesn verschiedenen Strängen und deswegen bietet Play ein Programmiermodell, wie mit solchen asynchronen Aufrufen umgegangen werden kann. Und das wird halt bereit gestellt über die Future-API, die Teil von Scala im Kern ist, aber auch im speziellen Teil der Webservice-Abstraktion von Play.

Stefan Tilkov: D.h. Webservices hier im allgemeinen Sinne gemeint. Irgendwas externen, was man aufruft. Muss kein SOAP-WSDL-Webservice sein, kann auch ein RESTful-HTTP-Service, irgendwas sein, was man aufruft.

Tobias Neef: Genau, also Webservice ist eigentlich in dem Sinne streng genommen HTTP. SOAP wird so nicht im Kern des Frameworks unterstützt. Da müsste man dann externe Librarys nutzen. Aber die Kernfunktionalität ist eher halt HTTP-basiert.

Stefan Tilkov: Wenn ich jetzt mehrere Systeme parallel anfrage, also ich hole mir – keine Ahnung – mehrere Daten, die ich integrieren möchte in meine Seite von drei verschiedenen Quellen. Kann ich dann diese Ergebnisse auch schon verarbeiten, wenn sie nur zum Teil vorliegen? Habe ich da einen Streaming-Support, wenn ich mit diesem Programmiermodell arbeite?

Tobias Neef: Genau, also der Streaming-Support ist ein wichtiger Teil des Play-Frameworks, gerade wenn man in Richtung High-Performance-Anwendungen gehen will oder wenn man Anwendungen hat, wo gerade sehr viele Message-Streams gleichzeitig laufen, die aggregiert werden müssen, zum User transportiert werden müssen. Da gibt es heute viele Technologien, die sage ich mal in diesem Kontext relevant sind. Gerade auch die Kommunikation gegenüber vom Benutzer gibt es Technologie, wie Messaging quasi zum Browser hin oder Web-Sockets als Technologie oder Comet. Das sind alles Möglichkeiten, wie man Informationen zum User pusht. Das Problem ist, dass in den wenigsten Web-Frameworks in der Javawelt hier ein wirkliches Programmiermodell bereit gestellt wird. Und wenn man in Play diese Anforderung hat, hat man ein Programmiermodell, wie man diese unterschiedlichen Browser-APIs in seiner Anwendung unterstützen kann, wie man auf Streams reaktiv Logik hinterlässt und das ist eine sehr nette Sache, falls man in seiner Anwendungsentwicklung solche Anforderungen hat.

Stefan Tilkov: Das klingt jetzt so, als wolltest du es ein bisschen einschränken. Also würdest du extra sagen, falls man solche Dinge hat. Also du siehst das nicht als zentralen Punkt des Frameworks.

Tobias Neef: Klar wird Play nach außen hin so vermarkt, das reaktive Framework und dieses ganze Stream-Processing sehr stark in den Fokus gehoben. Das ist sicherlich auch ein absolutes Alleinstellungsmerkmal, mit dem man ganz coole Dinge tun kann. Man muss aber dazu sagen, dass in einem Projekt, auch wenn es sehr viele Benutzer hat, meistens nur kleine Teile der Anwendung diese Funktionalität benötigen, wenn überhaupt. Und deswegen ist eigentlich der entscheidene Teil, wie man mit ganz normalen HTTP-Abfragen umgeht. Wie kann man diesen Workflow gut gestalten, mehr als jetzt das Stream-Processing, was eher in Nischen-Themen wirklich Relevanz hat.

Stefan Tilkov: Ok. Was wäre der dritte Punkt? Drei Dringe wolltest du aufzählen.

Tobias Neef: Der dritte Punkt von …?

Stefan Tilkov: Du hast gerade gesagt, du wolltest drei Dinge in Richtung Backend hervorheben.

Tobias Neef: Ahja, danke. Danke für den Hinweis.

Stefan Tilkov: Kein Problem.

Tobias Neef: Ja der dritte Punkt klassischerweise natülich die Datenbank. Und hier ist es so, dass standardmäßig auch mit SQL-Backends umgegangen wird, weil es auch natürlich immernoch der verbreitetste Datenbank-Typ ist. Und hier unterscheidet man zwischen Java-Play und Scala-Play. Hier werden unterschiedliche Mechanismen eben angeboten. Also Java ist eher so ein bisschen traditioneller, in Richtung JPA. Auch wenn der Provider, der da genutzt wird, nicht wirklich JPA-Compliant ist. Der Provider hier heißt Edorm und das zentrale Unterscheidungskriterium ist eben, es gibt kein Entity-Manager und damit auch eigentlich keine wirkliche Magie innerhalb der JPA-Nutzung. Also es werden nicht automatisch Dinge geupdatet. Es werden nicht automatisch Dinge synchronisiert. Es gibt keinen First-Level und Second-Level-Cache auf Ebene des Entity-Managers, sondern es ist alles mehr oder minder per Hand. Was einem die ein oder andere Überraschung erspart, wenn man Dinge wie Hibernate gewohnt ist. Wenn man natürlich Dinge wie Hibernate gut versteht und damit Leben kann, mit der ganzen Magie, dann ist es natürlich auch nicht verkeht, das Hibernate einzusetzen. Deswegen wird der auch in neueren Versionen JPS-nativ unterstützt.

In der Scala-Welt hat man sich gesagt, die ganzen Hibernate-JPA Sachen sind nicht ganz ideomatisch, für wie man Scala entwickelt. Weil wenn man sieht, was nutzt man, wenn man sowas wie JPA hat, dann hat man meistens JavaBeans, also mit Getter und Setter und das ist alles nicht so wirklich ideomatisch mit dem, wie man Scala baut. Hier versucht man ja eher seine Objekte unveränderlich zu lassen und dementsprechend brauch man auch passende Frameworks, die diese Unveränderlichkeit auch irgendwie darstellen können. Und hier ist man zu einem interessanten Framework gekommen, was sich Slick nennt. Mit Slick beschreibt man über Transformationsfunktionen, die man schon aus der Scala-Collection kennt, wie flat, map, map-filter, group-by, beschreibt man sein Statement, was man von der Datenbank haben will und das wird intern umgewandelt in ein SQL-Statement, was dann gegenüber der Datenbank ausgeführt werden kann. Also es ist im Grunde genommen schon alles, man ruft es auf, bekommt das zurück, hat einen schönen Präprozessor – sage ich mal –, der einem SQL generiert und das ist ein ganz angenehmer Mechanismus mit einer relationalen Datenbank umzugehen.

Stefan Tilkov: Erinnert an die .NET-Welt und an Link.

Tobias Neef: Genau, von der Architektur, von dem Ansatz, von der API ist das ganze sehr ähnlich zu Link2SQL aus der .NET-Welt.

Stefan Tilkov: Übrigens interessant, also ich finde diese Querbeziehungen immer interessant. Also Link stammt hauptsächlich von Erik Meijer, der einer der Haskell-Väter oder Haskell-Standardisierer ist und Haskell ist wiederum einer der Haupteinflüsse von Scala und diese Communities hängen alle irgendwie zusammen.

Tobias Neef: Zudem auch spannend darüber, der Vater von Scala, Martin Odersky, und der eben angesprochene Erik Meijer halten auch demnächst über Coursera eine gemeinsame Vorlesung zu dem Thema “Reactive Programming”. Also das sind sicherlich zwei Welten, die sich auch sehr stark voneinander inspirieren, ja.

Stefan Tilkov: Zu Reactive Programming machen wir sicherlich noch mal eine separate Episode. Ok, also wir haben einen Full-Stack-Framework mit diesen Facetten drin. Du hast schon ein bisschen über die Entwicklungsumgebung gesprochen. Wie sieht es mit der Laufzeitumgebung aus? Also was ist das Modell? Ich denke, das ist ganz interessant, weil es mit ein paar Dingen bricht, die man so gewohnt ist.

Tobias Neef: Ja, genau. Also in der Java-Welt ist man ja gewohnt, man hat seinen Servlet-Container und in seinen Servlet-Container werden war-Files rein deployt und die war-Files packen im Grunde genommen alle Java-Klassen und alle Assets, die man so in seinem Programm hat. In Play ist es ein bisschen anders, hier bricht man mit dieser Konvention aus mehreren Gründen. Man sagt sich zum einen, diese Servlet-API ist schon ziemlich alt und sie gibt einem auch wenige Einflussmöglichkeiten an zentralen Dingen, wo wir gerne Einfluss hätten. Also gerade, wenn wir sowas wie Stream-Processing realisieren wollen, ist es sehr schwierig das über die Servlet-API zu tun. Also Servlet 3.0 und 3.1 haben zwar hier Erweiterungen, wie man asynchron mit Ergebnissen umgehen kann, aber das ist trotzdem noch alles sehr schwerfällig und man sieht auch, dass es ich sag mal ein gewachsenes Thema ist. Deswegen hat man hier gesagt, man will natürlich nicht ganz von neu anfangen, deswegen verwendet man einen IO-Container, der sich Netty nennt. Basierend auf Netty baut man eben dieses Framework und tut das sehr stark mit Netty verknüpfen und eigentlich alle Low-Level-IO, Async-IO Anfragen werden auf das API-Layer von Play gemappt.

Stefan Tilkov: Und im Deployment bedeutet das dann was?

Tobias Neef: Im Deployment bedeutet das eigentlich, dass es die Wahl des Entwicklers ist, wie man Deployment betreibt. Also es gibt nicht den Standardweg, sondern man kann da verschiedene Stufen der Deployment-Komplexität wählen. Also der erste Einsatz, man macht es sehr minimalistisch, wie es auch oft in der Rails-Welt betrieben wird, dass man sagt, man hat ein Source-Code-Repository, z.B. ein Git-Repository, und wenn man ein Update eines Servers durchführen will, pusht man die Änderung zu diesem Source-Repository und anschließend in einem Post-Commit-Hook tut man den Service neu starten. Die zweite Möglichkeit, wenn man wirklich ein Artefakt haben will, was quasi das Release kennzeichnet, was deployt werden soll, hier hat man auch zwei Möglichkeiten. Der Weg, der am nähesten zu den Play-Konventionen ist, ist, dass man sagt, man baut aus diesem Projekt-File ein natives Package des Betriebssystems. Das würde dann irgendwie ein msi im Fall von Windows sein oder ein Debian-Package z.B. im Fall von Debian als Linux-System. Und hier gibt es auch schon entsprechenden Support des Build-System, das eben zu tun. Die dritte Möglichkeit, wenn man schon ein besettletes Operation-Team hat, was sagt, “Ok, unsere Voraussetzung ist, dass wir ein war-File bekommen.” Hier gibt es ein externes Projekt, was ein war-Mapping für Play-Projekte bereit stellt. Das wird auch produktiv von denen genutzt. Da wird halt gesagt “Ok, wenn ihr ein Servlet 3 oder besser noch 3.1 Container habt, dann habt ihr die meiste Funktionalität, die euch Play eben bereit stellt.” Es gibt keine Einschränkungen im Stream-Processing. Aber auch hier eben wieder 95% der Funktionalität wird unterstützt. Wenn man nur einen Servlet 2.x kompatiblen Container hat, da kommen halt einige Features, ja die können halt nicht unterstützt werden, weil es entsprechend keine Funktionalität für asynchrone Verarbeitung gibt.

Stefan Tilkov: Und, taugt das Zeug? Ist das ein gutes Framework? Hast du Spaß damit zu entwickeln?

Tobias Neef: Ja, definitiv. Man kann auf der einen Seite sagen, als Java- Entwickler ist man nicht gerade verwöhnt, was Web-Frameworks angeht. Aber das ist wirklich eine schöne Sache, gerade in Teams, wo auch wirklich die unterschiedlichen Bereiche der Softwareentwicklung zusammen kommen oder der Webentwicklung. Also wo Leute Frontend Code entwickeln, wo Leute eher Datenbank-nahen Code entwickelt, Business-Logik, worin man das heutzutage alles einteilt. Alle finden sich ganz gut zurecht innerhalb von Play, aber alle nutzen eine gemeinsame Umgebung und das führt auch dazu, dass man auch Architekturen haben kann, wo man nicht künstlich die Anwendung in irgendwelche Layer trennt, die eigentlich aus technischer Sicht gar nicht von Nöten sind und das macht es wirklich sehr angenehm innerhalb dieses einen Projekts zu entwickeln.

Stefan Tilkov: Ich kann noch sagen, dass interessanterweise bei uns Play auch den Rails-Kollegen immer Respekt abringt. Also nicht, dass die das jetzt total bewundern, aber man hat da eine andere Einstellung. Das ist ganz gut im Gegensatz zu anderen Clones, die versucht haben Rails nachzumachen, hat das durchaus eine eigene Identität und eigene Qualität.

Tobias Neef: Ja.

Stefan Tilkov: Gut, wenn man starten möchte mit Play, was empfiehlst du? Wie legt man am besten los? Welche Ressourcen würdest du einem interessierten Hörer, einer interessierten Hörerin am ehesten nahe legen?

Tobias Neef: Ja. Also hier hat man auch, ähnlich wie bei Scala, die Möglichkeit über den Typesafe-Activator einen Einstieg zu finden. Das ist im Grunde genommen ein Tool, das man als zip-Datei runterlädt, entpackt, durch einen Doppelklick startet und es poppt etwas im Browser auf und dann kann man innerhalb des Browsers ein Play-Template auswählen. Und damit kann man halt ganz einfach über eine Browser-basierte IDE mit Play interagieren. Aber auch so, wenn man ein Play-Projekt runterlädt – das ist auch wieder eine zip-Datei, welche man entpackt und startet –, ist es im Grunde genommen eine sehr einfache Geschichte. Denn man kann sich z.B. so ein Demo-Projekt, was Teil der Play-Distribution ist, an die Hand nehmen und starten und einfach mal live den Code modifizieren, nochmal F5 drücken und sehen, was eben die Änderungen sind, am Code. Und nach einigen Sekunden ist das ganze wieder kompiliert und der Refresh ist direkt sichtbar, das Feedback ist auch wirklich sehr schnell, was wirklich einer der größten Vorteile ist, dieser schnelle Feedback-Zyklus von Play.

Stefan Tilkov: Alles klar. Gut, Tobias. Vielen Dank für die spannenden Folge und bis zum nächsten Mal.

Tobias Neef: Ja danke Stefan. Bis zum nächsten Mal. Ciao.

In Memoriam ∞ CEO & Principal Consultant

Stefan Tilkov war Geschäftsführer und Principal Consultant bei INNOQ Deutschland, wo er sich vorwiegend mit der strategischen Beratung von Kunden im Umfeld von Softwarearchitekturen beschäftigte. Er war Autor des Buchs “REST und HTTP”, Mitherausgeber von “SOA-Expertenwissen” (beide dpunkt.verlag), Autor zahlreicher Fachartikel und häufiger Sprecher auf internationalen Konferenzen.

Wir trauern um Stefan.

Alumnus

Tobias Neef war bis Dezember 2020 als Entwickler und Senior Consultant bei INNOQ tätig. Sein Fokus liegt in der Konzeption und Implementierung von verteilten Software-Systemen. Aktuell beschäftigt er sich damit funktionale und reaktive Technologien wie Scala, Play und Akka bei Web-Dienstleistern und Großunternehmen zu verbreiten.