All Posts By

Stefan Zörner

Ein Steckbrief für das Erarbeiten von Fitness-Functions

By | Inhaltliches | No Comments

Evolutionäre Architektur ist als Trend schon lange im Gespräch. Konkret finden wir sie zum Beispiel auf dem Technology Radar bei Thoughtworks bereits 2010. Im entsprechenden O’Reilly-Buch von 2017 findet sich diese Definition:

„Eine evolutionäre Architektur unterstützt geleitete, inkrementelle Veränderungen über mehrere Dimensionen hinweg“. (N. Ford, R. Parsons, P. Kua, Patrick: Building Evolutionary Architectures)

Evolutionäre Architektur denkt einige Dinge anders als „klassische“ Softwarearchitektur. So werden dort Architekturentscheidungen nicht als schwer änderbar hingenommen. Stattdessen sind Änderungen in der Architektur aufgrund von Überraschungen willkommen und normal.

Ein Konzept, das eng mit Evolutionärer Architektur verknüpft ist, sind Fitness-Functions. Eine Fitness-Function misst objektiv, wie gut eine Lösung die an sie gesetzten Ziele erreicht. Fitness-Functions unterstützen genau die geleiteten Veränderungen, von denen in der Definition von Evolutionären Architektur die Rede ist. Sind wir mit unserer Lösung (noch) auf dem richtigen Weg? Halten neue Ideen, was sie versprechen? Wie bewerten wir Experimente, zum Beispiel mit neuen Technologien?

SteckbriefIm Rahmen unserer Coaching-Einsätze haben wir einen kleinen Steckbrief (oder „Canvas“) entwickelt, der uns und unsere Kunden bei der Entwicklung von Fitness-Functions unterstützt.

Teilnehmer des Workshops „Die Wirksamkeit Eurer Architektur automatisiert testen“ von Sandra Parsick und mir beim Software Architecture Summit in München dieses Jahr konnten diesen Steckbrief im Rahmen der Übungen für ihre eignen Projekte ausprobieren. Ich möchte dem Wunsch folgen, ihn hier zum Download bereit zu stellen … (Druckvorlage für 3 Steckbriefe inkl. Leitfragen zur Umsetzung).

Wie arbeitet Ihr mit dem Steckbrief? Tatsächlich steht das Erarbeiten und Umsetzen der Fitness Funktion nicht am Anfang. Im Workshop haben wir unser Vorgehen in 6 Schritten skizziert (Details in den Folien, insbesondere auch zu den Kategorien) – zu Beginn stehen die Architekturziele, verfeinert durch Beispielszenarien.

  1. Identifikation der Architekturziele
  2. Ausarbeitung von Beispielszenarien
  3. Auswahl für die Überprüfung
  4. Formulierung der Test-Idee
  5. Umsetzung und Automatisierung der Auswertung
  6. Sichtbarmachen der Resultate

Die Steckbriefe sammeln die Ergebnisse aus den Schritten 1, 2 und 4 im Vorgehen zusammen, und geben Input für 5 und 6. Pro Szenario gibt es dann eine Fitness-Funktion und dafür jeweils einen eigenen Steckbrief. Ausgefüllt sieht das Ganze z.B. so aus:

Fitness-Function Steckbrief, ausgefülltLassen wir uns ein kleines Beispiel durchspielen! Nehmen wir an, Eurer Team entwickelt eine Software, die lange leben soll. Ihr setzt dabei verschiedene Fremdbibliotheken ein. Oft werden diese Abhängigkeiten in Build-Skripten mit einer Version eingepflegt, diese dann aber nie aktualisiert. Was, wenn Ihr auf eine neue Version umsteigen müsst (z.B. weil dort ein Security-Problem gefixt wurde, das für Euch relevant ist …

Wir formulieren daher als Architekturziel zur Kompatibilität:

„Unsere Software läuft mit den aktuellen Versionen der eingesetzten Fremdbibliotheken.“

Das ganze verfeinern wir durch ein Beispielszenario (Über Qualitätsszenarien könnt Ihr z.B. in unserem arc42-Starschnitt nachlesen):

„Ein Open Source Projekt veröffentlicht eine neue Version einer von uns verwendeten Fremdbibliothek. Unsere Software lässt sich ohne Änderungen mit der neuen Version bauen und funktioniert damit einwandfrei.“

Zu diesem Szenario lässt sich eine Fitness Function formulieren, die absichert, dass bei Austausch einer verwendeten Fremdbibliothek x in Version n durch eine neuere Version n+1 die Software weiterhin baut und alle Tests besteht.

Umsetzen und automatisiert Auswerten lässt sich eine entsprechende Test-Idee durch

  1. Online-Überprüfung, ob zu einer Bibliothek eine neue Version verfügbar ist (Scannen der Repos),
  2. gezieltes Update der Bibliothek im Build-File in einem separaten Branch und
  3. Bauen des Branches und Durchlaufen der vorhandenen Tests.

Wenn Bauen und/oder Testen fehlschlagen weiß das Team frühzeitig, dass seine Software mit der neueren Version der Bibliothek nicht ohne Anpassungen funktioniert.

Dependabot bietet die beschriebene Funktion “von Hause aus” an. Wenn Schritt 1 eine neue Version für eine verwendete Abhängigkeit liefert (was Dependabot anhand des Build-Skripts prüft) legt das Werkzeug in GitHub einen eigenen Branch dafür an, modifiziert das Build-Skript, baut und meldet das Ergebnis. Im Erfolgsfall erzeugt es passende Pull-Requests zum Mergen:

Dependabot BeispielDas Team entscheidet, wie es mit dieser Erkenntnis umgeht. Mitunter kann es veraltete Funktionalität (Stichwort “deprecated”) der Fremdbibliothek durch neuere ersetzen, und den Test bestehen, ohne tatsächlich schon ein Update durchzuführen. Oder es stellt das Update als Aktivität unter “technische Schulden beheben” ein.

Bei kontinuierlichem Aktualisieren (oder dem Experimentieren damit) schlummern bei größeren Umbauten (z.B. neue Java-Version) keine unbekannten Risiken, die automatisierte Überprüfung mit Werkzeugen wie Dependabot nimmt dem Team hier Arbeit ab, die sich im Projektgeschäft manuell keiner macht.

Der Steckbrief hilft durch eine Kategorisierung im rechten oberen Bereich, Eure Test-Idee zu schärfen, und zur Umsetzung zu bringen. Die Kategorien sind in den Folien zum Workshop erklärt. Darüber hinaus haben wir ein paar „Leitfragen“ definiert, die Euch bei der Implementierung der Fitness-Funktion helfen. Sie sind auch in der Druckvorlage enthalten.

  • Wann, wie und wo führen wir die Testfunktion aus?
  • Wie kommen wir an die benötigten Daten?
  • Wie werten wir die Daten aus?
  • Was passiert, wenn die Ergebniskontrolle einen Fehler anzeigt?
  • Was passiert, wenn der Test selbst fehlschlägt?
  • Wie kommunizieren wir das Ergebnis ? Wie oft? Und an wen?

Die folgende Abbildung gibt einen Überblick über den Steckbrief und stellt die Bereiche in den Bezug zu den Schritten des Vorgehens oben.

Ausfüllen erklärt

Die Wirksamkeit Eurer Architektur automatisiert testen mit Sandra Parsick und Stefan Zörner

By | Publikationen, Vorträge | No Comments

Nicht-manuelle Tests stellen die Qualität einer Softwarelösung auf effiziente Weise sicher und sind Standard in der Software-Entwicklung. Auch weil die Automatisierung in der Regel früher Rückmeldung gibt zu Fehlern und anderen Unschönheiten. Der Ansatz ist auf verschiedenen funktionalen Ebenen gängig — Unit-Tests, Modul-Tests, Integrationstests… Wäre es nicht toll, auch Aspekte Eurer Softwarearchitektur automatisch testen zu können?

Was heißt es überhaupt, Eure Architektur zu testen? In diesem Workshop diskutieren wir zunächst kurz verschiedene Ansatzpunkte und Möglichkeiten dazu. Und wir räumen mit Mythen und Missverständnissen auf. So ist eine Überprüfung, ob eine Implementierung bestimmte Vorgaben einhält, zwar für einzelne Aspekte problemlos möglich. Wenn die Vorgaben nichts taugen ist das Ergebnis gleichzeitig uninteressant (und die Tests sind Verschwendung).

Konsequenterweise konzentrieren wir uns anschließend auf effektive Ansätze aus dem Chaos Engeneering und Fitness Functions. Denn diese können bei richtiger Anwendung die Wirksamkeit Eurer Architekturansätze langfristig absichern. Und sie erlauben eine zielgerichtete Weiterentwicklung Eurer Softwarelösung.

Anders als typische Literatur über Evolutionäre Architekturen hören wir nicht da auf, wo es konkret wird. Sondern zeigen Real-World-Beispiele und Implementierungsoptionen im Freiflug.

Interaktive Elemente und die Anwendung der Konzepte auf Eure Softwarlösungen runden den Workshop ab.

Graphic Recording von Lisa Moritz

Lisa Moritz (@Teapot4181) hat im Workshop live mit visualisiert. Hier das Resultat. Ein Dickes Danke dafür!!

Software Architecture Summit 2020

Ohne Firlefanz. Artikel zu prägnanten Architekturüberblicken auf Informatik Aktuell

By | Artikel, Publikationen | No Comments
Architektur ohne Firlefanz – Ihre Lösung auf einem Bierdeckel

Informatik Aktuell Logo


Viele interessieren sich für Ihre Softwarelösung oder zumindest für Teilaspekte davon: Neue im Team, teamfremde Kollegen, Manager, Kooperationspartner … – Wie geben Sie diesen Leuten einen prägnanten Einstieg? In diesem Beitrag erfahren Sie, wie Sie Schritt für Schritt einen prägnanten Architekturüberblick anfertigen. Ich diskutiere, was mindestens hineingehört und welche Formate sich in unterschiedlichen Situationen bewähren.

Artikel Online Lesen

Stefan Zörner live beim Special Day „Architektur“ der Java User Group Hamburg

By | Publikationen, Vorträge | No Comments

duke_JUG_Hamburg

„Architektur auf dem Bierdeckel – Eure Lösung in kurz und knackig“
Sprecher: Stefan Zörner
Special Day „Architektur“ der Java User Group Hamburg
Donnerstag, 19. September 2019, 14:00 bis 20:00
COYO GmbH, Gasstraße 6A, 22761 Hamburg

Foliendownload (PDF)

Viele interessieren sich für Eure Softwarelösung oder zumindest für Teilaspekte Eurer Lösung: Neue im Team, teamfremde Kollegen, Manager, Kooperationspartner … – Wie gebt Ihr diesen Leuten einen prägnanten Einstieg?

In dieser Session erfahrt Ihr, wie Ihr Schritt für Schritt einen prägnanten Architekturüberblick anfertigt. Ich diskutiere, was mindestens dazu gehört, welche Konzepte helfen, und welche Formate, Notationen und Werkzeuge sich in unterschiedlichen Situationen bewähren. Ihr lernt wie Ihr Euren Überblick aktuell haltet und in welchen Situationen Ihr besser mehr parat habt als das Minimum.

Der Vortrag ist gespickt mit Erfahrungswissen, Rezepten und Beispielen. Als Schmankerl zeige ich, wie ein methodisch clever gemachter Überblick es nicht nur ermöglicht, Eure Architektur wirkungsvoll zu kommunizieren. Sondern sie auch zu reflektieren und Risiken aufzudecken. Ob wir dabei mit den 107mm Durchmesser eines Bierdeckels auskommen, lasse ich hier mal offen …

follow us on Twitter – @embarced

Workshop auf dem Software Architektur Summit 2019 in Berlin

By | Publikationen, Vorträge | No Comments

„Softwarearchitektur automatisiert testen“
Sprecher: Sandra Parsick und Stefan Zörner
Software Architecture Summit 2019
Montag, 16. September 2019, 10:15 – 13:00 Uhr
H4 Hotel Berlin Alexanderplatz
@SoftwArchSummit #SoftwareArchitectureSummit

Source- Code & Demoanwendung auf Github
Foliendownload (PDF)

Nicht-manuelle Tests stellen die Qualität einer Softwarelösung auf effiziente Weise sicher und sind Standard in der Software-Entwicklung. Auch weil die Automatisierung in der Regel zu Fehlern und anderen Unschönheiten früher Rückmeldung gibt. Der Ansatz ist auf verschiedenen funktionalen Ebenen gängig — Unit-Tests, Modul-Tests, Integrationstests…

Wäre es nicht toll, auch Aspekte Eurer Softwarearchitektur automatisch testen zu können? Was heißt es überhaupt, Eure Architektur zu testen? In diesem Workshop diskutieren wir zunächst kurz verschiedene Ansatzpunkte und Möglichkeiten dazu. Und wir räumen mit Mythen und Missverständnissen auf. So ist eine Überprüfung, ob eine Implementierung bestimmte Vorgaben einhält, zwar für einzelne Aspekte problemlos möglich, wenn aber die Vorgaben nichts taugen ist das Ergebnis gleichzeitig uninteressant (und die Tests sind Verschwendung). Konsequenterweise konzentrieren wir uns anschließend auf effektive Ansätze aus dem Chaos Engineering und Fitness Functions. Denn diese können bei richtiger Anwendung die Wirksamkeit Eurer Architekturansätze langfristig absichern. Sie erlauben zudem eine zielgerichtete Weiterentwicklung Eurer Softwarelösung. Anders als typische Literatur über Evolutionäre Architekturen hören wir nicht da auf, wo es konkret wird, sondern zeigen Real World-Beispiele und Implementierungsoptionen im Freiflug. Interaktive Elemente und die Anwendung der Konzepte auf Eure Softwarelösungen runden den Workshop ab.

follow us on Twitter – @embarced

Microservices & Makro-Architektur — Drei zentrale Entwurfsfragen

By | Publikationen, Vorträge | No Comments

DWX19_Logo

„Microservices & Makro-Architektur — Drei zentrale Entwurfsfragen“
Sprecher: Stefan Zörner
Developer Week 2019
Montag, 24. Juni 2019, 15:30 – 16:30 Uhr (Raum Oslo)
Messe Nürnberg
#DWX2019

Foliendownload (PDF)

Moderne Architekturstile wie Microservices oder Self Contained Systems lassen Teams, die einzelne Teile entwickeln, viel Freiheit beim Treffen von Technologieentscheidungen.

Drei Fragestellungen entpuppen sich jedoch regelmäßig als Kandidaten, um in der Makro-Architektur (also übergreifend) adressiert zu werden, zumindest zu einem gewissen Grad. Sonst wirkt die Anwendung nicht aus einem Guss oder verfehlt andere Architekturziele (z.B. flexibel reagieren zu können auf Veränderungen).

In diesem Vortrag stelle ich die drei Themen entlang eines durchgängigen Beispiels vor. Ich zeige gängige Lösungsoptionen und Einflussfaktoren, die Euch eine informierte Auswahl für Eure Vorhaben ermöglichen. Wechselseitige Beeinflussungen, Kompromisse und Real World-Entscheidungen eingeschlossen.

follow us on Twitter – @embarced

Architektur in kurz und knackig – auf der Developer Week 2019

By | Publikationen, Vorträge | No Comments

DWX19_Logo

„Architektur auf dem Bierdeckel — Eure Lösung in kurz und knackig.“
Sprecher: Stefan Zörner
Developer Week 2019
Montag, 24. Juni 2019, 14:15 – 15:15 Uhr (Raum Sydney)
Messe Nürnberg
#DWX2019

Foliendownload (PDF)

Viele interessieren sich für Eure Softwarelösung oder zumindest für Teilaspekte Eurer Lösung: Neue im Team, teamfremde Kollegen, Manager, Kooperationspartner … – Wie gebt Ihr diesen Leuten einen prägnanten Einstieg?

In dieser Session erfahrt ihr, wie Ihr Schritt für Schritt einen prägnanten Architekturüberblick anfertigt. Ich diskutiere, was mindestens dazu gehört, welche Konzepte helfen, und welche Formate, Notationen und Werkzeuge sich in unterschiedlichen Situationen bewähren. Ihr lernt wie Ihr Euren Überblick aktuell haltet und in welchen Situationen Ihr besser mehr parat habt als das Minimum.

Der Vortrag ist gespickt mit Erfahrungswissen, Rezepten und Beispielen. Als Schmankerl zeige ich, wie ein methodisch clever gemachter Überblick es nicht nur ermöglicht, Eure Architektur wirkungsvoll zu kommunizieren. Sondern sie auch zu reflektieren und Risiken aufzudecken. Ob wir dabei mit den 107mm Durchmesser eines Bierdeckels auskommen, lasse ich hier mal offen …

follow us on Twitter – @embarced

Einheitlicher UI-Rahmen mit PHP und Server Side Includes (Micro Moves, Bauteil 8)

By | Inhaltliches | No Comments
Blog-Serie Micro Moves -- Logo

Bereits einer früheren Folge dieser Blog-Serie  hatten wir unterschiedliche Optionen für die UI-Frage rund um Microservices diskutiert, und auch zwei Extreme dargestellt. Wir haben uns dann für einen Weg entschieden, und dabei Nachteile in Kauf genommen. In dieser Folge zeige ich einen alternativen Ansatz, der diese Mankos vermeidet. Wie jeder Kompromiss hat aber auch dieser seinen Preis.

Er ist es wert, wenn wir beispielsweise beim Hinzufügen einer neuen fachlichen Funktionalität, die sich im Hauptmenü widerspiegelt, nicht viele bestehende Module anfassen wollen.

Um was geht es — ein Überblick

Diese Folge liefert einen einheitlichen Rahmen für das webbasierte Frontend, das bisher auf mehrere Bauteile (games, players, play, …) verteilt ist. Im Grunde bleibt es das auch. Wir ziehen lediglich wiederkehrende Teile heraus. So erhöhen wir die Wartbarkeit und reduzieren redundant implementierte Funktionalität.

Überblick, Bauteil 8

Die gemeinsamen Fragmente des UI-Rahmens liefert ein neues Modul homepage, das mit PHP 7 realisiert ist und in einem Apache httpd läuft. Die rote (8) markiert den Standpunkt des Bauteils im Gesamtbild („Sie befinden sich hier.“). Die Einbindung der Fragmente des UI-Rahmens erfolgt mit Server Side Includes (SSI) in unserem Reverse Proxy nginx, den wir in Folge 4 eingeführt hatten.

UI-Optionen und ein Kompromiss

Die UI-Frage im Zusammenhang mit Microservices: Trotz mehrerer Teile soll sich die Anwendung dem Benutzer “aus einem Guss“ präsentieren. Wie realisieren wir mit mehreren Teilen ein UI?

In Folge 3 dieser Serie haben wir zwei extreme Antworten für diese Frage beschrieben: Jeder Microservices hat sein eigenes UI bzw. es gibt einen gemeinsamen Client für alle. In der Abbildung unten seht Ihr sie als Optionen (1) bzw. (3). Dazwischen eine neue Option (2) als Kompromiss — die Heldin dieser Folge.

Die folgende Tabelle beschreibt die einzelnen Optionen und nennt Beispiele für die technische Umsetzung.

OptionBeschreibungUmsetzung
(1) Jeweils eigenes UIJeder Microservice bringt sein komplett eigenes UI mit. Die Integration zwischen den UIs erfolgt innerhalb des Browsers über Links.z.B. klassische HTML-basierte Web-Applikationen à la amazon.de, Web- MVC-Framework (Request/Response) garniert mit JavaScript (etwa Spring Web MVC oder PHP Micro Framework)
(2) Plugin-AnsatzMicroservices integrieren sich über eigene UI-Anteile in ein übergeordnetes UI. Im einfachsten Fall enthält dieses nur die Hauptnavigation.z.B. Desktop-Applikation à la Spotify, Portalserver, anderweitig server- oder client-seitig eingebettete HTML-Fragmente (etwa mit Server Side Includes oder als Single Page Application z. B. mit AngularJS).
(3) Full ClientEin gemeinsames UI nutzt alle Microservices über deren Schnittstellen. Diese sind selbst UI-los und enthalten nur Geschäftslogik.z.B. Mobile-App à la YouTube für Smartphone und Tablet, nativ entwickelt für Zielsysteme wie iOS, Android etc. oder hybrid erstellt, etwa mit PhoneGap

Jeweils eigenes UI

Bisher in dieser Serie haben wir im Wesentlichen Variante (1) verfolgt. So ist games mit Java und Spring Web MVC realisiert, players mit Python und Flask. Beide liefern jeweils den gesamten Inhalt ihrer Seiten. Für den Benutzer wirkt es durch den gemeinsamen Nenner Bootstrap wie aus einem Guss. Ein Wechsel zwischen games und players wirkt nicht wie ein Bruch, weil die Oberflächen gleich gebaut sind.

Die Vorteile von Ansatz (1) kommen besonders dort zum Tragen, wo Teams für Vertikalen verantwortlich sind und unabhängig arbeiten wollen:

  • Das Team hat große technologische Freiheiten im UI
  • Funktionalität ist vom Team vollständig (inkl. UI) lieferbar, unabhängig von anderen Teams

Full Client

Full Client so

Das Modul play unserer Serie deutet dagegen an, wie Ansatz (3) funktioniert. Bei play handelt es sich um eine Single Page Application (SPA) in Vue.js. Sie greift auf andere Services (chess-diagrams, games via REST) zu.

Die Vorteile dieses Ansatzes liegen in der potentiell besseren (bzw. leichter erreichbaren) User Experience:

  • Inhalte und Funktionen aus verschiedenen Themen lassen sich nahtlos auf einer Seite integrieren – es gibt keine Brüche
  • ein einheitliches User Interface ist leicht erreichbar
  • ein spezialisiertes Team für optimales UX denkbar

In unserer Serie hier führte die Wahl von (1) dazu, dass wir Teile der Oberfläche, etwa die Navigation, mehrmals implementiert haben. Das JWT-Token aus Folge 7 haben wir gleich drei mal ausgelesen (1x in Java in games, 1x in JavaScript in play, 1x in Python in players). Wie können wir diesen redundanten Code vermeiden, und trotzdem die Module unabhängig voneinander inkl. Oberfläche entwickeln und deployen?

Transklusion als weiterer Lösungsansatz

Eine verbreitete Idee für Weboberflächen nach Option (2) bezieht die Inhalte der Seite(n) von unterschiedlichen Stellen (bei uns Modulen wie players oder games) und fügt sie an einer Seite zusammen. Als Buzzword fällt hier mitunter „Transklusion“, lt. Wikipedia „die Übernahme von einem elektronischen Dokument oder Teilen davon in ein oder mehrere andere Dokumente …“. Auch in der Angular-Szene ist dieser Begriff gebräuchlich.

Auf diese Weise ist es möglich, wiederkehrende Schnipsel der Oberfläche wie zum Beispiel die Navigation von zentraler Stelle zu beziehen und immer wieder einzubinden. Im Ursprung des Begriffes ist von Dokumenten die Rede, es kann sich aber auch um dynamische Teilinhalte handeln. Dann wird es interessant.

Die Einbinde-Idee kennt verschiedene Möglichkeiten zur Umsetzung. Sie unterscheiden sich vor allem durch das Programm, das die Gesamtseite zusammenbaut. Ort des Geschehens kann sowohl der Client (also der Web-Browser), als auch das Backend (ein Server) sein.

ClientBackend
Im Browser laden geeignete JavaScript-Routinen Teile (HTML-Fragemente) dynamisch nach und fügen sie in das Dokument ein. Das Einbinden der Schachbrett-Grafik aus chess-diagrams in play durch ein img-Tag fällt auch in diese Kategorie und ist in der Umsetzung noch schlanker.Auf der Server-Seite kommen Edge-Server, CDNs (Content Delivery Networks) oder auch Proxy-Server oder der Web-Server selbst in Frage. Standardisierte Technologien in diesem Umfeld: SSI (Server Side Includes) und ESI (Edge Side Includes). Darüber hinaus gibt es darauf spezialisierte Bibliotheken und Framework-Lösungen wie Tailor von Zalando.

Ich zeige im Folgenden eine Lösung mit SSI und PHP. Anschließend diskutiere ich Stolpersteine und Konsequenzen dieses Ansatzes.

Eine Umsetzung mit PHP-Schnipseln

In unserer Schachplattform illustrieren wir die Technik mit drei wiederkehrende Schnipseln:

  • Den Header, inkl. den JavaScript- und CSS-Ressourcen
  • Das Menu (Navigationsleiste), inkl. der Kennzeichnung des aktiven Moduls
  • Den Footer, inkl. Link zur About-Seite des Moduls

Dabei sind der zweite und dritte Schnipsel mit (überschaubarer) Dynamik ausgestattet: In der Navigation ist das aktive Modul in der Menu-Zeile hervorgehoben. In Abhängigkeit vom Anmeldestatus des Benutzers ändern sich die Links im rechten Teil des Menüs (Anmelden / Registrieren vs. Profil /Abmelden). Hier ein Beispiel:

Aktives Modul: games, Benutzer Peter Pan ist angemeldet.
Aktuelles (aktives) Modul: games, Benutzer Peter Pan ist angemeldet.

Beim Footer-Schnipsel ist die Jahreszahl des Copyrights dynamisch und der Link auf die About-Seite des Moduls abhängig vom aktiven Modul. Das folgende Bild zeigt die Platzierung der Navigationsleiste navbar und der Fußzeile footer in der Oberfläche.

Sichtbare Schnipsel in der Weboberfläche
PHP 7 Logo

Umgesetzt sind die Schnipsel mit einem neuen Modul: homepage, Quelltext wie üblich auf GitHub. Es ist in PHP 7 geschrieben und läuft in einem Apache HTTP Server. PHP ist laut Selbstauskunft „eine beliebte, universell einsetzbare Skriptsprache, die sich besonders für die Webentwicklung eignet.“ Als Nebeneffekt haben wir mit PHP eine weitere Programmiersprache im System — polyglott war ja ein Ziel dieser Serie.

Das homepage-Modul besteht aus einer Handvoll HTML-Seiten, teilweise mit eingebettetem PHP. Die Tabelle unten listet sie auf.

SeiteBeschreibung
header.phpKopf einer Seite mit head– und title-Tag und CSS für Bootstrap.
navbar.phpNavigationsleiste. Der Request-Parameter active setzt den hervorgehobenen Menüeintrag. Mögliche Werte bisher: „games“, „players“.
footer.phpFuß der Seite mit Links, enthält auch die JavaScript-Bibliotheken für jQuery und Bootstrap. Das Copyright-Jahr setzt es via PHP automatisch, der Parameter module beeinflußt den Link auf die About-Seite. Beispiel: „players“ -> /players/about.html
index.htmlHomepage der gesamten Anwendung. Statischer Inhalt, die drei Schnipsel unten bindet es ein.
about.htmlÜber das Modul homepage. Statischer Inhalt, die drei Schnipsel unten bindet es ein.

Wie bei den anderen Modulen gibt es auch bei homepage ein Dockerfile. Die Einbindung in das Gesamtsystem erfolgt in der Datei nginx.conf für den Reverse Proxy sowie in docker-compose.yml für Docker Compose.

Server Side Includes

Server Side Includes (kurz SSI) sind eine ziemlich archaische Technologie für Web-Server. Ein solcher führt, wenn er SSI unterstützt, die entsprechenden Skript-Anweisungen innerhalb eines Dokumentes aus, bevor er es an den HTTP-Client (den Browser) ausliefert. Zuvor ersetzt er die SSI-Anweisungen durch deren Ergebnis.

Die für uns interessante SSI-Anweisung ist include — mit ihr bindet ein Server (oft wiederkehrende) Dokumentteile ein, und reduziert so Redundanz und Wartungsaufwand. Hier ein Beispiel für das Einbinden einer Datei:

<!--#include file="footer.html" -->

Alternativ zu statischen Dateien können auch dynamische Inhalte eingebunden werden. Im folgenden Fall führt der Server das PHP-Skript aus und inkludiert das Ergebnis.

<!--#include virtual="navbar.php" -->

Anwendung in FLEXess

In FLEXess habe ich die wiederkehrenden Elemente (Header, Footer, Navigation) aus den HTML-Seiten, welche die Module players, games etc. liefern, gelöscht und durch SSI-Anweisungen ersetzt. Bevor unser Reverse Proxy sie an den Browser ausliefert, führt er sie aus und fügt so die Inhalte aus den Modul homepage ein. Die SSI-Konfiguration in nginx ist dabei einfach. Hier ein Ausschnitt aus der Datei nginx.conf im FLEXess-Modul reverse-proxy für das Modul players :

...
location / {
    ssi on;
    proxy_pass http://homepage:80/;
}
...
location /players/ {
    ssi on;
    proxy_pass http://players:8000/;
}
...

Die erste Anweisung lenkt Anfragen von der Document-Root auf das neue homepage-Modul. Dieses liefert von nun an die Startseite (/index.html) und das Favicon (/favicon.ico). Vor allem aber die zentralen Fragmente für Header, Navigation und Footer. Sie landen via SSI auch in die statischen Seiten von homepage selbst (deswegen ist SSI auch dort aktiv geschaltet). Wichtig aber vor allem die Anweisung „ssi on;“ in players. Auf diese Weise scant nginx in HTML-Seiten von dort nach SSI-Anweisungen und führt sie aus. Details zur SSI-Konfiguration entnehmt Ihr der Dokumentation von nginx.

In players ist der Einbau der Fragmente sehr einfach. Die verwendete Template-Engine unterstützt Basisseiten. Von einer solchen sind alle anderen Seiten abgeleitet. Hier die zentrale Basisseite für players mit den SSI-Anweisungen.

<!DOCTYPE HTML>
<html>
<!--# include virtual="/header" -->
<body>

    <!--# include virtual="/navbar?active=players" -->

    <div id="header" class="container">
        <div class="page-header">
        {% block header %}
        {% endblock %}
        </div>
    </div>

    <div id="messages" class="container">
    {% with messages = get_flashed_messages(with_categories=true) %}
      {% if messages %}
        {% for category, message in messages %}
          <div class="alert alert-{{category}}">{{ message }}</div>
        {% endfor %}
      {% endif %}
    {% endwith %}
    </div>


    <div id="content" class="container">
        {% block content %}
        {% endblock %}
    </div>

    <!--# include virtual="/footer?module=players" -->

</body>
</html>

Feinheiten

Noch zwei Details zur Implementierung: Zum einen müssen wir nicht footer.php o.ä. schreiben, es reicht footer. Mir war wichtig, dass die verschiedenen Module nicht wissen, dass die Homepage in PHP geschrieben ist. Schlimm genug dass sie wissen müssen, dass die Einbindung mit SSI erfolgt. Erreicht habe ich das durch eine Konfiguration des Apache httpd. Details dazu lest Ihr in diesem Beitrag von Alex Cican: „How to remove .php, .html, .htm extensions with .htaccess“.

Zum zweiten: In den Verwendungen in der Seite aus players oben tauchen Aufrufparameter auf. Beispielsweise active für den aktiven Menupunkt. Da das Fragment aus homepage nicht weiß, von wo es eingebunden wurde, übergeben wir diese Information. Alternativ zu den Parametern könnten wir auch versuchen die URL auszuwerten. Im Falle des angemeldeten Benutzers arbeiten wir nochmal anders. Nämlich mit dem JWT-Cookie aus Folge 7, das sich in PHP auch prima auslesen lässt.

ESI statt SSI?

Neben SSI zum Einbinden der Schnipsel wäre ESI (Edge Side Includes) ein gangbarer und vergleichbarer Weg. Der ESI-Standard ist neuer und umfangreicher als SSI. Auch dort gibt es ein include. Die Syntax der Anweisungen ist etwas moderner: XML statt HTML-Kommentare. Die Wahl hier fiel vorrangig deshalb auf SSI, weil unser Reverse Proxy nginx es unterstützt, ESI hingegen nicht. Eine Alternative zu nginx wäre hier Apache Traffic Server, der könnte auch ESI.

Stolperfallen

Die Sache mir SSI funktioniert in unserem Fall hier ganz prima. Es gibt dennoch Stolperfallen, die ich Euch nicht vorenthalten möchte.

Stolperfalle

Zum einen: Der Reverse Proxy (bei uns nginx) führt nur SSI-Anweisungen in Dokumenten aus, die er „sieht“. Konkret muss dafür SSI für das betreffende eingebundene Modul aktiv sein („ssi on;“). Zum anderen (jetzt kommt die Falle) darf der Content nicht komprimiert sein.

Apache httpd beispielsweise zippt Inhalte standardmäßig, bevor er sie zum Client sendet. Sie landen dann im Browser und werden dort entpackt, inklusive der nicht ausgeführten SSO-Anweisungen.

Entweder, Ihr gewöhnt dem Webserver in der Konfiguration das Zippen ab, wenn nginx die Inhalte per SSI anreichern soll. Oder Ihr konfiguriert nginx umgekehrt durch Header-Anpassung so, dass er komprimierte Inhalte nicht akzeptiert. Apache sendet sie dann artig unkomprimiert. Ich habe das auf dem zweiten Weg gelöst. Eine kurze Beschreibung dazu findet sich zum Beispiel bei Stackoverflow („With nginx, how do I run SSI on a page returned from another server?“).

Weiterleitungsziele ermitteln (Redirect)

Ein weiteres Problemhat zwar nicht direkt mit SSI zu tun. Aber es ist bei der Umstellung in FLEXess auf SSI zu Tage getreten. Module möchten mitunter ein HTTP Redirect (Status Code 3xx) senden.

In unserem Fall war das bei players nach dem An- und Abmelden eines Benutzers erforderlich. Der Grund: In diesen beiden Fällen setzt players entweder ein Cookie (beim Anmelden) oder entfernt es (beim Abmelden). Anschließend stellt players eine Seite dar, in welcher der Anmeldestatus korrekt in der Navigation angezeigt sein muss. Problem: Die Homepage ermittelt den Anmeldestatus aus dem JWT-Token des aktuelle Requests — die Änderung des Cookies ist erst mit dem nächsten Request aktiv.

Früher konnte players das intern klären. Jetzt ist die einfachste Lösung ein Redirect. Der Browser sendet dann einen neuen Request, bei dem der Cookie mit dem JWT-Token nach Anmelden enthalten ist, und nach Abmelden auch schon gelöscht.

Problem: players hängt unterhalb des Reverse Proxies. Für das Redirect-Ziel benötigt es die Original-URL. Konkret: Schema (http vs. https), Servername, Port, URL … Die einfachste Lösung hier war es im nginx die Konfiguration so zu ändern, dass dieser die Daten in HTTP-Headern an players weiterleitet („proxy_set_header“). Eine Beschreibung dazu liefert ein schöner Beitrag bei Digital Ocean: „Understanding Nginx HTTP Proxying, Load Balancing, Buffering, and Caching“.

Diskussion des Ansatzes

Positive Konsequenzen

Mit dem beschriebenen Ansatz lassen sich gleich drei Module in FLEXess von Code für redundante Funktionalität im Frontend befreien (games, players und play). Bei play ist es zudem nicht mehr erforderlich, dass es das JWT-Token im Browser per JavaScript auslesen kann. Das lässt sich nun verbieten („httpOnly“) und damit eine Sicherheitslücke schließen (siehe XSS-Angriff).

Chat

Der größte Vorteil ist sicher, wenn ein weiteres Modul hinzukommt, dass den Rahmen der Weboberfläche nutzen und sich in der Navigation einnisten möchte. Es ist nun erforderlich nur zwei Module anzupassen und neu zu deployen: das neue Modul selbst und das angepasste homepage-Modul. Vorher hättet Ihr alle Module anpassen müssen, in denen die Navigation auftaucht.

Änderungen im zentralen Design oder eine Aktualisierung der Bootstrap-Version sind nun auch an zentraler Stelle möglich. Ein einheitlichen Aussehen lässt sich ebenfalls leicht realisieren.

Und der Preis dafür

Doch es gibt auch Nachteile. Einzelne Module können nun eben keine unterschiedlichen Bibliotheksversionen mehr im Frontend benutzen, und verlieren an Freiheit. Die Anwendung lässt sich nicht mehr schrittweise umstellen (falls gewünscht). Falls unterschiedliche Teams für die Module verantwortlich sind entstehen Abhängigkeiten zwischen diesen.

Zum Testen eines Moduls selbst ist zumindest für die Weboberfläche nun eine weitere Komponente erforderlich, die sich um SSI kümmert. Ansonsten fehlt die Navigation und das Ganze ist sehr trist. Dazu benötigt das zuständige Team nicht das ganze Modul-Arsenal. Es reicht ein nginx, der statische Inhalte einfügt, wenn der Test die Dynamik in der Navigation und im Footer nicht erfordert.

Muss es zentral sein?

Tatsächlich könnte ein Team auf den zentralen SSI-Ansatz für seine Module auch verzichten. Es liefert die betreffenden Schnipsel selbst und erhält sich so seine Freiheit. Das homepage-Modul würde dann als Vorschlag oder Angebot angesehen, nicht als Teil der Makro-Architektur. Auf dieser Weise bleibt Teams die Möglichkeit, neue Dinge einfach auszuprobieren in diesem Bereich. Auf Kosten des Mehraufwandes (für das Team). Und mitunter auch auf Kosten der Konsistenz der Oberfläche (für die Gesamtanwendung).

Wie es weiter geht …

Ein Blick auf den Bauplan verrät: Mittlerweile haben wir fast alle Teile beisammen. Was noch fehlt ist der mobile Client. Weiterhin möchte ich ein paar querschnittliche Themen rund um den Betrieb diskutieren (Deployment, Monitoring, Tracing, Logging …). Bleibt also spannend.

Fragen und Anregungen sind natürlich jederzeit willkommen. Per Kommentar hier im Blog oder gerne auch per Maildirekt an mich …