Scala, Ruby, Perl,… – wann nimmt man was?

Wer einen goldenen Hammer hat, für den sieht jede Schraube wie in Nagel aus. Aber wir haben einen riesigen Werkzeugkasten und wie man sieht, überschneiden sich tatsächlich manche Werkzeuge in ihren Einsatzbereichen, aber das Universalwerkzeug ist nicht wirklich in Sicht oder doch nicht wirklich in allen Bereichen mit den Spezialwerkzeugen konkurrenzfähig.

Oft hat man ja Altlasten, also vorhandene Applikationen, die man erweitern oder ergänzen soll oder es sollen sogar neue, „in die Landschaft passende“ Applikationen hinzugefügt werden. Dann landet man bei Cobol, Railo, Fortran, C, Java, C#, C++, PL/SQL, PL/1, (Visual)Basic u.s.w. Wobei diese zum Teil sogar ihre sehr große „Nische“ haben, in der sie noch aktuell sind. Dass C für Systemprogrammierung noch sehr aktuell und fast konkurrenzlos ist, sei unbenommen.

Wenn keine Vorgaben durch Bibliotheken, Altlasten, IT-Landschaft u.s.w. bestehen, ist es natürlich interessant, in der zur Verfügung stehenden Zeit möglichst viel machen zu können. Eine Technologie, die einen zwingt, viel Zeit mit trivialen Aufgaben zu verbringen und die eigentlich interessanten Dinge in einem Wust von trivialem Code zu verstecken, den man nun einmal schreiben muss, darf man dann auch schon einmal hinterfragen. Letztlich sind zwei Wege vielversprechend, um mit wenig Code viel auszudrücken und letzlich in wenig Zeit viel zu entwickeln: Die funktionalen Sprachen wie z.B. F#, Clojure, Erlang, Elixir und Haskell. Oder die Skriptsprachen wie Ruby, Perl, Perl6 (wenn es mal fertig wird), Python und PHP. Natürlich überschneidet sich das ein Stück weit, weil einige funktionale Sprachen auch ein bißchen wie Skriptsprachen einsetzbar sind und einige Skriptsprachen auch gewisse funktionale Konstruktionen unterstützen.

Letztlich erweisen sich die funktionalen Sprachen als vielversprechend, wenn es darum geht, sehr leistungsstarke Applikationen zu entwickeln, die einen hohen Durchsatz und eine hohe Parallelisierung der Verarbeitung verwirklichen. Twitter soll mit Scala diesen Weg gegangen sein. Grundsätzlich bieten alle ernsthaften funktionalen Sprachen hier einige Möglichkeiten. F# lässt sich übrigens auch mit Mono kombiniert unter Linux verwenden. Vielleicht hat Erlang noch einen kleinen Vorteil, weil es schon auf VM-Ebene für diesen Einsatzbereich optimiert ist. Diese VM lässt sich aber auch mit Elixir verwenden. Aber man hat die Wahl zwischen mehreren Wegen.

Für viele Web-Applikationen hat sich Ruby als gut geeignet erwiesen, man sieht aber, dass es einige sehr gute PHP-Applikationen gibt. z.B. MediaWiki, die Software, mit der Wikipedia läuft. Allerdings zeichnet sich im Moment ein Trend ab, mehr von der Logik in Javascript auf der Client-Seite zu implementieren und serverseitig (fast) nur noch Webservices mit REST anzubieten, die die eigentliche Businesslogik und die Zugriffe auf die Daten zur Verfügung stellen. Diese REST-Services kann man natürlich in Ruby entwickeln; aber da gibt es viele Wege…

Ruby und vor allem Perl sind aber auch sehr stark, wenn es darum geht, Textdateien zu verarbeiten. Man kann diese nach Mustern durchsuchen, umgruppieren und umbauen und damit schöne Auswertungen machen. Für sehr große Datenmengen sollte man sich natürlich noch etwas eingehendere Gedanken machen, weil dann der Durchsatz und die Parallelisierung plötzlich mehr Bedeutung bekommen als das eigentlich Parsen des Texts. Aber man kann noch viel mehr…

