Architekturprinzipien, Teil 1: Architekturgrundlagen

Ein etwas anderer Hausbau

Adam Bien

Vor dem Beginn der Rohbauarbeiten und nach dem Kauf eines Grundstücks beginnt die Planung des Hauses. Zu diesem Zweck werden Architekten beauftragt, die für die Planung von ästhetischen, wirtschaftlichen und auch rein technischen Aspekten zuständig sind. Die Implementierung des Hauses beginnt erst nach dieser Planungsphase. Die Entwicklungsphasen in der Softwareentwicklung sind leider nicht so klar definiert. In dieser Artikelserie werden wir die Architektur, das Design und auszugsweise auch die Implementierung einer Beispielanwendung näher betrachten.

Einführung

Das Vorgehen eines Softwarearchitekten unterscheidet sich völlig von seinen Kollegen aus der Baubranche. Einer der Gründe dafür sind die Endkunden. Die meisten Bauherren haben eine konkrete Vorstellung, wie das Traumhaus aussehen soll. Ein iteratives Vorgehen nach den agilen Ansätzen ist hier äußerst selten – es würde ja bedeuten, dass die Planung des Hauses gleichzeitig mit dem Abschluss der Bauarbeiten fertig ist. Auch der Architekt hat es hier wesentlich einfacher – aufgrund seiner Erfahrung sind die funktionalen und nicht funktionalen Anforderungen an das Bauvorhaben meistens nachvollziehbar und klar definiert.

Im Gegensatz dazu haben die Auftraggeber eines Softwaresystems oft nur eine vage Vorstellung über das genaue Aussehen der Anwendung. Schlimmer noch – die meisten Auftraggeber erwarten, dass die Anwendung gebaut wird, bevor die Fachlichkeit endgültig geklärt ist. Unter diesen Umständen scheint der Entwurf der Architektur eines Softwaresystems unmöglich zu sein. In den folgenden Ausgaben werden wir uns mit diesem Problem beschäftigen. In diesem Artikel werden die Architektur und das Design näher definiert.

Architektur vs. Design

Die Begriffe Architektur und Design werden fälschlicherweise gleichermaßen für die Beschreibung der Struktur eines Softwaresystems verwendet. Die Architektur einer Anwendung ist aber wesentlich abstrakter als ihr Design. Aus der Architektur resultiert das Design – es ist ihre Implementierung.

Die Softwarearchitektur beschreibt lediglich die grundlegende Organisation der Elemente und ihre gegenseitige Beziehungen einer Anwendung. In dem ANSI/IEEE 1471 2000-Standard wurde die Softwarearchitektur folgendermaßen definiert: The fundamental organization of a system embodied in its components, their relationships to each other and to the environment and the principles guiding its design and evolution. Die relevanten Elemente setzen sich aus Server- und Client-Elementen zusammen. Die Serverelemente liefern fachliche Dienste, die Client-Elemente konsumieren diese. Interessanterweise resultiert jede Architektur in einer baumartigen Struktur: Das System besteht aus mehreren Subsystemen, diese wiederum enthalten mehrere Komponenten, welche wieder aus Packages (oder Namespaces) bestehen. In den Packages befinden sich letztendlich die für die Architektur nicht mehr so relevanten Klassen. Die Struktur ist programmiersprachen- und implementierungsunabhängig und wird mittels Design weiter verfeinert.

Abb. 1: Systemarchitektur

Das Design einer Anwendung ist wesentlich konkreter. Es realisiert die Ideen, Intensionen und Visionen der Architektur. Für die endgültige Qualität der Software ist es essenziell wichtig, dass der Architekt seine Philosophie der Architektur an den Designer verständlich weitergibt. Das Design ist immer noch weitgehend programmiersprachenunabhängig, allerdings muss bereits an dieser Stelle die Entscheidung für die Art der Programmiersprache (OO oder prozedural) stehen. Bei der Umsetzung der Architekturvorgaben in der Designphase helfen an dieser Stelle die altbekannten Design-Patterns. Hierbei handelt es sich um fertige Lösungen für die bei der Realisierung auftretenden Probleme. In der Praxis wird das Design nicht nur durch die Architekturvorgaben beeinflusst – es wird noch in der Implementierungsphase kontinuierlich verfeinert. Diese Änderungen können sich natürlich auch auf die Architektur auswirken. Die Anpassung der Architektur aufgrund von Designentscheidungen bleibt auch in der Praxis äußerst selten. Der Grund dafür ist der Abstraktionsgrad der Architektur – nur die wenigsten Designentscheidungen sind für die Architektur oder den Architekten interessant. Die Beziehung zwischen der Präsentation und der Geschäftslogik der Anwendung muss nicht aufgrund eines Protokollwechsels (Web Services, IIOP, RMI usw.) oder gar der Technologie (Refactoring von eigener RMI-Implementierung gegen einen Applikationsserver) angepasst werden – die Architektur bleibt von dieser Änderung unangetastet. Bei der konsequenten Umsetzung dieser Grundgedanken in die Praxis sind wir auf dem besten Weg, der Model Driven Architecture die Show zu stehlen.

