Service für Schach-Diagramme mit Python und Flask (Micro Moves, Bauteil 2)

Blog-Serie Micro Moves -- LogoIn der ersten Folge der Micro Moves Blog-Serie haben wir einen Service auf Basis von Java und Spring Boot an den Start gebracht. Inhaltlich ging es um die laufenden Partien unserer Schach-Online-Plattform FLEXess.

In dieser Folge gibt es einen zweiten Service in Python. Ist eine andere Programmiersprache was tolles? Was spricht dagegen, den Service auch in Java zu bauen?

Um vielen einen Blick über den Tellerrand zu ermöglichen, zeige ich in dieser Blog-Serie unterschiedliche Technologien (und auch Programmiersprachen). Vielfalt ist Teil des Konzeptes. Aber …

Ist polyglott per se schick?

Monolithische Anwendungen stehen in vielen Unternehmen am Pranger. Der Grund dafür ist oft, dass es (zu) lange dauert neue Anforderungen umzusetzen, und/oder in Produktion zu bringen. Release-Zyklen von 3 Monaten und länger sind beispielsweise im Finanzbereich keine Seltenheit.

Mit der Zerlegung in kleine, unabhängige Teile (im Extremfall Microservices, moderater bei Self-contaned Systems) öffnet sich Spielraum, in den Teilen Dinge unterschiedlich zu handhaben. Mitunter wird dies sogar als eine besondere Stärke herausgestellt, für die Teile technologische Entscheidungen passgenau auf das Problem treffen zu können. Ein häufiges Beispiel hier ist die Persistenz. Wenn Services in unterschiedlichen Prozessen laufen, können sie auch leicht in unterschiedlichen Programmiersprachen entwickelt sein. Aber sie müssen nicht. Es sollte Nutzen stiften (in echten Vorhaben ist Vielfalt hier selten ein Wert an sich).

Was macht der Service?

Für verschiedene spätere Folgen benötigen wir Visualisierungen des Schachbretts. Die Forsyth-Edwards-Notation (kurz FEN), wie die die Entität Game aus der letzten Folge benutzt, ist wenig tauglich, um die Spielsituation zu erfassen. Ziel sind Graphiken wie diese:

Schachbrett mit Startaufstellung, generiert mit unserem Python Service

Der Service nimmt eine Spielsituation in FEN entgegen und liefert eine graphische Repräsentation wie oben zurück. Die Funktionalität steht per HTTP bereit, für den ersten Wurf unterstützt er

  • Eingabe in FEN als Request-Parameter
  • Response: Diagramm in fixer Größe (288 x 288 px, Figuren jeweils 32 x 32) und einem Format (PNG).

Es ist noch einiges an Einstellmöglichkeiten (etwa über Parameter) denkbar: andere Größen, Graphikformate, Figurensymbole, Farben … Wir fügen sie hinzu, wenn wir sie im Laufe der Serie brauchen. Die rote (2) markiert Euren Standpunkt im Gesamtbild („Sie befinden sich hier.“).

Lageplan FLEXess, Bauteil 2

Python und Flask

Die Programmiersprache Python (WikipediaHomepage), obgleich recht alt,  erfreut sich gerade aktuell großer Beliebtheit. Der TIOBE-Index (umstritten) führt Python im April 2018 auf Platz 4, RedMonk (umstritten) auf Platz 3. Unbestritten: Trends wie Big Data und Machine Learning erhöhen die Aufmerksamkeit für die Sprache.

Flask Web Development, 2nd EditionPython ist u.a. objektorientiert und in der Regel interpretiert. Ein häufiger Einsatzzweck sind daher Skripte. Ähnlich wie in Java oder .Net liefert Python eine Standardbibliothek mit. Darüber hinaus gibt es noch viel, viel mehr aus der Community. Da wir die Diagramme per HTTP ausliefern wollen brauchen wir eine Web-Applikation. Hier ist Flask recht beliebt und eben genau so ein Framework von Dritten.

Flask bezeichnet sich selbst als Micro-Framework für Web-Applikationen. Es beinhaltet einen Development HTTP-Server und verarbeitet dynamische Anfragen RESTful. Das „Micro“ in Micro-Framework heißt, dass Flask versucht seinen Core einfach aber erweiterbar zu halten. Anders als beispielsweise Django trifft Flask kaum Entscheidungen, etwa welche Datenbanktechnologie zu verwenden wäre. Mehr zu Flask im schönen Buch von Miguel Grinberg (Cover rechts), die zweite Auflage ist gerade frisch raus (März 2018).

