Java Magazin   12.2015 - Technische Schulden

Erhältlich ab:  November 2015

Autoren / Autorinnen: 
Niko Köbler ,  
,  
Sebastian Meyen ,  
Arno Haase ,  
Dierk König ,  
Michael Müller ,  
Lars RöwekampSven Kölpin ,  
Oliver Wronka ,  
Peter Roßbach ,  
Thorben JanssenAnatole Tresch ,  
Frank WisniewskiLars PfannenschmidtTobias Ullrich ,  
Carola Lilienthal ,  
Daniel Takai ,  
Gerrit Brehmer ,  
Klaus KreftAngelika Langer ,  
Sven Hofrichter ,  
Dominik Obermaier ,  
Michael Gruczel ,  
Stefan Toth ,  
Gabriele HeimannSebastian RothbucherHolger Endres

Der Herbst hat wieder einige interessante Gerüchte zur Zukunft Javas hervorgebracht. Rechtzeitig vor der JavaOne (die ja in dem Moment, da Sie dieses Heft in Händen halten, schon wieder vorüber sein wird) kolportierten mehrere Medien, dass Oracle beginne, sein Interesse an Java zu verlieren. Genauer gesagt: an seiner Rolle als „Steward of Java“, wie sich die Ellison-Company (bislang) gerne bezeichnet.

Nun ist es so, dass bei Oracle seit einem guten Jahr nicht mehr Gründer Larry Ellison regiert, sondern die reinen Businessleute Mark Hurd und Safra Catz. In diesem Zusammenhang würde es nicht verwundern, wenn in dem Unternehmen so manches auf den Prüfstand gestellt würde – so eventuell auch die Weiterentwicklung von Java.

Im Oktober 2014 hat die Oracle-Führung außerdem ihre neue Cloud-Strategie vorgestellt, die zur tragenden Säule für das Unternehmen werden soll – knapp zehn Jahre nachdem Amazon mit AWS debütierte. Hinzukommt, dass der allgemeine Trend zur Cloud für Java noch eine ganz andere Konsequenz haben könnte: Je höherwertiger die Services sind, die von den Cloud-Plattformen angeboten werden und je deutlicher diese ihre Komfort- und Kostenvorteile für Entwickler und Operations-Leute ausspielen, desto mehr gerät die Idee offener Standards, die ja stets zum Markenkern Javas gehörte, in den Hintergrund. Machen wir uns nichts vor: Die beeindruckenden Produktivitätsvorteile der Clouds werden in Zukunft zumindest teilweise durch einen höheren „Vendor Lock-in“, den die Java-Welt ja stets wie der Teufel das Weihwasser scheute, erkauft werden.

Java befindet sich indes mittlerweile in einem „Maintenance Mode“ – die Zeiten furioser Innovationsfeuerwerke ist vorüber. Das macht aber auch seinen Reiz aus, denn als stabile technische Grundlage (für deren Konsolidierung und Weiterentwicklung sich Oracle ohne Zweifel verdient gemacht hat!) versetzt es innovative Firmen in die Lage, ihre Erfindungen auf eine erprobte – und immer noch coole! – Plattform zu stellen.

Als Plattform und nicht nur als Programmiersprache betrachtet, ist Java mit das Ausgereifteste, was die Softwareindustrie zu bieten hat. Es bildet das Betriebssystem für so viele kleine und große Unternehmen weltweit, dass ein Stillstand nicht denkbar wäre. Selbst ganze Staaten, multinationale Organisationen oder militärische Allianzen vertrauen ihr Geschäft Java an.

Java ist „too big to fail“. Darum wird die Geschichte Javas weitergehen, was auch immer Oracle in nächster Zeit entscheiden sollte (wohlgemerkt: zum Zeitpunkt des Verfassens dieser Zeilen ist noch gar nichts entschieden).

Blicken wir also optimistisch und in vollem Vertrauen auf die Innova­tionskraft des gesamten Ökosystems in die Zukunft von Java!

In diesem Sinne wünsche ich Ihnen wunderschöne Feiertage und einen kraftvollen Start ins nächste Java-Jahr!

meyen_sebastian_sw.tif_fmt1.jpgSebastian Meyen, Chefredakteur

Website Twitter Google Xing

Noch vor wenigen Jahren von vielen Enterprise-Entwicklern als Unheil bringendes Voodoo abgetan, gewinnt JavaScript in modernen Webanwendungen mehr und mehr an Bedeutung. Entsprechend groß ist auch der Zoo an wunderverheißenden Frameworks, aus denen es das passende zu wählen gilt. Wie so oft im Leben gilt leider auch hier: „Wer die Wahl hat, hat die Qual“.

Neulich auf dem Firmenflur: Mein Kollege Sven Kölpin – seines Zeichens „gebürtiger“ Enterprise-Web-Developer – und ich unterhalten uns über die Wahl des „richtigen“ JavaScript-Frameworks. Ein Gespräch, das meinen Horizont und meine Toleranz gegenüber JavaScript deutlich erweitert hat und das ich deshalb auch den Lesern dieser Kolumne nicht vorenthalten möchte.

Fancy UI vs. Single-Page-App

Als Enterprise-Entwickler bin ich es gewohnt, eher in Dekaden als in Monaten zu rechnen. Hat man sich einmal für eines der etablierten Frameworks, wie Java EE oder Spring, entschieden, kann man relativ sicher sein, dass es dieses auch in den kommenden Jahren noch geben wird. Anders dagegen im Dschungel der JavaScript-Frameworks – oder wer erinnert sich noch an die Marktführer von 2010: Prototype UI und script.aculo.us. Wie also wähle ich das passende Framework und wie stelle ich sicher, dass mich die Wahl nicht über kurz oder lang in eine Sackgasse führt?

Zunächst einmal muss ich für mich die Frage klären, was ich mit dem Framework überhaupt erreichen möchte. Geht es eher um UI-Effekte, wie zum Beispiel Drag and Drop und Pop-up-Dialoge, oder soll eine Single Page Web Application (SPA) erstellt werden, deren Logik zu großen Teilen auch direkt auf dem Client ausgeführt wird. Im ersten Fall steht die Manipulation des DOM-Baums im Vordergrund, im zweiten Fall wird das JavaScript auch zur Umsetzung von Businesslogik herangezogen. Der Trend geht dabei mittlerweile mehr und mehr zu SPAs über.

Serverseitiges Rendering plus fancy UI

Serverseitiges Rendering ist der traditionelle Weg, Webanwendungen zu entwickeln. Über die letzten Jahre sind mit Frameworks wie JSF in diesem Bereich recht solide Werkzeuge entstanden. Diese Art der Entwicklung bietet vor allem einen riesigen Vorteil: Abstrak­tion. Webanwendungen können häufig ohne tiefgehende Kenntnisse über die eigentlichen Webtechnologien geschrieben werden.

Die Entwicklung von serverseitig gerenderten Webanwendungen bedeutet heutzutage aber keinesfalls mehr, dass ein Benutzer am Ende mit einer statischen 90er-Jahre-Webseite konfrontiert wird. Vielmehr entwickelt man „Rich Internet Applications“, also Webanwendungen, die ein aus Desktopanwendungen bekanntes Interaktionsverhalten ermöglichen, aber eben im Browser laufen. Wie das? Das desktopähnliche Verhalten erreicht man über den Einsatz von JavaScript und Ajax. Die Rolle von JavaScript ist hierbei in erster Linie die Manipulation des DOM-Baums, um so eine interaktive Benutzeroberfläche zu schaffen (Dialoge, Drag and Drop, ...). Der Einsatz der Bibliotheken jQuery und jQuery-UI hat sich hierbei zum Quasistandard entwickelt. Durch die zusätzlichen Abstraktionsebenen der serverseitigen Frameworks (z. B. Primefaces für JSF) hat der Entwickler aber in der Regel keine direkte Berührung mit den Webtechnologien und den unter der Haube verwendeten JavaScript-Bibliotheken.

Trotz teilweise recht großer JavaScript-Codebasis wird JavaScript bei diesem Ansatz nahezu ausschließlich zur Umsetzung von View-Logik – meist realisiert durch gekapselte jQuery-Funktionen – verwendet. Weil die Komplexität von JavaScript bei der serverseitigen Entwicklung also eher überschaubar ist, wird das ganze Thema häufig stiefmütterlich behandelt, oder eben wie im Falle von JSF komplett in externe Bibliotheken ausgelagert. JavaScript ist bei der serverseitigen Entwicklung eher ein Nebenprodukt als ein ernstgenommener Bestandteil der Anwendung.

SPA aka clientseitiges Rendering

So weit, so gut? Was ist nun aber bei Single Page Web Applications anders? SPAs sind die nächste Evolutionsstufe von Webanwendungen. Sie bestehen nur aus einer einzigen HTML-Seite, deren Inhalt bei Bedarf dynamisch nachgeladen wird. Die Rolle von JavaScript hat sich hierbei drastisch geändert: Es steht nun nicht mehr die DOM-Manipulation, sondern die Umsetzung von Businesslogik im JavaScript-Code im Vordergrund. Der Server dient nur noch als zentraler Datenspeicher und wird in den meisten Fällen statuslos implementiert (RESTful-Ansatz). Da der Server also nur noch Datenlieferant ist und nicht mehr die Aufgabe des Erzeugens von HTML-Fragmenten übernimmt, muss auch dieser Teil vom JavaScript-Code im Browser übernommen werden (z. B. das Erzeugen einer HTML-Tabelle aus Kundendaten). Aus diesem Grund spricht man hier vom clientseitigen Rendering.

Diese veränderte, viel bedeutsamere Rolle von JavaScript hat Auswirkungen auf den gesamten Entwicklungsprozess und birgt eine Menge neue Herausforderungen. Am wichtigsten ist die Auswahl des passenden SPA-Frameworks, was sich leider nicht als trivial erweist.

Das größte Problem ist die Kurzlebigkeit und die damit verbundene Hypegefahr in diesem Bereich. Anders als beim serverseitigen Ansatz ist die Entwicklung von rein clientseitigen Webanwendungen eine noch recht junge Disziplin, weshalb hier ein riesiges Entwicklungspotenzial vorliegt. Aus diesem Grund konnte sich in den letzten fünf Jahren keines der vorhandenen SPA-Frameworks eindeutig durchsetzen. Zwar hat Google mit AngularJS kurzfristig den Anschein erweckt, endlich eine solide Lösung am Markt zu etablieren. Dieser Trend ist aber seit der Veröffentlichung von ReactJS (Facebook) wieder stark rückläufig. Das hat vor allem zwei Gründe. Erstens wird es mit der nächsten Version von AngularJS (2.0) keine hundertprozentige Rückwärtskompatibilität zu den Vorgängerversionen geben, was die vorhandene Nutzerbasis selbstverständlich stark verunsichert hat. Zweitens liefert ReactJS ein revolutionäres (HTML in JavaScript) und performantes (Virtual DOM) Programmiermodell, das eine viel geringere Komplexität und Lernkurve als AngularJS aufweist. Deshalb ist es nicht unwahrscheinlich, dass sich die Community in den nächsten Jahren eher in Richtung von ReactJS orientieren wird. Es bleibt in jedem Fall festzuhalten, dass sich die Schnelllebigkeit der SPA-Frameworks vermutlich auch in den nächsten Jahren noch nicht wesentlich verändern wird. Die Umsetzung rein clientseitiger Lösungen, vor allem im Bereich von Enterprise Applications, ist also zum aktuellen Zeitpunkt noch mit einem gewissen Risiko verbunden.