Eine große Applikation kann diese Dinge auch kombinieren. GNU-Emacs ist eine sehr altes Beispiel, dass hier einen noch heute sehr aktuellen Ansatz verfolgt. Die Grundfunktionalität ist in C entwickelt und die weitergehenden Funktionen und Erweiterungen alle in Emacs-Lisp. So läßt sich ohne viel Aufwand einen Erweiterung einbinden, was nicht so leicht geht, wenn man erst einmal neu kompliieren muss. Die Idee lässt sich auch heute noch aufgreifen, wenn man eine Applikation z.B. in Scala entwickelt und dann die Möglichkeit anbietet, diese über Ruby- oder Groovy-Scripte anzusprechen, zu erweitern und zu konfigurieren.

Wenn man einmal an Häuser denkt, ist die Idee nicht so abwegig. Das eigentliche Haus ist relativ stabil aus Beton, Stein und Holz gebaut und bleibt in der Regel jahrzehntelang unverändert. Die Möbel sind selten aus Beton gegossen und eher flexibler (auch wenn sie vielerorts jahrzehntelang gleich stehen).

Share Button

Akka-Framework

Die Idee ein Framework zu entwickeln, dass ganz auf Messages zur Kommunikation zwischen den Komponenten basiert, ist interessant. Ich habe schon verschiedene Ansätze in der Java-Welt gesehen, z.B. Versuche, das in JavaEE mit JMS zu bauen. Letztlich ist das in der Java- und JVM-Welt ein eher selten verwendeter Ansatz, aber z.B. Erlang-Software basiert komplett auf diesem Prinzip, wobei natürlich effiziente Messaging-Mechanismen vorausgesetzt werden müssen.

Das Akka-Toolkit oder Akka Framework setzt diese Idee nun in konsequenter Weise für die Java- und JVM-Welt um, wobei es natürlich am besten in seiner nativen Sprache, also in Scala verwendet wird. Die Idee ist, eine effiziente massive Parallelisierung hinzubekommen und durch assynchrone Kommunikation die Komponenten weitestgehend zu entkoppeln. Typisch in der Scala-Welt ist es, dass man unveränderliche (deep immutable) Objekte in den Messages verschickt, um Änderungskonflikte und Fehler zu vermeiden, wenn dasselbe Objekt an mehreren Orten gleichzeitig verwendet wird. Veränderbare Objekte in den Messages sollte man vermeiden, außer man kennt das Framework und die Multithreading-Thematik sehr gut und weiss was man tut und es ist aus Performance-Gründen wirklich ein so großer Vorteil, dass der zusätzliche Entwicklungs- und Testaufwand gerechtfertigt ist. Dabei ist noch zu sagen, dass sich solches Verhalten kaum testen lässt, weil das Zeitverhalten in den Tests nie genau das im ungünstigsten Fall auf dem Produktivsystem sporadisch auftretende Zeitverhalten ist. So können in schlecht oder fahrlässig programmierten Applikationen noch Fehler lauern, die erst irgendwann auf dem Produktivsystem auftreten und die sich dann noch schlecht einordnen lassen. Genau deshalb sollte man hier auf Nummer sicher gehen und nur deep-immutable Objekte in Messages verschicken.

Für die Parallelisierung von Software gibt es grundsätzlich verschiedenen Ansätze. Mehrere getrennte Prozesse sind attraktiv, weil die Trennung sauber ist und man nur bei der Kommunikation überhaupt aufpassen muss. Dafür sind sie etwas schwergewichtiger als Threads und vor allem ist der Aufwand für de Kommunikation größer. Mehrere Threads zu verwenden hat den Vorteil, dass man dasselbe Memory benutzt und deshalb Daten einfacher getauscht werden können. Dafür steigen auch die Risiken, wenn mehrere Zugriffe auf dasselbe Objekt gleichzeitig stattfinden und mindestens einer davon schreibend ist.

Akka verwendet sogenannte Aktoren (engl. Actors), die einen Memory-Footprint von unter 1 k haben sollen, weshalb man etwa eine Million Actors durchaus gleichzeitig im Memory haben kann. Nun werden diesen Actors Messages geschickt, die etwa Methodenaufrufen in der (synchronen) objektorientierten Denkweise entsprechen, aber assynchron sind. Das heißt, dass der Sender die Message verschickt und dann fertig ist. Sie wird in einer Warteschlange für den passenden Actor eingereih und dann irgendwann abgearbietet. Nun hat so ein Actor nicht permanent einen Thread zugewiesen, sondern es gibt einen Threadpool. Actors mit einer nicht-leeren Warteschlange werden dann einem Thread im Threadpool zugewiesen und so abgearbeitet.

Share Button