Die graphische Arbeit erledigt bei uns Pillow, ein Fork der Python Imaging Library (PIL).

Die Umsetzung

Dank Flask und Pillow ist nicht all zu viel zu tun. Der überschaubare Python-Quelltext des chess-diagrams-Moduls liegt auf GitHub. Ich habe ihn auf zwei Dateien aufgeteilt.

Datei Beschreibung
chess_diagrams.py Enthält die Flask-Applikation mit zwei HTTP-Routen (Test-Seite in HTML und Diagram-Generierung). Abhängigkeiten zu Flask und draw.py
draw.py Enthält Funktionen zur Erzeugung der Diagramme.  Abhängigkeit zu Pillow.

Darüber hinaus liegen die Figurenbilder als PNG im Ordner images, und ein Font für die Brettkoordinaten (a..h, 1..8) im Ordner fonts. Um den Service leicht ausprobieren zu können, ohne FEN in der URL tippen (und enkodieren) zu müssen, liegt eine Test-Seite als HTML im Ordner templates.

Für die Funktion zum Erzeugen einer Diagramm-Graphik ausgehend von einem Web-Request sieht der Call-Graph (generiert mit Doxygen) so aus.

Call Graph (Doxygen)

Die folgende Graphik zeigt die Wirkung der einzelnen draw_xy-Funktionen aus draw.py zum Zeichnen eines Diagramms.

Schritte zum Diagramm in draw.py

Den Service bauen, starten und nutzen

Python ist eine interpretierte Sprache. Übersetzt werden muss der Quelltext daher nicht. Lediglich ein Python-Interpreter muss vorliegen. Getestet habe ich mit den Versionen 2.7 und 3.6. Abhängigkeiten lassen sich mit der Python-eigenen Paketverwaltung pip installieren (pip = pip installs packages). Die Datei requirements.txt zählt  die Pakete auf.

$ git clone https://github.com/embarced/micro-moves.git 
Cloning into 'micro-moves'... 
$ cd micro-moves/modules/chess-diagrams/
$ cat requirements.txt 
Flask
Pillow
$ 

Nach Installation der Pakete ließe sich das Ganze direkt starten. Zuvor lassen wir aber noch Unit- und Integrationtests laufen. Als Testwerkzeug verwende ich pytest. Die Ausführung der Tests in verschiedenen Umgebung (Python 2 und 3) überlasse ich tox. tox ist insbesondere im Umfeld von Continuous Integration beliebt, etwa beim Einbinden in einen CI-Server wie Jenkins. Einfach per pip installieren und tox aufrufen — die Datei tox.ini legt u.a. fest, für welche Versionen die Tests (Dateien mit dem Präfix test_) laufen sollen …

$ pip install tox
$ tox
... 

Test laufen lassen mit tox

Neben Unit-Tests für draw.py sind auch Integrationstests inkl. Flask-Webapplikation enthalten.  Wie Ihr Flask-Anwendungen testet beschreibt diese Seite.

Den Service im Development Web-Server von Flask starten, um ihn z.B. mit einem Browser zu testen, geht am einfachsten so:

$ pip install -r requirements.txt
$ python chess_diagrams.py
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
... 

Der Service lauscht nun auf localhost, und Ihr könnt ihn direkt mit einem Browser ansprechen über http://127.0.0.1:5000/. Die Testseite enthält ein paar Links um Diagramme zu erzeugen, die dann als PNG zurückgeliefert werden.

Testseite und einzelnes Diagramm im Browser

Der Service im Betrieb

Den von Flask mitlieferten HTTP-Server solltet Ihr nur zu Entwicklungszwecken einsetzen. Das Projekt rät selbst von einem Einsatz in Produktion ab und nennt auf seiner Webseite zahlreiche Alternativen, um Flask-Anwendungen in einem Web-Server zu betreiben. Hierzu zählen Public Cloud-Umgebungen wie Amazon (via AWS Elastic Beanstalk) oder Google App Engine eben so wie selbst betriebene HTTP-Server.
Green Unicorn Logo
Als ein Beispiel zu letzteren zeige ich hier gunicorn (für Green Unicorn, Logo rechts) laut „Selbstauskunft“ ein ziemlich schneller Python WSGI HTTP Server für UNIX. Die Installation kann ebenfalls über pip erfolgen. Die folgenden Zeilen Zeichen den Start unseres Service in gunicorn mit 4 Workern.