Umdenken ist angesagt

Die Entwicklung von Single Page Applications erfordert ein Umdenken im bisher gewohnten Entwicklungsprozess. Wie eingangs erwähnt, ist JavaScript bei SPAs ein Hauptbestandteil der Entwicklung und kein Nebenprodukt, das unter Umständen sogar vor dem Entwickler versteckt werden kann. Die Auswirkungen dieser Tatsache sind weitreichend und fangen bei der Teamzusammensetzung an. In den seltensten Fällen gibt es im Team bereits Experten im Bereich von SPAs und selbst wenn, reicht die Erfahrung durch die erwähnte Schnelllebigkeit der Frameworks meistens nur auf wenige Jahre zurück. Auch die Lernkurve für JavaScript als solches darf nicht unterschätzt werden. Die Sprache erlaubt aufgrund ihrer Dynamik extrem viel, was bei wenig erfahrenen Entwicklern häufig zu unerwarteten Nebeneffekten führt. Die neue JavaScript-Version (ECMAScript 2015) verspricht zwar durch zusätzliche Sprachfeatures einen einfacheren Einstieg, nichtsdestotrotz müssen grundlegende Konzepte neu erlernt werden. Bei der Projektplanung für eine SPA müssen diese Tatsachen unbedingt berücksichtigt werden, weil die Menge der technisch bedingten Probleme mit hoher Wahrscheinlichkeit ansteigen wird. Auch langjährige Entwickler sind im Bereich der Single Page Applications heutzutage häufig eher Pioniere als erfahrener Senior Developer.

Die neue Rolle von JavaScript hat auch Auswirkungen auf andere Bereiche der täglichen Entwicklung. Die tragende Rolle des Frontend-Codes erfordert eine feste Integration in den Build-Lifecycle. Hier müssen geeignete Tools (Grunt, gulp, Webpack …) evaluiert werden. Ähnlich wie bei den SPA-Frameworks gibt es auch in diesem Bereich noch keine Patentlösung, sondern lediglich Trends und Ideen. Nicht unerwähnt soll an dieser Stelle das Thema Testen bleiben – die hierfür existierenden Tools sind mittlerweile mindestens auf dem gleichen Level, wie man es aus Java gewohnt ist. Zusätzlich bieten die meisten SPA-Frameworks extrem gute Möglichkeiten, testbaren Code zu entwickeln.

SPA-konforme Architekturen

Neben den Veränderungen im Frontend hat die Entwicklung von SPAs auch Auswirkungen auf die Gesamtarchitektur einer Anwendung. Auf der Serverseite müssen idealerweise saubere RESTful-APIs zur Verfügung gestellt werden. Diese sind häufig Grundvoraussetzung für ein problemloses Zusammenspiel zwischen Server und SPA-Framework. Die Entwicklung einer richtigen RESTful-Architektur ist für unerfahrene nicht trivial, weil man nicht service-, sondern ressourcenorientiert denken muss. Zusätzlich erzeugen Themen wie Validierung und Authentifizierung neue Herausforderungen.

Eine letzte zu erwähnende Herausforderung bei der Verlagerung des Renderings auf die Clientseite ist das Thema Performanz. Wie eingangs erwähnt, werden bei SPAs die Ansichten (das HTML) erst im Browser generiert, was bei dem Benutzer häufig den Eindruck eines langsamen ersten Seitenaufbaus bewirkt. Um diesem Problem entgegenzuwirken, wird die initiale Seite einer SPA häufig auf dem Server vorgerendert, sodass beim ersten Request stets eine fertige HTML-Seite an den Client übermittelt wird. Auf dieser setzt ein SPA-Framework dann im zweiten Schritt auf. Der Nachteil dieses Ansatzes: Es muss serverseitig JavaScript-Code ausgeführt werden (z. B. mit Node.js oder in Java mit Nashorn), was eine weitere technische Komplexitätsstufe in ein Projekt bringt. Allerdings lassen sich durch das initiale serverseitige Rendering auch weitere Herausforderungen von SPAs, zum Beispiel Search Engine Optimization (SEO) oder Seitencaching, leichter lösen.

Fazit

Moderne Webanwendungen ohne JavaScript sind heute kaum noch vorstellbar. Bei der Wahl des richtigen Frameworks gilt es zunächst einmal zwischen „Fancy UI“ und „Single Page Web Application“ zu unterscheiden. Hat man sich für eine der beiden Varianten entschieden und ein scheinbar passendes Framework gefunden, sollte man zusätzlich die Performanz und Testbarkeit hinterfragen, um auch langfristig mit dem Framework glücklich zu werden.

Abschließend ist auf jeden Fall auch ein tieferer Blick auf die zum Framework zugehörige Community und deren Aktivität zwingend erforderlich. Eine große und aktive Community ist zwar noch kein Garant für ein langlebiges Framework, erhöht aber auf jeden Fall die Chancen.

Als Fazit kann festgehalten werden, dass wir uns derzeit am Anfang einer sehr spannenden Entwicklung befinden. Sowohl mein Kollege Sven Kölpin als auch ich sind uns sicher, dass wir in den kommenden Monaten noch viel Positives im Umfeld der JavaScript-Frameworks erwarten dürfen. In diesem Sinne: Stay tuned ...

roewekamp_lars_sw.tif_fmt1.jpgLars Röwekamp ist Geschäftsführer der open knowledge GmbH und berät seit mehr als zehn Jahren Kunden in internationalen Projekten rund um das Thema Enterprise Computing.

Twitter

koelpin_sven_sw.tif_fmt1.jpgSven Kölpin ist Enterprise-Entwickler, Speaker und Autor bei der open knowledge GmbH in Oldenburg. Schwerpunkt und Leidenschaft ist die Konzeption und Entwicklung von Webanwendungen.

Die wenigsten Entwicklungsteams haben heute noch die Chance, ein komplett neues System „from scratch“ zu entwickeln. Meistens stehen wir vor der Herausforderung, ein bestehendes, über Jahre gewachsenes System zu warten und auszubauen. Damit das auf Dauer gelingen kann, brauchen wir eine qualitativ hochwertige und flexible Architektur mit möglichst wenig technischen Schulden.

Sind die technischen Schulden gering, dann finden sich die Wartungsentwickler gut im System zurecht. Sie können schnell und einfach Bugs fixen und haben keine Probleme, kostengünstig Erweiterungen zu machen. Wie kommen wir in dieses gelobte Land der Architekturen mit reduzierten Schulden?

Technische Schulden

Wurde zu Beginn eines Softwareentwicklungsprojekts eine gute Architektur entworfen, dann kann man davon ausgehen, dass das Softwaresystem sich am Anfang schnell warten lässt. In diesem Anfangsstadium befindet sich das Softwaresystem in einem Korridor hoher Architekturqualität ohne technische Schulden (Abb. 1). Die technischen Schulden, von denen ich in diesem Artikel spreche, sind Schulden, die die Entwicklungsteams daran hindern, Fehler schnell zu finden und Änderungen kostengünstig durchzuführen. Diese technischen Schulden finden sich in der statischen Struktur des Softwaresystems. Andere technische Schulden, wie Performance- oder Securityprobleme, werden hier nicht betrachtet.

lilienthal_technische_schulden_1.tif_fmt1.jpgAbb. 1: Entstehung von Architekturerosion

Wird das System nun erweitert oder werden Fehler gefixt, so wird die Architekturqualität ein wenig schlechter (gelbe Pfeile in Abbildung 1). Diese Verschlechterung ist ganz normal. Softwareentwicklung ist ein ständiger Lernprozess, bei dem der erste Wurf einer Lösung in der Regel mehrfach überarbeitet werden muss, bis er sitzt. Diese Überarbeitung der Architektur (Architekturerneuerung, grüne Pfeile in Abbildung 1) muss in regelmäßigen Abständen durchgeführt werden, damit das System seinen hohen Qualitätsstandard beibehält. Es entsteht so eine stetige Folge von Erweiterung und Refactoring.

Behält man die Architekturqualität nicht ständig im Auge, so wird im Laufe der Zeit Architekturerosion einsetzen. Über kurz oder lang verlässt das Softwaresystem den Korridor guter Architekturqualität (rote Pfeile in Abbildung 1). Die Architektur erodiert, und es entstehen immer mehr technische Schulden. Die Ursachen dieses Erosionsprozesses sind vielfältig: Aufgrund von Zeitdruck müssen wir Hacks in unser System einbauen, obwohl wir wissen, dass die Architektur eigentlich ganz anders aussehen müsste. Die Komplexität und der Kopplungsgrad in der Software wachsen unbemerkt, weil wir beim Entwickeln nicht darauf achten (können). Wir haben keine Zeit für Architekturdiskussionen, und so fehlt uns das nötige Architekturverständnis.

Befinden wir uns erst einmal auf dem absteigenden Ast der technischen Schulden, so werden Wartung und Erweiterung der Software immer teurer bis zu dem Punkt, an dem jede Änderung zu einer schmerzhaften Anstrengung wird. Abbildung 1 macht diesen langsamen Verfall dadurch deutlich, dass die roten Pfeile immer kürzer werden. Pro Zeiteinheit kann man bei steigenden Schulden immer weniger Funktionalität umsetzen. Änderungen, die früher einmal an einem Personentage möglich waren, dauern jetzt doppelt bis dreimal so lange. Die Software wird fehleranfällig, schwer änderbar und teuer. Um aus diesem Dilemma der technischen Schulden herauszukommen, muss die Architekturqualität rückwirkend wieder verbessert werden. Auf diesem Weg muss das System Schritt für Schritt wieder in den Korridor hoher Architekturqualität zurückgebracht werden (s. rote aufsteigende Pfeile in Abbildung 1).

Natürlich kann es auch passieren, dass zu Beginn der Entwicklung kein fähiges Team vor Ort war und das Softwaresystem ohne Architektur oder mit einer rudimentären Architekturvorstellung entwickelt wurde. In einem solchen Fall wächst die Architektur im Laufe der Zeit ohne Plan vor sich hin. Technische Schulden werden in diesem Fall gleich zu Beginn der Entwicklung aufgenommen und kontinuierlich erhöht. Über solche Softwaresysteme kann man wohl sagen: Sie sind unter schlechten Bedingungen aufgewachsen. Auch in diesem Fall ist es die Mühe wert, das Softwaresystem von technischen Schulden zu befreien. Die Alternative Neuimplementierung steht den meisten Firmen aufgrund der hohen Investitionen heute oft nicht zur Verfügung.

Architekturanalyse und -verbesserung

Um technische Schulden zu reduzieren, ist es sinnvoll, regelmäßig zu überprüfen, ob die geplante Architektur im Sourcecode tatsächlich umgesetzt worden ist. Für solche Soll-/Istvergleiche stehen heute eine Reihe guter Tools zur Verfügung: Sotograph, SonarQube, J/N/PHP_Depend, Axovion Bauhaus, Structure101, Lattix, Teamscale, Software Diagnostics u. v. m. In meinen Analysen arbeite ich mit dem Sotographen, von dem sie in diesem Artikel einige Grafiken sehen werden.