Bei der Modellierung von größeren Systemen versucht man ihre Komplexität hinter personalisierten Sichten (Viewpoints) zu verbergen. Diese Sichten sind speziell für sog. Stakeholder aufbereitet, d.h. Personen, welche in dem Entwicklungsprozess involviert sind. Jeder Stakeholder (Fachabteilung, Entwickler, Tester, Architekt usw.) ist nur an bestimmten Aspekten eines Systems interessiert. Alle anderen Informationen werden ausgeblendet. Uns interessieren lediglich die Architektur des Systems und somit auch nur die Sicht des Architekten auf das System. Die Sichten können mit UML-Diagrammen realisiert werden. Jedes Diagramm bietet eine andere Sicht auf das Repository oder das Modell des Systems an. In den Diagrammen werden lediglich die Referenzen auf die Elemente visualisiert – somit bleiben das Modell und auch die Diagramme konsistent.

Was beeinflusst die Architektur eines Systems?

Nun haben wir die Architektur und die Rolle des Architekten ausreichend definiert. An dieser Stelle ist es interessant, die eigentliche Aufgabe des Architekten näher kennen zu lernen. Der Architekt benötigt für seine Arbeit einige Eingabeparameter. Neben der reinen Funktion des Systems – den funktionalen Anforderungen – spielen für den Architekturentwurf die Randbedingungen und die nicht funktionalen Anforderungen eine übergeordnete Rolle. Die Randbedingungen sind oft durch die politischen, strategischen und technischen Umstände in dem Unternehmen einfach vorgegeben. Entscheidungen über den eingesetzten Applikationsserver, Einsatz von Open Source oder die Art der Anbindung von bestehenden Systemen lassen sich oft im Rahmen eines Projekts nicht ändern und müssen hingenommen werden. Bereits an dieser Stelle sind Kenntnisse über die eingesetzte Infrastruktur absolut notwendig. Ansonsten kann es sich einige Iterationen später herausstellen, dass die Architekturentscheidungen in der Praxis einfach nicht funktionieren können. Einige Beispiele von zumindest problematischen Entscheidungen aus der Praxis:

  • Kommunikation mit einem Applikationsserver durch die Firewall
  • Kommunikation der Applikationsserver unterschiedlicher Hersteller über IIOP
  • Verwendung von Web Services als Kommunikationsmedium zwischen Komponenten
  • Verkürzung der Projektlaufzeit wegen der hohen Wiederverwendbarkeit der Komponenten
  • Wahl der Enterprise JavaBean-Technologie wegen der hohen Skalierbarkeit und Performance
  • problemlose Austauschbarkeit der Applikationsserver
  • automatische Plattformunabhängigkeit von in Java entwickelten Anwendungen

Neben den Randbedingungen beeinflussen auch noch die nicht funktionalen Anforderungen die Architektur des Systems. Die nicht funktionalen Anforderungen definieren die für den Endkunden eher ungreifbare und auch oft unsichtbare innere Qualität der Software. Die nicht funktionalen Anforderungen sollten bereits in den frühen Entwicklungsphasen klar definiert werden. Der Auftraggeber geht einfach von einer hohen Qualität der Software aus. Es ist die Aufgabe des Architekten, bereits in der Anforderungsanalyse die nicht funktionalen Anforderungen durch Interviews mit der Fachabteilung zu definieren. Dabei ist es besonders wichtig, den Kunden über die Auswirkungen seiner Entscheidungen aufzuklären.