$ pip install gunicorn
$ gunicorn -w 4 chess_diagrams:app
[2018-05-01 14:38:20 +0200] [14928] [INFO] Starting gunicorn 19.7.1
[2018-05-01 14:38:20 +0200] [14928] [INFO] Listening at: http://127.0.0.1:8000 (14928)
[2018-05-01 14:38:20 +0200] [14928] [INFO] Using worker: sync
[2018-05-01 14:38:20 +0200] [14931] [INFO] Booting worker with pid: 14931
[2018-05-01 14:38:20 +0200] [14932] [INFO] Booting worker with pid: 14932
[2018-05-01 14:38:20 +0200] [14933] [INFO] Booting worker with pid: 14933
[2018-05-01 14:38:20 +0200] [14934] [INFO] Booting worker with pid: 14934
$

Faktoren und Prinzipien für Microservices und die Cloud

Für Anwendungen die einem aktuellen Architekturstil genügen und die sich vielleicht auch in „der Cloud“ wohlfühlen gelten einige Eigenschaften als zentral. Sehr verdichtet finden sich diese in Form von Listen aus Faktoren oder Prinzipien versammelt und diskutiert, von denen die älteste und bekannteste die Twelve-Factor-App ist. Eine etwas neuere Meinung findest sich E-Book „Beyond the Twelve-Factor-App“ von Kevin Hoffman. Weniger Microservices-lastig sind die ISA-Principles (ISA = Independent Systems Architecture) — sie haben (auch) Self-contained Systems im Sinn und kommen aus deren Umfeld.

Hält man den chess-diagrams Service gegen die Faktoren, so fällt insbesondere auf, dass er im Gegensatz zum games-Service rasant startet. Schnelles Starten ist entscheidend, wenn man auf hohe Last dynamisch mit weiteren Exemplaren reagieren möchte.

Der games-Service liegt bei mir bei etwa 10 Sekunden für den Start. Fairerweise ist ein in Spring Boot realisierter Service schneller oben als ein Java EE Application Server inklusive Service. Hauptkritikpunkt für in Java realisierte Services z.B. im Docker/Kubernetes-Umfeld ist allerdings nicht die Startzeit, sondern der Ressourcenhunger, insbesondere in Bezug auf Speicher.

Weitere Informationen — und wie es weiter geht …

Wenn man von Java kommt wie ich ist Entwickeln in Python wie eine Reise in ein fremdes Land. Die Sprache ist ausgereift und natürlich gibt es alles, was Ihr in Java zum Programmieren nutzt, in Python irgendwie auch. Nur wie? Zum Beispiel: Wie testet Ihr Eure Sachen? Wie bindet Ihr Fremdbibliotheken ein? Welche IDE benutzt Ihr? Einige Sachen waren sehr ungewohnt für mich. Zum Beispiel die parallele Existenz von Python 2 und 3.

The Hitchhiker's Guide to Python (Cover) Ein Buch, das mir hier sehr geholfen hat, ist „The Hitchhiker’s Guide to Python“ von Kenneth Reitz (Cover rechts). Es ist dicht gepackt mit Best Practices, Konventionen und gebräuchlichen Werkzeugen aus dem Python-Universum. Und es ist hier frei online verfügbar (!).

Im weiteren Verlauf gibt es noch ein weiteres Bauteil in Python übrigens. Das für die Spieler. In der nächsten Folge verheiraten wir aber erst einmal die Teile aus den ersten beiden Folgen (games und chess-diagrams) und setzen eine Single Page Application (SPA) als Oberfläche drauf. Ziel: Im Browser gegeneinander spielen können …

Ach ja: Fragen und Anregungen sind natürlich jederzeit gerne Willkommen. Per Kommentar hier im Blog oder gerne auch per Mail direkt an mich …

Zur Blog-Serie Micro Moves

Leave a Reply