Die Sollarchitektur ist der Plan für die Architektur, der auf Papier oder in den Köpfen der Architekten und Entwickler existiert (Abb. 2). Dieser Plan ist eine Abstraktion und Vereinfachung des Sourcecodes. Häufig wird er bereits vor Beginn der Implementierung erstellt und im Laufe der Zeit an die Gegebenheiten angepasst. In der Sollarchitektur werden die Klassen und Pakete zu Subsystemen, Komponenten, Modulen (je nachdem, welchen Begriff man wählt) und Schichten zusammengefasst. Im weiteren Artikel bezeichne ich alle diese Elemente als Bausteine.

lilienthal_technische_schulden_2.tif_fmt1.jpgAbb. 2: Soll-/Istvergleich der Architektur

Die Sollarchitektur wird bei der Architekturanalyse mit dem echten Sourcecode abgeglichen. Der Sourcecode enthält die implementierte Istarchitektur. In allen mir bekannten Fällen weicht die Istarchitektur von der Sollarchitektur ab. Die Ursachen dafür sind vielfältig und hängen oft auch mit Architekturerosion und technischen Schulden (s. o.) zusammen. Bei der Architekturanalyse und -verbesserung machen wir uns gemeinsam mit den Architekten und Entwicklern auf die Suche nach einfachen Lösungen, wie die Istarchitektur an die Sollarchitektur angeglichen werden kann. Oder aber wir diskutieren die geplante Sollarchitektur und stellen fest, dass die im Sourcecode gewählte Lösung besser ist. In diesem Fall muss der Plan der Sollarchitektur angepasst werden.

Neben diesem Abgleich zwischen Soll- und Istarchitektur besteht ein wichtiger Teil der Architekturanalyse darin, dass das Entwicklungsteam oder auch das Management wissen will, ob die gewählte Architektur gut wartbar ist. Um diese Frage zu beantworten, bediene ich mich bei meinen Analysen eines Modells, das ich auf Basis von Erkenntnissen aus der kognitiven Psychologie entwickelt habe.

Kognitive Psychologie als Basis der Bewertung

Das menschliche Gehirn hat sich im Laufe der Evolution einige beeindruckende Mechanismen angeeignet, die uns beim Umgang mit komplexen Strukturen helfen. Diese Mechanismen gilt es in Softwaresystemen zu nutzen, damit Wartung und Erweiterung schnell und ohne viele Fehler von der Hand gehen. Das Ziel ist dabei, dass wir unsere Softwaresysteme auch mit sich verändernden Entwicklungsteams lange bei gleichbleibender Qualität weiterentwickeln können. Die drei Mechanismen, die unser Gehirn für komplexe Strukturen entwickelt hat, sind (Abb. 3): Chunking, Bildung von Hierarchien und Aufbau von Schemata. Diese Mechanismen haben direkte Abbilder in Kriterien für die Architektur.

lilienthal_technische_schulden_3.tif_fmt1.jpgAbb. 3: Kognitive Mechanismen und ihr Abbild in Architektur

Aufbau von Schemata und Musterkonsistenz

Der effizienteste Mechanismus, den Menschen einsetzen, um komplexe Zusammenhänge zu strukturieren, sind so genannte Schemata. Unter einem Schema werden Wissenseinheiten verstanden, die aus einer Kombination von abstraktem und konkretem Wissen bestehen. Ein Schema besteht auf der abstrakten Ebene aus den typischen Eigenschaften der von ihm schematisch abgebildeten Zusammenhänge. Auf der konkreten Ebene beinhaltet ein Schema eine Reihe von Exemplaren, die prototypische Ausprägungen des Schemas darstellen. Jeder von uns hat beispielsweise ein Lehrerschema, das abstrakte Eigenschaften von Lehrern beschreibt und als prototypische Ausprägungen Abbilder unserer eigenen Lehrer umfasst.

Haben wir für einen Zusammenhang in unserem Leben ein Schema, so können wir die Fragen und Probleme, mit denen wir uns gerade beschäftigen, sehr viel schneller verarbeiten als ohne Schemata. Schauen wir uns ein Beispiel an: Bei einem Experiment wurden Schachmeistern und Schachanfängern für ca. fünf Sekunden Spielstellungen auf einem Schachbrett gezeigt. Handelte es sich um eine sinnvolle Aufstellung der Figuren, so waren die Schachmeister in der Lage, die Positionen von mehr als zwanzig Figuren zu rekonstruieren. Sie sahen Muster von ihnen bekannten Aufstellungen und speicherten sie in ihrem Kurzzeitgedächtnis. Die schwächeren Spieler hingegen konnten nur die Position von vier oder fünf Figuren wiedergeben. Die Anfänger mussten sich die Position der Schachfiguren einzeln merken. Wurden die Figuren den Schachexperten und Schachlaien allerdings mit einer zufälligen Verteilung auf dem Schachbrett präsentiert, so waren die Schachmeister nicht mehr im Vorteil. Sie konnten keine Schemata einsetzen und sich so die für sie sinnlose Verteilung der Figuren nicht besser merken.

Die in der Softwareentwicklung vielfältig eingesetzten Entwurfsmuster nutzen die Stärke des menschlichen Gehirns, mit Schemata zu arbeiten. Haben Entwickler bereits mit einem Entwurfsmuster gearbeitet und daraus ein Schema gebildet, so können sie Programmtexte und Strukturen schneller erkennen und verstehen, die dieses Entwurfsmuster einsetzen. Der Aufbau von Schemata liefert für das Verständnis von komplexen Strukturen also entscheidende Geschwindigkeitsvorteile. Das ist auch der Grund, warum Muster in der Softwareentwicklung bereits vor Jahren Einzug gefunden haben.

Muster kann man bei der Architekturanalyse nicht messen, aber man kann sie sichtbar machen und ihre Umsetzung diskutieren. Ich untersuche einerseits die Muster auf der Architekturebene an und andererseits die Muster auf der Klassenebene. Auf beiden Ebenen ist für die Entwickler und Architekten wichtig, dass es Muster gibt, dass sie im Sourcecode wiederzufinden sind und dass sie einheitlich und durchgängig eingesetzt werden. Deshalb verwende ich für diesen Bereich den Begriff „Musterkonsistenz“.

Mangelnde Musterkonsistenz weist beispielweise Abbildung 4 auf. In der Abbildung sieht man den Pa­ckage-Baum eines Java-Systems. Die Pfeile gehen jeweils vom übergeordneten Package zu seinen Kindern. Das System ist in vier Komponenten aufgeteilt, die im Package-Baum durch vier Farben markiert sind. An den gestrichelten Linien ist zu erkennen, dass zwei der Komponenten (orange und lila) über den Package-Baum verteilt sind. Diese Verteilung ist nicht konsistent zu dem von der Architektur vorgegebenen Muster und führt bei Entwicklern und Architekten zu Verwirrung. Das Einführen von jeweils einem Package-Root-Knoten für die orangene und die lila Komponente würde hier Abhilfe schaffen.

lilienthal_technische_schulden_4.tif_fmt1.jpgAbb. 4: Das Architekturmuster ist schlecht umgesetzt

Auf der Klassenebene werden heute in vielen Systemen Entwurfsmuster eingesetzt. Sie leiten die Entwickler noch stärker als die Muster auf Architekturebene. In Abbildung 5 sieht man ein anonymisiertes Tafelbild, das ich mit einem Team entwickelt habe, um seine Muster aufzunehmen. Auf der rechten Seite von Abbildung 5 ist der Sourcecode in diese Musterkategorien eingeteilt, und man sieht sehr viele grüne und einige wenige rote Beziehungen. Die roten Beziehungen gehen von unten nach oben gegen die durch die Muster entstehende Schichtung. Die geringe Anzahl der roten Beziehungen ist ein sehr gutes Ergebnis und zeugt davon, dass das Entwicklungsteam seine Muster sehr konsistent einsetzt. Spannend ist bei der Analyse noch, welchen Anteil des Sourcecodes man Mustern zuordnen kann und wie viele Muster das System schlussendlich enthält. Lassen sich 80 Prozent oder mehr des Sourcecodes Mustern zuordnen, so spreche ich davon, dass dieses System eine Mustersprache hat. Für die „richtige“ Anzahl an Mustern habe ich keine exakte Zahl. Wichtig ist vielmehr, dass die vorhandenen Muster tatsächlich unterschiedliche Konzepte darstellen und nicht Varianten eines Konzepts sind. Beispiele für solche Varianten könnten zum Beispiel zwei Muster sein, die „Service“ und „Manager“ heißen. Hier wäre zu klären, was den Manager von einem Service unterscheidet und in welchem Verhältnis sie zueinander stehen.

lilienthal_technische_schulden_5.tif_fmt1.jpgAbb. 5: Muster auf Klassenebene = Mustersprache

Die Untersuchung der Muster im Sourcecode ist in der Regel der spannendste Teil einer Architekturanalyse. Hier hat man die Ebene zu fassen, auf der das Entwicklungsteam wirklich arbeitet. Die Klassen, die die einzelnen Muster umsetzen, liegen oft über die Packages oder Directories verteilt. Mit einer Modellierung der Muster wie in Abbildung 5 rechts kann man diese Ebene der Architektur sichtbar und analysierbar machen.

Chunking und Modularität

Damit Menschen in der Menge der Informationen, mit denen sie konfrontiert sind, zurechtkommen, müssen sie auswählen und Teilinformationen zu größeren Einheiten gruppieren. Dieses Bilden von höherwertigen Abstraktionen, die immer weiter zusammengefasst werden, nennt man Chunking. Dadurch, dass Teilinformationen als höherwertige Wissenseinheiten abgespeichert werden, wird das Kurzzeitgedächtnis entlastet und weitere Informationen können aufgenommen werden. Chunking kann unser Gehirn allerdings nur dann anwenden, wenn die Teilinformationen eine sinnvolle zusammenhänge Einheit bilden. Bei unzusammenhängenden Informationen gelingt uns Chunking nicht.

Entwickler wenden Chunking automatisch an, wenn sie sich unbekannte Programme erschließen müssen. Der Programmtext wird im Detail gelesen, und die gelesenen Zeilen werden zu Wissenseinheiten gruppiert und so behalten. Schritt für Schritt werden die Wissenseinheiten immer weiter zusammengefasst, bis ein Verständnis des benötigten Programmtexts erreicht ist. Allerdings funktioniert auch bei Softwaresystemen das Chunking nur dann, wenn die Struktur des Softwaresystems sinnvoll zusammenhängende Einheiten darstellt. Programmeinheiten, die beliebige Operationen zusammenfassen, sodass für die Entwickler nicht erkennbar ist, warum sie zusammengehören, lassen sich nicht in Wissenseinheiten codieren. Für unsere wartbaren Softwarearchitekturen ist es also essenziell, dass sie Bausteine wie Klassen, Komponenten, Module, Schichten enthalten, die sinnvoll zusammenhängende Elemente gruppieren.