Pattern Beschreibung Wechselwirkung
Hochverfügbarkeit, Ausfallsicherheit Bestimmt, wie oft die Software innerhalb einer definierten Zeitperiode
ausfallen darf.
Performance, Skalierbarkeit
Robustheit Gibt die Fehlertoleranz und das Verhalten im Fehlerfall eines Systems
an.
Komplexität
Wartbarkeit Definiert die Aufwände für die Wartung der Software nach dem Abschluss
der Entwicklungsarbeiten.
Komplexität
Skalierbarkeit Die Fähigkeit des Systems, seine Dienste bei zunehmender Anzahl
der Anfragen in der geforderten Antwortzeit anzubieten.
Performance
Erweiterbarkeit Je höher die Erweiterbarkeit, desto effizienter lässt sich neue
Funktionalität nachträglich bereitstellen.
Wartbarkeit, Komplexität, Performance
Flexibilität Die Fähigkeit, auf Hardware und Software Änderungen effizient zu
reagieren.
Komplexität, Performance
Performance Die Fähigkeit, die Dienste des Systems im Rahmen der Vorgaben zu
erfüllen.
Skalierbarkeit, Wartbarkeit
Installierbarkeit Wirkt sich auf die Aufwände für die Verteilung und Installation
der Software aus.
Bedienbarkeit
Wiederverwendbarkeit Die Fähigkeit, bestehende (Teil-)Funktionalität eines Systems wiederzuverwenden. Wartbarkeit, Komplexität
Portabilität Bestimmt, wie effizient einer Anwendung auf eine andere Softwareplattform
(z.B. Applikationsserver, Datenbank, GUI Frameworks usw.) migriert
werden kann.
Komplexität
Installierbarkeit Bestimmt die für die Installation des Systems voraussichtlich zu
erwarteten Aufwände.
Bedienbarkeit, Komplexität
Bedienbarkeit Wirkt sich direkt auf die Akzeptanz und die Dauer der Einarbeitungszeit
des Endbenutzers aus.
Installierbarkeit, Robustheit
Testbarkeit Bestimmt, wie aufwändig es ist, die Realisierung der funktionalen
Anforderungen zu testen.
Wiederverwendbarkeit
Komplexität Wird durch die Anzahl der Elemente (z.B. Klassen) und ihre wechselseitige
Beziehungen bestimmt.
Wartbarkeit, Ausfallsicherheit, Performance
Administrierbarkeit Ähnlich zu Bedienbarkeit, wird jedoch lediglich für die Sicherstellung
der nicht funktionalen Anforderungen benötigt.
Testbarkeit, Bedienbarkeit
Parallelität der Entwicklung Bestimmt, ob es möglich ist, mit mehreren Teams gleichzeitig die
Anwendung zu entwickeln.
Wartbarkeit, Testbarkeit, Wiederverwendbarkeit, Komplexität

Leider ist es in der Praxis nicht möglich, alle nicht funktionalen Anforderungen gleichermaßen gut zu erfüllen. Vielmehr existiert eine Wechselwirkung zwischen den nicht funktionalen Anforderungen. Beispielsweise kann sich wegen der guten Installierbarkeit die Entscheidung für einen Thin Client negativ auf die Bedienbarkeit der Software auswirken. Genauso erhöht eine hohe Erweiterbarkeit der Software durch den zusätzlichen Aufwand für die Entkoppelung der Komponenten die Gesamtkomplexität des Systems und kann sich durch zusätzliche Indirektionen negativ auf die Performance des Systems auswirken. Es ist ratsam, den Kunden bereits in der Anforderungsanalyse über die Wechselwirkungen proaktiv aufzuklären. Wenn dem Kunden die Tragweite (= Kosten) seiner Entscheidungen von Anfang an klar ist, lässt er sich einfacher von mancher ambitionierten Idee abbringen.

Für die Architektur des Systems spielen die funktionalen Anforderungen nur eine untergeordnete Rolle. Diese instanzieren lediglich die aus den nicht funktionalen Anforderungen und Randbedingungen entstandenen Vorgaben. So entstehen in den ersten Iterationen Subsysteme, Komponenten und Packages, die den Kriterien der nicht funktionalen Anforderungen entsprechen. Aus den funktionalen Anforderungen werden lediglich die Namen der Elemente, ihre Daten und Abläufe abgeleitet. Die Organisation der Elemente erfolgt auch mit der Hilfe der funktionalen Anforderungen. So werden beispielsweise Klassen aufgrund ihrer Kohäsion – ihrer fachlichen Anziehungskraft – organisiert. Mit diesem Ansatz können Systeme anhand ihrer Fachlichkeit partitioniert werden. Somit kann die Einarbeitungszeit neuer Entwickler deutlich verkürzt werden – die Wartbarkeit der Anwendung lässt sich mit diesem Ansatz deutlich erhöhen.

Das Design des Systems wird lediglich durch die nicht funktionalen Anforderungen beeinflusst. Die Fachlichkeit einer Anwendung kann genauso gut von einer Klasse mit einer statischen Methode als auch von mehreren verteilten Komponenten korrekt abgepictureet werden. Zunächst gibt sich der Kunde mit beiden Lösungen zufrieden. Erst bei den ersten Erweiterungen und in der Wartungsphase werden die Qualitätsunterschiede deutlich.