Ob die Bausteine in einer Softwarearchitektur zusammenhängende Elemente darstellen, lässt sich leider nicht messen oder mit Analysewerkzeugen überprüfen. Um bei der Analyse von Architekturen trotzdem Aussagen über die Modularität machen zu können, untersuche ich die folgenden Aspekte:

  • Entwurf nach Zuständigkeit: Sind die Bausteine eines Systems modular gestaltet, so sollte man für jeden Baustein die Frage beantworten können: Was ist seine Aufgabe? Der entscheidende Punkt dabei ist, dass der Baustein wirklich eine Aufgabe hat und nicht mehrere. Diese Frage ist natürlich nur im fachlichen Kontext des jeweiligen Systems gemeinsam mit dem Entwicklerteam zu klären. Anhaltspunkte bei der Suche nach Bausteinen mit unklarer Zuständigkeit sind:

    • Der Name des Bausteins – der Name eines Bausteins sollte seine Aufgabe beschreiben. Ist der Name schwammig, so sollte man ihn sich ansehen.

    • Seine Größe (s. nächster Punkt).

    • Der Umfang seiner Kopplung mit anderen Bausteinen – wird ein Baustein sehr viel von allen möglichen anderen Bausteinen verwendet, so liegt die Vermutung nahe, dass er ein Sammelbecken von vielfältigen nicht unbedingt zusammenhängenden Funktionalitäten ist.

    • Seine mangelnde Musterkonsistenz (s. Abschnitt „Aufbau von Schemata und Musterkonsistenz“).

  • Ausgewogene Größenverhältnisse: Bausteine, die auf einer Ebene liegen, also die Schichten, die fachlichen Module, die Packages, die Klassen oder die Methoden, sollten untereinander ausgewogene Größenverhältnisse haben. Hier lohnt es sich, die sehr großen Bausteine zu untersuchen, um festzustellen, ob sie Kandidaten für eine Zerlegung sind.

  • Zusammengehörigkeit durch Kopplung untereinander: Bausteine sollten Subbausteine enthalten, die zusammengehören. Eine Klasse sollte beispielsweise Methoden enthalten, die gemeinsam ein Ganzes ergeben. Dasselbe gilt für größere Bausteine, wie Packages, Komponenten, Module und Schichten. Haben die Subbausteine mehr mit anderen Bausteinen zu tun als mit ihren „Schwestern und Brüdern“, dann stellt sich die Frage, ob sie nicht eigentlich in einen anderen Baustein gehören.

Bildung von Hierarchien und Hierarchisierung

Hierarchien spielen beim Wahrnehmen und Verstehen von komplexen Strukturen und beim Abspeichern von Wissen eine wichtige Rolle. Menschen können Wissen dann gut aufnehmen, es wiedergeben und sich darin zurechtfinden, wenn es in hierarchischen Strukturen vorliegt. Untersuchungen zum Lernen von zusammengehörigen Wortkategorien, zur Organisation von Lernmaterialien, zum Textverstehen, zur Textanalyse und zur Textwiedergabe haben gezeigt, dass Hierarchien vorteilhaft sind. Bei der Reproduktion von Begriffslisten und Texten war die Gedächtnisleistung der Versuchspersonen deutlich höher, wenn ihnen Entscheidungsbäume mit kategorialer Unterordnung angeboten wurden. Lerninhalte wurden von den Versuchspersonen mithilfe von hierarchischen Kapitelstrukturen oder Gedankenkarten deutlich schneller gelernt. Lag keine hierarchische Struktur vor, so bemühten sich die Versuchspersonen, den Text selbstständig hierarchisch anzuordnen. Die kognitive Psychologie zieht aus diesen Untersuchungen die Konsequenz, dass hierarchisch geordnete Inhalte für Menschen leichter zu erlernen und zu verarbeiten sind und dass aus einer hierarchischen Struktur effizienter Inhalte abgerufen werden können.

Die Bildung von Hierarchien wird in Programmiersprachen bei den Enthalten-Seins-Beziehungen unterstützt: Klassen sind in Packages, Packages wiederum in Packages und schließlich in Projekten bzw. Build-Artefakten enthalten. Diese Hierarchien passen zu unseren kognitiven Mechanismen. Sind die Hierarchien an die Muster der Architektur angelehnt, so unterstützen sie uns nicht nur durch ihre hierarchische Strukturierung, sondern sogar noch durch Architekturmuster.

Für alle anderen Arten von Beziehungen gilt das nicht: Wir können beliebige Klassen und Interfaces in einer Sourcecode-Basis per Benutzt-Beziehung oder/und per Vererbungsbeziehung miteinander verknüpfen. Dadurch erschaffen wir verflochtene Strukturen (Zyklen), die in keiner Weise hierarchisch sind. Es bedarf einiges an Disziplin und Anstrengung, Benutzt-Beziehung und Vererbungsbeziehung hierarchisch zu verwenden. Verfolgen die Entwickler und Architekten von Anfang an dieses Ziel, so sind die Ergebnisse in der Regel nahezu zyklenfrei.

In meinen Analysen bekomme ich die ganze Bandbreite von sehr wenigen zyklischen Strukturen bis zu großen zyklischen Monstern zu Gesicht. Ähnlich wie bei den Mustern und der Modularität kann man Zyklen auf Architekturebene und auch Klassenebene untersuchen.

In Abbildung 6 sieht man vier technische Schichten eines kleinen Anwendungssystems (80 000 LOC). Zwischen den Schichten haben sich einige Rückreferenzen (rote Bögen) eingeschlichen, die zu Zyklen führen. Die Zyklen in Abbildung 6 werden nur durch sechzehn Klassen hervorgerufen und lassen sich in diesem Fall leicht ausbauen. Abbildung 6 stellt also eine gut gelungene Schichtenarchitektur dar.

lilienthal_technische_schulden_6.tif_fmt1.jpgAbb. 6: Zyklen auf Architekturebene

Der Klassenzyklus in Abbildung 7 stammt von einem anderen System. Die 242 Klassen in diesem Zyklus sind über achtzehn Verzeichnisse verteilt. Jedes Verzeichnis ist in Abbildung 7 mit einer anderen Farbe vertreten.

lilienthal_technische_schulden_7.tif_fmt1.jpgAbb. 7: Zyklus aus 242 Klassen

Insgesamt hat das System, aus dem der Zyklus in Abbildung 7 stammt, 479 Klassen. Hier brauchen sich also über die Hälfte aller Klassen (242) direkt oder indirekt. Noch dazu hat dieser Zyklus eine starke Konzentration im Zentrum und wenige Satelliten. Eine natürliche Möglichkeit, ihn anhand von Kopplungszentren zu zerlegen, bietet sich also nicht an. Zum Glück finden sich in den meisten Systemen kleinere und weniger konzentrierte Zyklen, die man mit wenigen Refactorings zerlegen kann.

Zusammenfassung

In diesem Artikel haben Sie einen ersten Eindruck bekommen, wie technische Schulden in Architekturen entstehen und wie man sie reduzieren kann. Technische Schulden lassen sich abbauen, indem man Strukturen schafft, die unser Gehirn leicht verarbeiten kann. Hat man die Architektur in diese Richtung verbessert, so geht Wartung und Erweiterung effizienter und schneller von der Hand. Weitere Details zur Analyse von technischen Schulden und architekturverbessernden Refactorings finden Sie in meinem Buch „Langlebige Softwarearchitekturen“ vom dpunkt.verlag.

lilienthal_carola_sw.tif_fmt1.jpgDr. Carola Lilienthal ist Senior-Softwarearchitektin bei der Workplace Solutions GmbH und Mitglied der Geschäftsleitung. Sie hat an der Universität Hamburg studiert und dort zum Thema „Komplexität von Softwarearchitekturen“ promoviert. Seit 2003 analysiert sie im Auftrag ihrer Kunden in ganz Deutschland regelmäßig die Architektur von Softwaresystemen und fasst das Ergebnis in Qualitätsgutachten sowie mit priorisierten Refactoring-Maßnahmen zusammen. Außerdem leitet sie seit 2000 Softwareprojekte von unterschiedlicher Größe im Banken-/Versicherungs- und Logistikbereich und berät das Management kleiner und mittelständischer Unternehmen bei der Entwicklung einer modernen IT-Strategie.

Software besteht aus dem reinsten Werkstoff: unseren Gedanken. Aus diesem Grund ist sie unsichtbar, und wir müssen Anstrengungen unternehmen, um sie fassbar zu machen. In der Architektur gibt es hierfür zwei Qualitätsmerkmale: die Analysierbarkeit und die Prüfbarkeit. Die Analyse wird für die Entwicklung und Dokumentation des Systems benötigt. Die Prüfbarkeit hingegen findet zur Laufzeit statt. In diesem Artikel wird die Prüfbarkeit beschrieben, nachdem sich der letzte Artikel bereits mit der Analysierbarkeit beschäftigte.

Die Prüfbarkeit beschreibt den Grad an Immanenz, den ein System zur Laufzeit aufweist. Je besser die Prüfbarkeit, desto leichter ist es, Daten über ein System zu sammeln und auszuwerten. Die systematische Beobachtung von Komponenten nennt man Monitoring. Monitoring ist schwierig und kann nur mit speziellen Monitoringsystemen durchgeführt werden. Die Implementierung und der Betrieb dieser Systeme kosten, und Ausgaben in dieser Richtung haben bei den meisten Stakeholdern, insbesondere den Sponsoren zu Beginn eines Projekts, nur selten hohe Priorität. Dabei ist Monitoring aus verschiedenen Gründen wichtig:

  • Ausfälle eines Systems sollen im Betrieb frühzeitig, falls möglich bereits vor dem Ausfall (proaktiv), erkannt werden können, zum Beispiel bevor die Festplatte vollläuft.

  • Erkenntnisse über das Systemverhalten sollen gesammelt werden, damit notwendige Änderungen an der Architektur erkannt werden können. Vor allem Performance und Kapazität können so dem tatsächlichen Bedarf angepasst werden.

  • Die Geschäftszielerreichung eines Systems soll messbar gemacht werden, beispielsweise um den Nutzen einer Investition nachzuweisen.

  • Die Erfüllung von Service Level Agreements (SLAs) kann bewiesen werden.

  • Intrusion-Detection-Systeme können für den Zugriffsschutz eingesetzt werden.

Monitoring besteht aus der Messung der Zustandsänderungen und Datenflüsse in einem System. Zustandsänderungen können direkt gemessen werden. Datenflüsse zwischen Komponenten werden per Logeintrag gemessen [1]. Ein Monitoringsystem weist die gleichen Qualitätsmerkmale auf wie jedes andere System. Monitoringsysteme für Websysteme sind selbst auch Websysteme.

Terminologie

Im Monitoring wird eine spezielle Terminologie verwendet, die wir klären möchten. Eine Messung ist ein einzelnes Datum, in der Regel ein numerischer Wert. In Kombination mit einer Messgröße (oder Messeinheit) entsteht eine Metrik. Eine oder mehrere Metriken bilden einen Indikator. Die Messfrequenz gibt an, wie häufig etwas gemessen wird. Die Perspektive beschreibt, von wo aus gemessen wird. Es ist besonders bei Latenzmessungen von Websystemen ein großer Unterschied, ob ich auf dem Server selbst oder von einem anderen Kontinent aus messe. Die Interpretation einer Metrik, die zu einer Erkenntnis führt, heißt Insight.

Die für ein System geschäftlichen relevanten Indikatoren heißen Key-Performance-Indikatoren (KPI). Für die Komponenten eines Systems lassen sich Service-Level-Indikatoren definieren (SLI) und mit etwas Erfahrung Service Level Targets (SLT), also gewünschtes Minimum und Maximum eines SLIs. Zu einem SLI gehört eine exakte Definition der Metriken, der Messfrequenz sowie der Perspektive. In einem Service Level Agreement (SLA) können SLIs und SLTs vertraglich festgelegt werden. Oft enthält ein SLA auch Strafen, falls die SLTs nicht eingehalten werden. Da während der Entwicklung eines Systems noch keine Daten über den Produktivbetrieb vorliegen, kann die vertragliche Verankerung von vernünftigen SLAs im Vorfeld schwierig sein. Deswegen sollten SLAs, die Strafen enthalten, auf der Grundlage von handfesten Daten geschlossen werden. Denken Sie auch daran, dass die Messungen und Zusammenstellung der Indikatoren für den Nachweis der Einhaltung aufwändig sein können.

Klassifikation

Nach dem Standard ISO/IEC 25010 [2] ist die Prüfbarkeit (engl. Inspectability) ein Teil der Analysierbarkeit. Im Standard werden Prüfbarkeit und Analysierbarkeit zusammengefasst. Die in diesem Artikel rund um die Prüfbarkeit diskutierten Konzepte zeigt Abbildung 1. Stefan Toth hat in seinem Buch [3] die Qualitätsszenarien nach Akzeptanzkriterien, Qualitätsgeschichten und allgemeinen Merkern klassifiziert. Die Prüfbarkeit generiert in erster Linie einen allgemeinen Merker, dass Prüfbarkeit hergestellt werden muss oder nicht. Falls dies der Fall ist, erzeugen Diskussion um Prüfbarkeit im Weiteren dann konkrete Akzeptanzkriterien, und zwar hauptsächlich im Betrieb und im Marketing. Siehe hierzu die Beispiele für Qualitätsszenarien am Ende des Artikels.

takai_pruefbarkeit_1.tif_fmt1.jpgAbb. 1: Konzepte rund um die Prüfbarkeit

Architektur für Prüfbarkeit

In unserer Architektur gibt es das System, das geprüft wird, sowie das Monitoringsystem, das das System prüft (Abb. 2). Betrachten wir nun zuerst das System, das beobachtet wird. Wenn sich das System nicht beobachten lässt, dann hat das System einen permanenten Katzenzustand, aber glücklicherweise lässt sich jedes System beobachten, sonst könnten wir es nicht entwickeln. Bei Websystemen ist die Beobachtung besonders einfach, da sie stets HTTP unterstützen. Der Abruf einer Seite per HTTP lässt bereits rudimentäre Aussagen über das System zu (Antwort hat die richtige Payload, Antwort ist schnell oder langsam), es kann jedoch keine Aussage darüber gemacht werden, warum beispielsweise die falsche Payload ausgeliefert wird oder warum das System nur langsam antwortet. Hierfür muss der interne Zustand des Systems per Introspektion gemessen werden. Die Schnittstelle, die das leistet, nennt man im Allgemeinen „Health Check“. Manchmal heißt sie auch „Software Probes“. Die Anfrage des Monitoringsystems, ob noch alles in Ordnung ist, heißt „Health Check Query“. Die häufigste Anwendung stammt hier vom Load Balancer, der alle 5 Sekunden eine solche Query absetzt, und bei negativem Bescheid den entsprechenden Knoten aus der Lastverteilung rausnimmt. Eine eingehende Diskussion von Lastverteilung und Skalierbarkeit wird es in einem späteren Artikel geben.

Somit ist klar, dass solch ein Health Check nicht viele Ressourcen verbrauchen darf, aber gleichzeitig die wichtigen Parameter der Anwendung kommunizieren muss. Für das Design dieser Schnittstelle zu Gunsten der Prüfbarkeit ist also Zeit zu reservieren.

takai_pruefbarkeit_2.tif_fmt1.jpgAbb. 2: Architektur für Prüfbarkeit und Monitoring

Im Artikel über Testbarkeit [4] wurde ein eigener Port zur Messung des internen Zustands für den Test Harness besprochen. Dieser lässt sich auch für die Beobachtung zur Laufzeit einsetzen. Es gibt hier aber vor allem Bedenken in Bezug auf die Sicherheit, da dieser Port zumeist generisch ausgelegt ist und den breiten Zugriff auch auf sensible Daten erlaubt. Wenn das System sensible Daten speichert, werden Probleme auftreten, den für das Testing bestimmten Port auch auf Produktion für das Monitoring einzusetzen. Der Vorteil eines solchen Ports ist aber seine Generizität, da man sich nicht zu Beginn auf die Metriken festlegen muss, die man messen möchte. Auf der anderen Seite möchte man eben diese Metriken genau definieren, um ein funktionierendes Monitoring planen und herstellen zu können. Wenn man hier agil vorgeht und Entwicklung und Betrieb die Evolution des Monitorings gemeinsam begleiten, kann man sich guten Ergebnissen schrittweise annähern. Für die Beobachtung von Zustandsänderungen eignen sich unter anderem die folgenden Technologien:

  • Für Anwendungen auf der JVM eignet sich JMX-Technologie [1], die flexibel für die Beobachtung beliebiger Metriken eingesetzt werden kann. Hierfür wird jedoch ein Monitoringsystem benötigt, das JMX spricht, z. B. Zabbix [5], eine quelloffene Monitoringlösung mit guter Visualisierung der beobachteten Metriken. Code muss hier für die Erzeugung von Metriken via MBeans geschrieben werden.

  • Für alle Anwendungen eignet sich zudem eine REST-Schnittstelle, die die jeweiligen Metriken exportiert. Es kann sich lohnen, hierfür ein eigenes Modul zu entwerfen, das sich harmonisch in die Authentifizierungsinfrastruktur einpasst, wenn viele Komponenten auf demselben Technologiestack funktionieren. Für das Monitoringsystem ist REST mitunter besser geeignet, da man dann für die Beobachtung flexibler und einfacher eigene Werkzeuge bauen kann, zum Beispiel mit Kibana [6] oder Grafana [7].

  • Eine weitere Möglichkeit ist das Monitoring der JVM durch Instrumentierung des Java-Codes. Der Java-Agent von New Relic [8] beispielsweise verwendet Bytecode-Instrumentierung auf Basis des ASM-BCI-Frameworks [9] zur Laufzeit. Der Hersteller spricht von Performanceeinbußen von 5 Prozent beim Einsatz.

  • Für die Beobachtung von Datenflüssen werden Logs eingesetzt, d. h. unser System muss diese Logs selbst erzeugen und dem Monitoringsystem zukommen lassen. Es bietet sich an, dieses direkt zu tun. Splunk [10] bietet beispielsweise für die Java-Entwicklung verschiedene Appender für die Nachrichtenübermittlung. Der ELK-Stack ist ein weiteres Beispiel.

Damit haben wir die technischen Rahmenbedingungen besprochen, sind aber bei der Architektur unseres Systems noch nicht weiter. Hierfür lassen sich die folgenden Erkenntnisse festhalten:

  • Je kleiner und einfacher der Service, desto besser ist seine Prüfbarkeit, da nur wenige und einfache Metriken exportiert werden müssen.

  • Eine SOA- oder Microservices-Architektur ist schwieriger prüfbar als ein Monolith, da Metriken aggregiert und im Kontext ausgewertet werden müssen.

  • Cloud-Elastizität senkt die Prüfbarkeit, da die dynamische Allokation von Ressourcen auch im Monitoring nachvollzogen werden muss.

  • Continuous Deployment senkt die Prüfbarkeit, da für die Dauer eines Deployments der Datenfluss vom System versiegt.

Eine Erkenntnis für die Entwicklung ist die Entwicklung von Richtlinien für das Logging. Zum einen sollte das Logformat über alle Komponenten hinweg möglichst konsistent sein, damit Nachrichten von einem Drittsystem besser verarbeitet werden können. Zum anderen sollten sinnvolle Dinge geloggt werden, und sinnvolle Dinge sind aussagekräftige und korrelierbare Nachrichten. Hierfür können Logevents typisiert werden. Im Artikel über konzeptionelle Integrität [11] wurde der Einsatz eines Contentmodells besprochen. Sie können dieses Modell auch als Grundlage für Log­events nehmen, damit aussagekräftige Berichte erstellt werden können. Cockcroft nennt den Einsatz eines Modells als förderlich für die Erkennung von Abhängigkeiten [12].

Tatsächlich bietet es sich an, die Generierung von Events an die Use Cases des Systems zu koppeln, um aussagekräftige Indikatoren genieren zu können. Limoncelli [13] behauptet (nicht ganz im Ernst), dass es für E-Commerce-Websites nur eine einzige Metrik braucht, nämlich den Umsatz einer Maschine pro Zeiteinheit. Sobald der sinkt, ist etwas nicht in Ordnung, und die Maschine muss entsorgt werden.

Architektur für Monitoring

Unser System wird sich nicht selbst beobachten können, sodass ein weiteres System für die Beobachtung zum Einsatz kommen muss. Hierfür gibt es eine breite Palette an vorhandenen Werkzeugen. Unter Umständen ist es sogar nötig, ein Monitoringsystem selbst herzustellen. Adrian Cockroft hat hierfür sechs Regeln aufgestellt, die das Monitoring und die Architektur des Monitoringsystems beeinflussen [12]:

  • Verbringe mehr Zeit mit dem Schreiben von Code für die Analyse der Bedeutung von Metriken als mit Code, der Metriken sammelt, speichert oder anzeigt.

  • Reduziere die Messfrequenz von Latenzen auf weniger als die menschliche Aufmerksamkeitsspanne von 10 s.

  • Achte darauf, dass dein Messsystem ausreichend akkurat und präzise ist. Sammle Histogramme der Antwortzeiten.

  • Monitoringsysteme müssen eine höhere Verfügbarkeit und Skalierbarkeit als das System aufweisen, das beobachtet wird.

  • Optimiere für die Beobachtung von verteilten, flüchtigen, Cloud-basierten, containerisierten Microservices.

  • Passe die Metriken in Modelle ein, um Abhängigkeiten zu erkennen.

Limoncelli skizziert eine Schichtenarchitektur eines Monitoringsystems, die in Abbildung 3 dargestellt ist. Für jede Schicht gibt es heute Open-Source-Bibliotheken, aus denen sich auch selbst ein System konstruieren lässt, wenn man über die entsprechenden Mittel verfügt.

takai_pruefbarkeit_3.tif_fmt1.jpgAbb. 3: Bausteine eines Monitoringsystems

Wesentlich für ein Monitoringsystem ist die Sammlung von Logs, da hier große Mengen von Daten anfallen können. Werkzeuge wie Splunk, das durch ausgezeichnete Visualisierungsmöglichkeiten verfügt, werden beispielsweise nach verarbeiteten Lognachrichten lizenziert [10]. Das Logmanagement sollte wohlüberlegt sein, denn es fallen bisweilen sehr große Datenmengen an. Leicht kommt es zu Konflikten zwischen geforderter Aufbewahrungszeit (Retention) und vorhandenem Speicherplatz. Datenaggregation ist möglich, führt aber zum Verlust der Originaldaten, sodass sich viele Dinge später nicht mehr auswerten lassen. Besser man stellt sich die Frage, ob die Fehlermeldungen aus dem letzten Quartal überhaupt relevant sind. Die Monitoringziele sind schnell erreicht, und wenn dies der Fall ist, dann kann man die Daten entsorgen.