…und was macht der Designer?

Die Hauptaufgabe des Designers ist die Konkretisierung der abstrakten Ideen und Wünsche des Architekten. Seine Entscheidungen werden maßgeblich von den nicht funktionalen Anforderungen beeinflusst. Interessanterweise lässt sich die Qualität der Arbeit des Designers und des Architekten nur beurteilen, wenn die nicht funktionalen Anforderungen und die Randbedingungen bekannt sind. Der Designer nimmt die Ergebnisse der Arbeit des Architekten entgegen und setzt die Vision der Endkunden möglichst effizient um. Auch hier ist Projekterfahrung sehr wichtig. Ein gutes Design ermöglicht beispielsweise effiziente Zusammenarbeit mehrerer Teams während der Entwicklung. Dies ist nur möglich, wenn frühzeitig klare Schnittstellen zwischen unabhängigen Subsystemen definiert werden. In diesem Fall können die Implementierung der Schnittstellen und auch ihre Verwendung von unterschiedlichen Entwicklern realisiert werden. Diese Eigenschaft kann weiter verstärkt werden, wenn die Zuständigkeiten noch klarer getrennt werden. So ist es grundsätzlich ratsam, die Präsentation einer Anwendung von ihrer Geschäftslogik zu trennen. Die Entwickler können sich so wesentlich besser auf ihre Kernkompetenzen konzentrieren und werden von den wechselnden Anforderungen an die Oberfläche der Anwendung des Kunden abgeschirmt. Ferner können mit diesem Ansatz prototypische Anwendungen mit wenig Aufwand entwickelt werden – es wird lediglich eine Mock-Implementierung dieser Schnittstelle bereitgestellt.

Der Designer implementiert die Architektur des Systems. Die Art Trennung der Aufgaben des Architekten und des Designers lässt sich mit der des Component Provider, Assembler und Deployer aus der EJB-Spezifikation vergleichen. Aus diesem Grund hat sich diese Trennung der Architektur von dem Design in der Praxis genauso wenig durchgesetzt – ein Architekt übernimmt meistens auch das Design und vereinzelt auch noch prototypische Implementierung der Anwendung. Somit sind viele Missverständnisse vermeidbar – der Designer kann bei Bedarf direkt mit dem Endkunden kommunizieren und die Auswirkungen seiner Entscheidungen präsentieren. Die Einbindung des Endkunden in diesen Prozess ist sehr wichtig, da nur so seine Erwartungen und Wünsche an das System erfüllt werden können. In den nächsten Artikeln werden wir aus diesem Grund die Architektur von dem Design nicht mehr trennen.

Fazit

In diesem Artikel haben wir einige Begriffe geklärt und die wichtigsten Eingabeparameter für die Arbeit eines Architekten definiert. Aus pragmatischen Gründen wurden das Design und die Architektur zusammengeführt. Für den Entwurf von realisierbaren Architekturen sind nicht nur ein abstraktes Denkvermögen und UML-Kenntnisse gefordert. Genauso wichtig sind hier auch die Projekterfahrung und fundierte Kenntnisse über die eingesetzte Plattform. Aber auch mit guten Programmierkenntnissen lassen sich funktionierende Architekturen entwerfen . In der nächsten Ausgabe werden wir mit dem Entwurf der Architektur einer konkreten Anwendung – eines J2EE-Forums beginnen. Insbesondere der Prozess der Architekturfindung wird uns näher beschäftigen – im Gegensatz zu diesem Artikel werden uns vielmehr die Praxis und weniger die Theorie interessieren. Anmerkungen sind jederzeit auf: abien@adam-bien.com willkommen.

Adam Bien ist freiberuflicher Berater, Dozent und Buchautor (Enterprise Java Frameworks, J2EE Patterns, J2EE HotSpots und Struts) mit dem Schwerpunkt Enterprise-Architekturen, Frameworks und J2EE. Er arbeitet mit Java seit JDK 1.0, mit Enterprise Java seit 1997 (Java Webserver 1.0), ist Mitglied der Individual Expert Group bei JCP.org und BEA Technical Director.

Links und Literatur

  • [1] Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides: Entwurfsmuster, Addison-Wesley, 2001
  • [2] James Rumbaugh, Ivar Jacobson und Grady Booch: The Unified Modeling Language Reference Manual, Addison-Wesley, 1999
  • [3] IEEE-SA Standards Board, IEEE Recommended Practice for Architectural Description of Software-Intensive Systems
  • [4] www.adam-bien.com/
Geschrieben von
Adam Bien
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.