Standardmetriken und Verfahren

Die gängigen Metriken fallen für Websysteme in zwei Kategorien. So gibt es zum einen maschinennahe Metriken, die per Default von den gängigen Monitoringlösungen gesammelt und ausgewertet werden. Beispiele sind:

  • CPU: Rechenlast

  • Memory: Speicherauslastung

  • Network: Netzwerklast

  • IOPS: Datenträgerlast

  • Anzahl Prozesse

Die andere Gruppe von Metriken sind solche, die die Webanwendung selbst beobachten. Die Grenze zu Web Analytics ist hier fließend (siehe unten). Im Folgenden ein paar Beispiele für Metriken, die per Browser gemessen werden können:

  • Start rendering: Wie lange dauert es, bis der Browser anfängt zu rendern? Dies wird beispielsweise durch das Laden von JavaScript beeinflusst.

  • Document complete: Wie lange dauert es, bis das Dokument vollständig angezeigt wird?

  • Above the fold: Wie lange dauert es, bis der für den Benutzer sichtbare Bereich fertig gerendert ist?

  • Synthetic monitoring: Aus entfernter Perspektive wird Benutzerverhalten simuliert und die Antwortzeiten gemessen. Oft werden hier ganze Anwendungsfälle durchgespielt, um gleichzeitig eine Funktionsprüfung durchzuführen.

  • RUM: Beim Real User Monitoring (RUM) wird auf dem Browser des Benutzers selbst gemessen und die Ergebnisse zurückgespielt. Dies verschlechtert die Performance auf dem Client, aber nicht unbedingt in einem Bereich, der bemerkbar wäre. Die ermittelten Daten können sehr wertvoll sein, da präzise und genau gemessen werden kann.

Tritt eine Störung ein, so löst das Monitoringsystem einen Alert (oder Alarm) aus. Ein Alert wird ausgelöst, wenn entweder eine Metrik oder ein Indikator einen bestimmten Schwellwert über- oder unterschreitet. Ein Alert muss dann im Monitoringsystem manuell abgeschaltet werden. Geschieht dies nicht innerhalb einer bestimmten Zeitspanne, so wird der Alert eskaliert. Gute Monitoringsysteme haben ein Escalation-Feature, das in einem solchen Fall den Fallback auf den nächsten definierten Mitarbeiter zulässt.

Monitorig am Beispiel

Abbildung 4 zeigt ein Beispiel für ein Monitoringsystem, das die gängigen Techniken illustriert. Das zu prüfende System ist in blau dargestellt und wird von Nagios [14] (bewährte und teilweise quelloffene Lösung für das Infrastrukturmonitoring) und New Relic (proprietärer Monitoring-SaaS mit zielgruppenspezifischen Schwerpunkten von Kapazitätsplanung bis Geschäftsanalyse) beobachtet. Nagios wertet dabei die Metriken der Infrastruktur aus und New Relic die Performance und Kapazität. New Relic wird eingesetzt, da per JVM-Instrumentierung problematische Requests bequem auf dem Stack Trace durchgeklickt werden können.

Interessant ist nun, was passiert, wenn ein Alarm anschlägt. Dies kann entweder bei Nagios oder New Relic der Fall sein. Beide Systeme erzeugen dann ein Ticket im JIRA-System, das niemandem zugeordnet wird. Die Erzeugung des Tickets löst jedoch eine Nachricht an PagerDuty aus, eine SaaS-Lösung für das Incident-Management. Im PagerDuty wird ein Pikett-Plan gepflegt, sodass das System weiß, wem es nun eine SMS schicken muss. Leider ist das Mobile des Kollegen aus dem Service aber nicht in Betrieb, sodass kein manuelles Acknowledgement innerhalb von 10 Minuten im PagerDuty stattfindet. In diesem Fall greift die konfigurierte Eskalation, und PagerDuty schickt an die nächste Person eine SMS. Diese ist sogar vor Ort und bearbeitet den Case zügig.

takai_pruefbarkeit_4.tif_fmt1.jpgAbb. 4: Beispiel für Monitoring

Klassischerweise testen Unit Tests nur eine einzige Klasse oder Prozedur. In der Integrationsentwicklung ergibt das nur begrenzt Sinn, da unsere Einheiten sehr eng miteinander verbunden sind und selbst wenig Logik enthalten. Da ServiceMix im Wesentlichen aus Camel [1] besteht, verstehen wir unter einem Unit Test hier, dass eine Route die richtige Antwort bei gegebener Eingabe liefert. Dabei wird die Fixture der Tests mittels Mocks, Stubs oder Fakes aufgesetzt, die wir per Spring konfigurieren [3]. Für unser Beispiel möchten wir eine einfache Route.

Web Analytics

In Abbildung 4 ist für die Webanalyse der Adobe Tag Manager [15] integriert worden. Tag Manager sind in der Webanalyse der letzte Schrei, da sie eine dynamische Integration von Analysesystemen beinhalten. Hierfür muss man wissen, dass internationale Unternehmen gerne eine Vielzahl von Webanalysesystemen einsetzen, um die Bedürfnisse der Marketers organisatorisch besser handhaben zu können. In Südamerika sind nunmal andere Tools hip als in Asia Pacific. Der Tag Manager injiziert dabei zur Laufzeit JavaScript in die Website, das wiederum die für das vorliegende Tag relevanten Systeme mit Daten versorgt. Gut beraten ist, wer den Fertigungsprozess dieses JavaScripts mit Qualitätssicherung ausstattet.

Um den Umfang dieses Artikels nicht zu sprengen, verzichte ich auf die Diskussion weiterer Werkzeuge in diesem Bereich, möchte aber jedem Architekten eine genaue Betrachtung der gewünschten Webanalysewerkzeuge aus Gründen der Qualität ans Herz legen. Besonders empfehlenswert ist eine ROI-Diskussion, denn damit die Berichte wertvoll sein können, muss regelmäßig Zeit investiert werden. Die automatische Generierung von aussagekräftigen Dashboards ist hier aufgrund der volatilen Anforderungen oft nicht möglich, weswegen die Daten „von Hand“ ausgewertet werden. Dies ist günstiger, als Software zu schreiben, und zugleich wertvoller, da die Auswertung von einem Data Scientist gemacht werden kann, und nicht von jemandem, der „nur“ gut JavaScript programmieren kann (siehe hierzu auch die erste Regel von Cockroft). Für die Auswertung bietet sich der Einsatz von R [16] aus Gründen der Effizienz an.

Beispiele von Qualitätsszenarien

Die folgenden Qualitätsszenarien eignen sich für die Kommunikation zwischen Betrieb, Architekt und Fach:

  • Zur Laufzeit des Systems werden die einzelnen Schritte der implementierten Anwendungsfälle geloggt und vom Monitoringsystem ausgelesen.

  • Während der Laufzeit kann ein Systemingenieur die Messpunkte in der Dokumentation nachvollziehen und findet hier auch Angaben zu deren Konfiguration.

  • Während der Laufzeit kann ein Systemingenieur die kritischen Systemparameter zu I/O, CPU und Plattenplatz der eingesetzten Maschinen beobachten.

  • Zur Laufzeit alarmiert das Monitoringsystem den Systemingenieur proaktiv, falls CPU, I/O oder verwendeter Plattenplatz über 80 Prozent steigt.

  • Die vom Monitoringsystem erzeugten Alarme sind actionable, d. h., ein Systemingenieur kann für jeden Alarm, den das Monitoringsystem erzeugt, eine Dokumentation mit Handlungsanweisungen im Wiki finden.

  • Während der Entwicklung des Monitoringsystems werden minimale und maximale Schwellwerte, u. a. für Alarme definiert und dokumentiert.

  • Zur Laufzeit sammelt das Monitoringsystem an zentraler Stelle Logs.

  • Zur Laufzeit kann vom gesamten Team ein Health-Check-Monitor eingesehen werden, der den aktuellen Zustand des Systems transparent darstellt.

  • Während der Entwicklung unterliegen Quelltexte und Konfigurationen für das Monitoringsystem derselben Source Control wie die anderen Quellen des Projekts.

  • Während der Entwicklung werden für das Monitoringsystem automatische Tests entwickelt.

  • Wenn eine neue Version des Systems ausgespielt wird, dürfen die Alarme für die betroffenen Systeme nicht anschlagen.

Fazit

Aussagekräftige Berichte und Insights, die helfen, eine Website substanziell zu verbessern, sorgen für Begeisterung. Und wer ein geschäftskritisches System betreibt, der kommt um gutes Monitoring sowieso nicht herum. Über die Jahre ist aus der Beobachtung von Infrastrukturparametern ein komplexes Feedbackökosystem zur integrierten Echtzeitoptimierung von Websites geworden. Die Möglichkeiten, die SaaS-Lösungen wie New Relic heute bieten, waren vor wenigen Jahren nur internationalen Großkonzernen vorbehalten. Auf der anderen Seite lauern hier versteckte Kosten, da die Integration allfälliger Optimierungsschlaufen Aufwände nach sich zieht. Gehen Sie also besser nicht davon aus, dass es nur bei den Lizenzkosten bleibt, aber rechnen Sie damit, dass diese stetig steigen werden. Insgesamt ist der Markt für Monitoring- und Analytics-Lösungen stark in Bewegung, und die Zukunft gehört den SaaS-Lösungen. Verkompliziert wird das Ganze durch Aspekte des Datenschutzes. Ist die IP-Adresse ein persönliches Datum oder nicht? Gilt die Safe-Harbor-Bewertung der USA oder nicht? Das kann ich nicht beantworten, aber eines ist sicher: Der Markt dreht schneller als die Judikative.

takai_daniel_sw.tif_fmt1.jpgDaniel Takai ist Technologiemanager bei der Unic AG in Bern. Er ist dort für die Entwicklungsprozesse, Technologieentwicklung und Softwarearchitekturen verantwortlich.

Twitter

Projekte und Produktentwicklungen sind unterschiedlich. Fest steht jedoch: Nirgendwo findet man ein perfektes Umfeld mit ausreichend Geld, Zeit und fähigen Leuten, ohne störende Legacy-Lasten, fehlerhafte Libraries oder böse Überraschungen. Selbst wenn viele dieser Parameter passen, ist Ihr Kunde oder Fachbereich vielleicht wankelmütig, oder das Management wechselt während des Vorhabens die eigene Linie (falls es eine gibt). Moderne Softwareentwicklung ist komplex und wenig schablonenhaft. Zeitgemäße Arbeit an der Softwarearchitektur muss deshalb Reaktionsfähigkeit stärken, fokussieren und sich davon verabschieden, dass alles vorab plan- und analysierbar ist.

Viele methodische Entwicklungen der letzten fünfzehn Jahre kann man als Reaktion auf die komplexen Herausforderungen der heutigen Softwareentwicklung verstehen. Agile Vorgehensmodelle versuchen mit Unsicherheit zu leben, Flexibilität im Vorgehen zu ermöglichen und Zusammenarbeit zu stärken. Die richtige Reaktion ist wichtiger als der richtige Plan. Lean stellt das Lernen und stetige Verbesserung in den Vordergrund, versucht Verschwendung zu elimieren und unser Vorgehen auf wichtige Aspekte zu fokussieren. Der Trend geht weit über die Softwareentwicklung hinaus, und selbst wenn Sie den Begriff „Agil“ oder den (abflachenden) Hype darum nicht mögen – es hat sich etwas im Projektalltag verändert, und die Disziplin der Softwarearchitektur muss darauf regieren:

  • Neue Ideen, Erkenntnisse und gut funktionierende Praktiken aus aktuellen Vorgehensmodellen sollten in den Architekturwerkzeugkasten übertragen werden. Das bedeutet, den Nutzen von Architekturtätigkeiten für Kunden zu offenbaren, entsprechende Anforderungen zu priorisieren, den Aufwand für Architekturtätigkeiten je nach Priorität und Kritikalität zu variieren, oder auch Architektur in Teams zu entwerfen.

  • Architekturpraktiken und -tätigkeiten sollten sich in aktuellen Vorgehensmodellen nicht wie ein Fremdkörper anfühlen. Architekturarbeit muss so schlank wie möglich und so fundiert wie nötig sein. Das bedeutet, Architekturarbeit muss gut mit der Entwicklung verzahnt werden, agile Konstrukte zur Projektsteuerung annehmen, iterativ leistbar und möglichst frei von umständlichen Ergänzungen sein.

Ich greife Aspekte dieser Punkte im Folgenden auf und beschreibe sie etwas detaillierter.

Durch Anforderungen getrieben

Wenn Sie eine fachliche Methode ausimplementieren oder ein neues Feld im UI vorsehen, orientieren Sie sich an Wünschen und Anforderungen des Kunden. Dasselbe sollten Sie tun, wenn Sie Technologien auswählen oder Fremdsysteme anbinden. Was auch immer die grundlegenden Fragestellungen in Ihrem Projekt sind: Lassen Sie sich von Anforderungen leiten.

Qualitätsanforderungen kommt dabei eine besondere Bedeutung zu. Sie beschreiben die nicht funktionalen Aspekte der zu erstellenden Lösung, also wie eine Funktionalität bereitgestellt werden soll. Soll die Funktionalität ohne Unterbrechung zur Verfügung stehen, sind Zuverlässigkeit und Verfügbarkeit wichtig. Wollen wir in Zukunft mehr Benutzer mit unserer Funktionalität beglücken, ist Skalierbarkeit spannend. Wollen wir verhindern, dass Unbefugte heikle Funktionalität nutzen, ist Sicherheit ein Thema. Diese Qualitätsmerkmale beziehen sich oft auf weite Systemteile oder sogar das Gesamtsystem. Zuverlässigkeit lässt sich nicht durch eine neue Klasse oder Komponente sicherstellen, die gesamte Anwendung und deren Basis müssen entsprechenden Prinzipien gehorchen.

Qualität ist somit meist querschnittlich und betrifft viele Projektmitarbeiter. Wir erreichen Qualitätsmerkmale durch den Einsatz der richtigen Technologien, Plattformen, Frameworks, Muster oder die breite Adaptierung von Arbeitsweisen. Das ist grundlegende Arbeit am Fundament. Entsprechende Entscheidungen sind weitreichend und oft aufwändig in der Umsetzung. Wir sind damit mitten in der Architekturdomäne, und es ist wenig überraschend, dass Qualitätsanforderungen als die Architekturanforderungen gesehen werden.

Umgang mit Qualitätsanforderungen

Um mit Qualitätsanforderungen effektiv zu arbeiten, benötigen Sie konkretere Informationen als die bloße Nennung wichtiger Qualitätsmerkmale wie Sicherheit oder Performanz. Sie benötigen detaillierte Aussagen zu qualitativen Anforderungen – etwa Qualitätsszenarien, die konkrete Beispiele für Qualitätsanforderungen liefern [1]. Abbildung 1 zeigt den Aufbau von Qualitätsszenarien und illustriert ihn mit einem Beispiel. Vereinfacht könnte man sagen, dass Qualitätsszenarien User Stories mit nicht funktionalem Hintergrund sind.

toth_agila_1.tif_fmt1.jpgAbb. 1: Qualitätsszenarien – Aufbau und generisches Beispiel [2]

Szenarien sind auch konkret genug, um sie gut untereinander und gegen funktionale Anforderungen priorisieren zu können. Damit sind auch agile Backlogs für die Steuerung von Architekturarbeit im Spiel. Sie können die Qualitätsszenarien wie Stories unabhängig in den Backlog legen oder sie einzelnen funktionalen Anforderungen zuordnen. In der Praxis ist beides sinnvoll: Ein Szenariobeispiel wie „Der Algorithmus zur Berechnung der Artikelbeliebtheit soll leicht anpassbar und austauschbar sein“, ist am besten bei der funktionalen Anforderung zur Berechnung der Artikelbeliebtheit aufgehoben und wird gemeinsam mit dieser Anforderung priorisiert. Andere Szenarien, die Sicherheit oder Zuverlässigkeit zum Thema haben, beziehen sich nicht auf einzelne Funktionalitäten, sondern betreffen oft das gesamte System oder weite Teile desselben. Diese Szenarien sind die aus architektonischer Sicht wichtigeren und werden mit der „normalen“ Suche nach Akzeptanzkriterien zu funktionalen Anforderungen schwer gefunden. Eine gezielte Suche nach konkreten Aussagen zu Qualitätsmerkmalen bietet sich deshalb an.

Gefundene Szenarien, die unabhängig in die Anforderungsliste aufgenommen werden können, müssen priorisiert werden. In neu gestarteten Projekten sollte möglichst schnell ein „Walking Skeleton“ entstehen – ein Gerüst der Anwendung, das alle kritischen Schichten und Technologien berührt, ohne viel „Fleisch“ (im Sinne von Funktionalität) zu bieten. Technologisch herausfordernde oder neue Anforderungen und Szenarien werden folglich höher priorisiert als Anforderungen, die architektonisch mehr vom selben sind. In späteren Projektphasen ist vor allem das architektonische Risiko entscheidend. Folgende Fragen liefern Hinweise auf die Höhe des Risikos:

  • Wie teuer oder zeitaufwändig wäre es, eine Fehlentscheidung zu revidieren?

  • Wie viele Projektmitglieder sind von der Entscheidung betroffen?

  • Sind zentrale Ziele des Projekts mit der Fragestellung verknüpft?

Szenarien mit hohem architektonischen Risiko oder großem Beitrag zum Walking Skeleton (oder beides) wandern weiter oben in die Anforderungsliste.

Vom Aufwand her dem Problem angemessen

Stellen Sie sich ein Produktentwicklungsprojekt vor, das auf einem bekannten Technologiestack aufsetzt. Es gibt ein passendes unternehmensspezifisches Applikationsframework; das einzige Umsetzungsteam hat bereits ähnliche Projekte durchgeführt und kennt die Domäne. Der Projektplan ist realistisch und der Aufwand überschaubar. Dieses Projekt kommt wohl mit weniger Architekturaufwänden aus als ein großes Projekt für die Umsetzung einer neuartigen Flugsicherungssoftware. Im ersten Projekt ergeben sich wahrscheinlich weniger risikoreiche Fragestellungen. Das Umfeld ist weniger komplex, das zu lösende Problem und der Lösungsweg sind recht gut verstanden. In Projekt zwei sind einige Komplexitätstreiber zu finden – die Architekturarbeit wird spannender. Abbildung 2 zeigt, wie sich Architekturaufwände und Komplexitätstreiber die Waage halten sollten.

toth_agila_2.tif_fmt1.jpgAbb. 2: Das richtige Maß für Softwarearchitekturarbeit [2]

Arbeit an der Softwarearchitektur hat das Ziel, gute Entscheidungen zum richtigen Zeitpunkt zu treffen und das Risiko einer falschen Entscheidung zu minimieren. Zu hohe Aufwände machen Projekte schwerfällig, langsam und aufwändiger als nötig. Erstellen Sie etwa einen Prototyp für eine einfach umzusetzende Anforderung, verzögern Sie die Umsetzung und die damit verbundene Rückmeldung. Ihr Aufwand hat zudem wenig bis keinen Nutzen. Solche Irrwege behindern vor allem in weniger komplexen, dynamischen Projekten und machen sie starrer als nötig.

Auf der anderen Seite führt zu wenig Arbeit an der Softwarearchitektur zu zufälliger Architektur und potenziell zur Verfehlung wichtiger Projektziele. In architektonisch risikoreichen Projekten muss folglich ausreichend fundierte Architekturarbeit geleistet werden. Wichtig ist die richtige Balance, die sich für jedes Projekt anders gestaltet.

Konkrete Fragestellungen einschätzen

Es ist das Eine, einzuschätzen, wie viel Architekturaufwand Ihr Projekt allgemein verdient. Es ist etwas Anderes, herauszufinden, wo genau diese Aufwände hinfließen sollten. Wie erkennen Sie an konkreten Fragestellungen, ob Architekturarbeit notwendig ist? Eine Lösung: Lassen Sie sich von den folgenden Fragen leiten (angelehnt an [3]):

  • Ist die Entscheidung der Fragestellung später nur schwer zu ändern?

  • Ist die Umsetzung der Entscheidung eher teuer?

  • Werden sehr hohe qualitative Anforderungen gestellt (Hochsicherheit, Hochverfügbarkeit, Hochperformanz etc.)?

  • Lassen sich die Anforderungen oder Lösungsalternativen nur schwer in Bestehendes abbilden (Istarchitektur, Rahmenbedingungen)?

  • Ist die eigene Erfahrung im Lösungsspektrum schwach?

Die Fragen sind weder überschneidungsfrei noch messerscharf formuliert, sie sind aber für sehr unterschiedliche Rahmenbedingungen und Projektumgebungen funktionsfähig. „Schwer änderbar“ beinhaltet einmal mehr, einmal weniger Fragestellungen. Und was für manche Projekte „teuer“ wäre, ist für andere ein Klacks. Auch die beiden letzten Fragen, die eher Richtung Wissen, Erfahrung und Lösungsidee zielen, setzen keinen bestimmten Rahmen voraus.

Beantworten Sie die Fragen mehrheitlich mit „ja“, haben Sie vermutlich eine architektonisch risikoreiche Fragestellung an der Hand. Gerade die erste Frage ist recht aussagekräftig: Später schwer zu ändernde Entscheidungen betreffen viele Projektmitglieder, haben externe Abhängigkeiten oder beinhalten hohen finanziellen Einsatz. Häufig basieren solche Fragestellungen auf qualitativen Anforderungen, die querschnittlich wirken.

Haben Sie eine Fragestellung oder Entscheidung als architekturrelevant erkannt, lohnt sich der Einsatz architektonischer Mittel, um das Risiko einer Fehlentscheidung zu minimieren. Dazu gehören etwa die genauere Analyse nicht funktionaler Anforderungen, die Konzeption und ggf. Modellierung möglicher Lösungen, die Definition von Prinzipien, die Erstellung von Durchstichen und Prototypen oder die breite Vermittlung und Etablierung von Entscheidungen.

Andere Fragestellungen können während der Implementierung und im Zusammenspiel mit Test und Auslieferung effizienter beantwortet werden. Typische Kandidaten hierfür sind das genaue Klassendesign, interne Schnittstellen oder Implementierungsalternativen. Rückschläge auf dieser Ebene bedrohen Sie bei beschränkten Mitteln jedoch meist weniger als die eben identifizierten architekturrelevanten Fragestellungen.

Von aktuellen Erkenntnissen zu Zusammenarbeit und Vorgehen beeinflusst

Auch wenn die Wurzeln der Disziplin noch weiter zurückreichen, Softwarearchitektur ist ein Kind der 90er Jahre. Im universitären Umfeld und mit großer finanzieller Unterstützung des amerikanischen Verteidigungsministeriums wurden Muster, Sprachen und Methoden erarbeitet. Weil Rollen- und Prozessmodelle ihre Blütezeit erlebten, konnte man die Diszplin relativ leicht einem „Architekten“ zuschlagen.

Die Softwareentwicklung hat seit den 90er Jahren viel gelernt. Agile Softwareentwicklung, Lean Development oder auch die Organisationstheorie beinhalten viele Erkenntnisse zu Zusammenarbeit, Komplexität und Dynamik. Auch Softwarearchitektur kann als Disziplin von diesen Erkenntnissen profitieren.

Wie wäre es mit Praktiken, die es ermöglichen, Architekturaufgaben effektiv auf mehrere Schultern zu verteilen? Praktiken, die dynamische Projekte nicht bremsen? Was halten Sie von zeitgemäßen Methoden zur Minimierung von Unsicherheiten und Risiken? Und was wäre, wenn Softwarearchitektur so transparent wird, dass Sie stetig und gewinnbringend mit Stakeholdern zusammenarbeiten können? Konkrete Methodikbausteine wären (näher beschrieben in [2]):

  • Leichtgewichtige Ausprägungen von Architekturbewertungsverfahren: Sie bringen Projektmitglieder zusammen, um gezielt über architektonische Herausforderungen zu sprechen, stärken also Kommunikation und Fokussierung.

  • Konsensmechanismen zur Unterstützung von Gruppenentscheidungen: Sie ermöglichen etwa die Vorbereitung von Entscheidungen durch einzelne Projektmitglieder und deren Annahme durch alle interessierten Entwickler. Über die Messung von Widerständen werden Risiken effektiv behandelt und Entscheidungsverfahren ufern nicht zu sehr aus.

  • Sichtbare Architekturartefakte, etwa auf einer „Architekturwand“, wie in Abbildung 3 gezeigt: Eine Architekturwand kann als Informationsradiator nach agilem Vorbild verwendet werden und stärkt gleichzeitig die Zieltreue, verhindert das Verwässern wichtiger Architekturideen.

toth_agila_3.tif_fmt1.jpgAbb. 3: Die Architekturwand [2]

Gut mit der Implementierung verzahnt

Abbildung 4 zeigt ein vereinfachtes Bild eines generischen Entwicklungsprozesses. Er zeigt, wie Anforderungen die iterative Entwicklung speisen (Mitte), und der Umsetzungszyklus auslieferbare Software erstellt (rechts). Grundsätzliche, fundamentale Fragestellungen wandern vor der Implementierung durch den Architekturzyklus (links). Ich durchwandere das Bild mithilfe eines vereinfachten Beispiels, um die Verzahnung von Architektur und Implementierung zu illustrieren.

toth_agila_4.tif_fmt1.jpgAbb. 4: Iterative Architekturarbeit mit Umsetzung verzahnt [2]

Sie haben immer wieder wichtige Entscheidungen in Ihrem Projekt zu treffen. Nehmen wir zum Beispiel an, ein Teil Ihrer Applikation nimmt komplizierte Berechnungen vor. Sie haben den Applikationsteil bereits in Bausteine zerlegt und sehen sich nun mit Anforderungen konfrontiert, die hohe Flexibilität im Berechnnungsablauf fordern. Da die Fragestellung nicht isoliert betrachtet werden kann und viele Bausteine betrifft, wandern Sie in den Architekturzyklus aus Abbildung 4.

Um möglichst lose Kopplung zu erreichen, entwerfen Sie einen einfachen Eventmechanismus. Sie sehen vor, dass Komponenten einen eigenen Berechnungszustand halten und bei Änderungen an diesem Zustand entsprechende Events feuern. Andere Bausteine können auf diese Events reagieren. Sie erstellen eine kleine Implementierung, die Möglichkeiten Ihrer Plattform nutzt, um diese Idee umzusetzen. Es funktioniert.

An dieser Stelle definieren Sie die Idee als brauchbare Möglichkeit und entscheiden sich für eine breitere Umsetzung. Sie schaffen damit die Grundlage für Implementierungstätigkeiten, Sie stellen eine Vorgabe auf (Abb. 4, oben links). Es handelt sich um den ersten wichtigen Berührungspunkt zwischen Architektur- und Umsetzungsarbeit.

In der Umsetzung wenden Sie das Konzept auf Ihre Bausteine an (vielleicht nicht sofort auf alle). Sie versuchen, Zustandsübergänge zu definieren, eine produktivtaugliche Implementierung für den Zustand selbst zu kreieren und entwerfen fachliche Events. Erst hier haben Sie das Problem annähernd vollständig vor Augen: Sie erkennen, wie kompliziert sich Zustände teilweise zusammensetzen, welche Daten mit den Events übertragen werden müssen und wie diese Lösung mit anderen Konzepten Ihrer Bausteine zusammenwirkt. Haben Sie wichtige Teile umgesetzt, können Sie mit Tests eine Idee vom Laufzeitverhalten bekommen.

Hier ist der zweite wichtige Berührungspunkt zwischen Architektur und Implementierung: die Rückmeldung aus der Implementierung, samt den Erkenntnissen aus Integration und Test (Abb. 4, oben rechts). Sie sollten diese Rückmeldung häufig und zeitnah suchen. So prüfen Sie Architekturentscheidungen und minimieren den Raum für Annahmen und Spekulationen. Technische oder konzeptionelle Probleme, die auf Implementierungsebene auftreten, stellen einen sekundären Architekturtreiber dar (neben den weiter oben besprochenen Anforderungen). Insgesamt entsteht eine gelebte Softwarearchitektur, die durch die Implementierung nicht verwässert, sondern bereichert wird.

Der Schlüssel hierzu sind die häufige Integration (und Auslieferung) von Software und die Verankerung von Architekturinformationen in Tests oder im Monitoring des Systems. So können konkrete Rückschlüsse auf die Erreichung wichtiger Qualitätsmerkmale gezogen werden. Unpassende, nicht performante oder unsichere Architekturkonzepte werden schneller entlarvt und treiben den Architekturzyklus. Die meisten Projekte beschreiben die erkannten Schwächen in Form von technischen Schulden und priorisieren sie wiederum mit Qualitätsszenarien und funktionalen Anforderungen im Backlog.

Einfach in aktuelle Vorgehensmodelle integrierbar

Immer mehr Projekte adaptieren ein Vorgehen, das mit so wenig Verzögerung wie möglich Richtung Auslieferung von Software drängt. Das Stichwort „agil“ ist so omnipräsent, dass sich viele bereits genervt abwenden, wenn das Thema zur Sprache kommt. Ich verweigere mich jedem religiösen Fanatismus an dieser Ecke und möchte hier auch nicht dogmatisch werden. Nüchtern betrachtet setzen immer mehr Projekte auf agile Praktiken – und es funktioniert. Viele Studien und Umfragen zeigen Erfolge von agilen Projekten [4], [5]. Eine von VersionOne durchgeführte Umfrage [6] befragte 2013 4 048 IT-Mitarbeiter aus Europa und den USA zum „State of Agile Development“. 84 Prozent der Organisationen setzen demnach agile Methoden ein, nur 3 Prozent der Unternehmen planen, das in Zukunft nicht zu tun. Scrum ist, wenig überraschend, am weitesten verbreitet und kommt auf 72 Prozent Marktanteil unter den agilen Methoden (Varianten mit eingerechnet).

Was bedeutet das für die Disziplin der Softwarearchitektur? Zeitgemäße Softwarearchitektur muss auch in agile Softwareprojekte passen und sollte die Konzepte, Praktiken und Rollen dieser Projekte nutzen und annehmen. Sie muss zumindest iterativ zu leisten sein und sollte eher erklären, wie Architekturpraktiken in moderne Vorgehensmodelle passen, als diese Vorgehensmodelle mit behindernden oder umständlichen Ergänzungen zu versehen. Wenn 75 Prozent der Projekte Iterationsplanungstreffen abhalten, 56 Prozent kontinuierlich integrieren und immerhin 23 Prozent Kanban nutzen [6], sollte Softwarearchitektur zumindest seinen Platz in diesen Praktiken kennen.

Die beschriebene Adoption des Backlogs zur Steuerung von Architekturarbeit ist bereits ein wichtiger Baustein, um diesem Zielbild näher zu kommen. Neben der Rückmeldung aus Systemtest und -integration muss man auch die Rollenfrage stellen. Was passiert mit „dem Architekten“ in agilen Vorgehen? In der Praxis etablieren sich neben dem Architekten als Person auch Modelle, in denen die Rolle auf mehrere Schultern verteilt wird (Abb. 5).

toth_agila_5.tif_fmt1.jpgAbb. 5: Rollenmodelle für Architekten [2]

Ich habe jede der gezeigten Formen bereits in Projekten funktionieren sehen. Je nach Umfeld und Rahmenbedingungen funktionieren bestimmte Interpretationen der Architektenrolle besser oder schlechter – wichtig jedoch auch hier: Die Welt wird offener und flexibler. Die Architekturdisziplin wandelt sich zu einem Betätigungsfeld voller Möglichkeiten.

Fazit

Das gezeichnete Bild einer zeitgemäßen Architekturdisziplin, die auch in agilen Vorhaben ihren Platz findet und sich an modernen Praktiken orientiert, ist (dem Rahmen geschuldet) nicht vollständig. Es soll aktuelle Möglichkeiten zeigen und Sie dazu animieren, Ihr Denken zu öffnen und einige Facetten davon in Ihrem Kontext auszuprobieren. Wollen Sie tiefer in das Thema einsteigen, werden sie in [2] fündig – sehr praxisnah und intensiv können Sie auch im neuen iSAQB Advanc­ed-Level-Modul „AGILA – Agile Softwarearchitektur“ [7] lernen und diskutieren. Dort werden auch noch weiterführende Themen, wie der Zusammenhang der gewählten technischen Architektur und agilen Vorgehensmodellen, thematisiert.

toth_stefan_sw.tif_fmt1.jpgStefan Toth berät Unternehmen aus unterschiedlichen Branchen in Sachen Softwarearchitektur. Neben breitem technologischem Kontext ist methodische Erfahrung aus agilen Projekten, Architekturbewertungen und IT-Transformationen sein größtes Kapital. Er ist Mitglied des iSAQB e.V. und lizenzierter CPSA-Advanced- und Foundation-Trainer.

Mail
Desktop Tablet Mobile
Desktop Tablet Mobile