Unified Modelling Language

UML für die Systemarchitektur

25.08.2011 von Stefan  Queins
Wer die Unified Modeling Language (UML) zur Entwicklung kompletter Systeme einschließlich Hardware verwendet, muss auf einige Anpassungen der Notation achten.

Die UML gilt in der Softwareentwicklung seit einiger Zeit als gängiges Notationsmittel, um die Ergebnisse der Analyse (Was soll meine Software tun?) und Architektur (Wie ist meine Software realisiert?) zu dokumentieren. Nun liegt die Frage nahe, ob und wie sich diese Notation auf einen geänderten Betrachtungsgegenstand, einem System, übertragen lässt, um Erfahrungen und Synergieeffekte, insbesondere zur Nachverfolgbarkeit von Anforderungen, auszunutzen.

Die für ein Türsystem benötigten Komponenten lassen sich in der UML durch Stereotypen zusätzlich klassifizieren. So werden logische Komponenten spezifiziert.
Foto: Sophist

Für die Analyse existiert kein wesentlicher Unterschied für die beiden Typen von Betrachtungsgegenständen und damit können die Notationen aus der Softwareanalyse relativ einfach für die Systemanalyse übernommen werden. In der Architektur wird das System ebenso wie die Software eine Zerlegung des Ganzen in kleinere, überschaubare Teile vorgenommen. Für die so gefundenen Komponenten müssen deren Aufgaben und Zusammenspiel festgelegt werden. Zu beachten sind dabei sowohl statische als auch dynamische Aspekte, die die Struktur des Systems und den Ablauf der geforderten Funktionen definieren. Bei genauerer Betrachtung finden sich schnell die ersten Unterschiede zwischen der System- und der Softwarearchitektur.

Architekturunterschiede

Zunächst einmal gibt es in der Systemarchitektur keine Artefakte oder Prozesse, die man auf eine Systemlandschaft verteilen muss. Es werden also keine Prozess- oder Verteilungssichten benötigt, wie man sie aus der reinen Softwarearchitektur kennt. Je nach Art der Systemzerlegung muss aber möglicherweise eine Gruppierung der Systemkomponenten zu räumlichen Komponenten (Schränke, Einsteckkarte etc.) vorgenommen werden.

Ein weiterer Unterschied zeigt sich in der Art der Komponenten, aus denen ein System besteht. In der Softwarearchitektur werden natürlich nur reine Softwarekomponenten benötigt. In der Systemarchitektur braucht man jedoch eine zusätzliche Möglichkeit, um Software3- und Hardwarekomponenten4 unterscheiden zu können. Die Komponentenbildung unterliegt außerdem anderen Gesichtspunkten. So kann für die Zerlegung eines Systems ein wichtiges Kriterium die Beauftragung durch externe Lieferanten sein, was man bei der Softwarearchitektur eher selten findet. Ebenso lässt sich leicht erahnen, dass typische Muster aus der Softwarearchitektur5 wie das Schichtenmodell oder Pipes and Filter nicht ohne weiteres in die Systemarchitektur übertragen werden können.

Da sich die Unterschiede im Entwurf einer System- und Softwarearchitektur hauptsächlich auf Tätigkeiten beschränken, sich die erzeugten Ergebnisse in ihrer Art aber ähneln, stellt die UML auch für Systeme eine adäquate Möglichkeit dar, einen Großteil dieser Ergebnisse zu dokumentieren. Es geht nicht darum, bewährte Notationen der Hardwareentwicklung wie zum Beispiel Konstruktionszeichnungen abzulösen. Vielmehr bietet die UML in einigen Bereichen eine gewinnbringende Zusatzoption. Dies ist der Fall, wenn es um die Kommunikation der an der Systementwicklung beteiligten Teams geht, um die Nachvollziehbarkeit der Entwicklungsentscheidungen oder um einen leichteren Übergang zur Softwareentwicklung.

Start mit Use-Case-Analyse

Der Ausgangspunkt für ein auf der UML 2.0 basierendes Modell der Systemarchitektur ist die vollständige Systemanalyse, aus der die Anforderungen an das System bis zu einer gewissen Tiefe hervorgehen. Eine Technik hierfür ist die Use-Case-Analyse, mit der die funktionalen Anforderungen an ein System ermittelt und dokumentiert werden können. Dieser Ansatz schließt mit ein, dass die Use Cases (typische Interaktionen des Systems mit seiner Umwelt) durch Aktivitätsdiagramme oder, vor allem bei Realtime-Embedded-Systemen, durch Zustandsautomaten detailliert werden. Darüber hinaus bilden die nichtfunktionalen Anforderungen wie Zuverlässigkeit, Sicherheit oder die Einbettung des Systems in seine Umwelt eine wichtige Eingabe in die Systemarchitektur. Auch diese Aspekte werden in der Systemanalyse erhoben und dokumentiert.

In der Praxis wird man kaum eine vollständige Systemanalyse vor den ersten Architekturtätigkeiten erreichen. Normalerweise ergibt sich ein verzahnter Prozess zwischen einer groben Analyse, den ersten Architekturfestlegungen sowie einer Verfeinerung der Analyseergebnisse.

Die Strukturierung eines Systems ist nur eine von mehreren Tätigkeiten, die ein Architekt vorzunehmen hat. Eine zweite ist die Beschreibung der Komponenten innerhalb dieser Struktur, insbesondere die Beschreibung der Aufgaben der einzelnen Komponenten. Die Definition der Schnittstellen zwischen den Komponenten bildet den dritten wichtigen Aspekt in der Architektur. Das Ziel der Systemarchitektur ist es somit, sowohl für die Software- als auch für die Hardwareentwicklung, solche Komponenten zu beschreiben, die möglichst losgelöst von den anderen Komponenten realisiert werden können.

Alle drei Tätigkeiten sind eng miteinander verbunden. Sie beeinflussen sich gegenseitig und liefern Input für die jeweils anderen Tätigkeiten. Aus diesem Grund werden die Tätigkeiten in der Systemarchitektur nicht wasserfallartig ausgeführt, sondern iterativ und eng verzahnt.

Drei Aufgaben

Die Tätigkeiten eines Systemarchitekten bestehen im Wesentlichen aus drei übergeordneten Aufgabenbereichen, die sich bei der Durchführung wechselseitig beeinflussen:

  • Zunächst gilt es für die Strukturierung des Systems die Komponenten zu identifizieren. Dazu muss er das System in kleine, unabhängig voneinander realisierbare Einheiten zerlegen und diese in einem hierarchischen Baum darstellen.

  • Im zweiten Schritt muss er die Aufgaben der Komponenten festlegen. Zusammengenommen müssen die Aufgaben die Anforderungen beziehungsweise gewünschten Funktionen eines Gesamtsystems erfüllen.

  • Schließlich geht es um die Schnittstellen. Sie beschreiben die Daten und Funktionen, die eine Komponente zur Verfügung stellt.

Komponenten identifizieren

Das Türsystem enthält die Softwarekomponente "Lokale Türsteuerung" mit den in der UML notierten Use-Cases der Komponente, wobei auch die Kommunikationspartner dargestellt sind.
Foto: Sophist

Um Komponenten zu identifizieren, wird das System nach und nach vollständig zerlegt und ein hierarchischer Baum von Komponenten erzeugt. So kann das betrachtete System aus Subsystemen aufgebaut sein, die wiederum aus einzelnen Segmenten bestehen. Bis zu welcher Ebene Sie die Zerlegung treiben sollten, ist im Prinzip leicht zu beantworten: Es gilt, Komponenten zu finden, deren Umsetzung die Realisierung anderer Komponenten nicht mehr beeinflusst. Eine Ausnahme bilden hier natürlich die Schnittstellen der Komponenten. Als Randbedingung gilt hierbei natürlich, dass Sie für die Komponenten der untersten Ebene auch eine Abteilung oder externen Zulieferer finden, der diese Komponente für Sie entwickeln kann.

Ein Kriterium bei der Strukturierung des Systems auf den höheren Ebenen kann die räumliche Anordnung der Systemteile sein. Besteht das System zum Beispiel aus mehreren, voneinander getrennten Baugruppen, so können diese die erste Hierarchieebene in der Komponentenzerlegung bilden. Ferner kommen die aus der Softwarearchitektur bekannten Prinzipien für das Schneiden von Komponenten zum Tragen. Das sind zum Beispiel eine hohe Kohäsion, eine geringe Kopplung oder eine überschaubare Anzahl von Komponenten.

Zur Darstellung der Systemkomponenten verwendet man als Notationsmittel die UML-Komponenten. Diese können durch die so genannten Stereotypen zusätzlich klassifiziert werden, die Angabe erfolgt in spitzen Klammern. So lässt sich beispielsweise die Unterscheidung zwischen logischen, das heißt gruppierenden Komponenten beziehungsweise Hard- und Softwarekomponenten über die Stereotypen <<logical>>, <<HW>> und <<SW>> abbilden, oder als weitere mögliche Unterscheidung <<HW-Elektronik>> und <<HW-Mechanik>>.

Die Wahl der Stereotypen richtet sich häufig nach den Vorgaben an Ihr Projekt. So wird in V-Modell-basierten Projekten der Stereotyp <<logical>> häufig durch die Begriffe Subsystem, Segement und Subsegement weiter differenziert.

Iteratives Vorgehen

Bei der Erstellung der Komponentenhierarchie können Sie Top-down, Bottom-up oder Middle-out vorgehen. Letzteres bedeutet, dass man Komponenten auf den mittleren Hierarchieebenen identifiziert und diese dann sowohl nach unten hin verfeinert als auch nach oben hin zusammenfasst. In der Praxis geht man selten streng nach einer Methode vor, sondern wechselt zwischen allen drei Verfahren. Dabei steht allerdings besonders am Anfang von Neuentwicklungen meistens das Top-Down-Vorgehen im Vordergrund.

Wird ein Punkt erreicht, an dem eine weitere Aufteilung einer Komponente schwerfällt, sollte man zunächst ihre Aufgaben definieren. Dieses zusätzliche Wissen über die Komponente ist eine gute Grundlage für das weitere Vorgehen hinsichtlich ihrer Zerlegung. Gerade im Rahmen von Neuentwicklungen ist diese iterative Herangehensweise nützlich.

Komponenten und ihre Aufgaben

Nachdem die Komponenten identifiziert wurden, muss man sich Gedanken darüber machen, welche Rollen sie im zukünftigen System spielen werden. Daher beschäftigt sich die zweite Tätigkeit innerhalb der Systemarchitektur damit, die Aufgaben von Komponenten festzulegen. Bereits in der Systemanalyse, möglicherweise in Form von System-Use-Cases und deren Verfeinerungen, wurden die Anforderungen und gewünschten Funktionen des Systems erarbeitet. Nun geht es darum, diese Anforderungen auf die einzelnen Komponenten zu verteilen und damit auszudrücken, welche Aufgaben welche Komponenten übernehmen. Durch dieses Vorgehen ergibt sich auch ein Kriterium, wie weit Sie die Verfeinerung in der Systemanalyse treiben sollten: Eine Anforderung sollte weiter verfeinert werden, bis die sich ergebenden Anforderungen eindeutig einer Komponente des Systems zugewiesen werden kann. Bei der Entscheidung, welche Aufgabe in welcher Komponente realisiert werden soll, spielen die nichtfunktionalen Anforderungen wie Zuverlässigkeit, Zeitverhalten, Fehlertoleranz etc. eine wichtige Rolle.

Aus diesen Aufgaben werden nun die formalen Anforderungen an die Komponenten bestimmt. Diese Tätigkeit entspricht einer konventionellen Analyse der einzelnen Komponenten, ähnlich wie in der Systemanalyse die Anforderungen an das Gesamtsystem erarbeitet wurden. Aus diesem Grund lassen sich auch die bekannten Analysemethoden wie Use Case und deren Detaillierungen heranziehen. Nur eben mit dem Unterschied, dass nun nicht das gesamte System, sondern eine Komponente im Mittelpunkt der Analyse steht. Demnach werden im Use-Case-Diagramm einer Komponente als Systemgrenze die betrachtete Komponente und die Use-Cases der Komponente auftauchen. Die Akteure werden durch die Nachbarkomponenten gebildet, die an der Bearbeitung der Komponenten-Use-Cases beteiligt sind.

Als Ausgangspunkt für die Use-Case-Analyse einer Komponente werden alle zuvor zugewiesenen Aufgaben betrachtet, diese eventuell zu neuen Use Cases zusammengefasst und die Use Cases weiter detailliert. Es gibt natürlich neben der Use-Case-Analyse auch die Möglichkeit, das (gewünschte) Verhalten einer Komponente durch einen Zustandsautomaten oder einfach durch natürlichsprachliche Anforderungen zu beschreiben.

Schnittstellen festlegen

Da die Komponenten in einem Gesamtsystem arbeiten, benötigen diese Schnittstellen, über die Daten und Funktionen für die Realisierung der Systemfunktionen ausgetauscht bzw. genutzt werden. Ziel dieser dritten Architekturtätigkeit ist es, genau diese Schnittstellen zwischen den Komponenten festzulegen.

Die Darstellung von Schnittstellen kann in der UML als Klasse mit dem Sterotyp "Interface" erfolgen. Eine Komponente, die einer anderen eine Schnittstelle zur Verfügung stellt, wird mit dieser über eine "Realize"-Beziehung verbunden, umgekehrt verwendet man eine "Use"-Verbindung. Alternativ dazu ist die „Ball and Socket“-Notation. Über den Stereotyp "Delegate" werden die von Subkomponenten angebotenen Schnittstellen abgebildet.
Foto: Sophist

Prinzipiell unterscheidet man zwischen "angebotenen" (provided) und "benötigten" (required) Schnittstellen. Eine angebotene Schnittstelle stellt Dienste/Daten nach außen zur Verfügung, wohingegen eine benötigte Schnittstelle Dienste/Daten von außen in Anspruch nimmt. Diese Unterscheidung ist oft nicht einfach, da durch sie in dieser Phase der Entwicklung noch keine Aussagen über die Kommunikationsrichtung getroffen werden sollte. Man sollte an dieser Stelle intuitiv vorgehen und das Anbieten von Diensten/Daten als angebotene Schnittstelle modellieren.

Zum Finden der Schnittstellen können Sie die Use-Case-Diagramme der Komponenten und deren Verfeinerungen ausnutzen, da dort ja die Beteiligung der Nachbarkomponenten an einem Use-Case beschrieben wird.

Die UML bietet unterschiedliche Darstellungsmöglichkeiten für Schnittstellen. Eine davon sind die Interface-Klassen. Hier legt man eine Klasse mit dem Stereotyp <<interface>> an. Die Komponente, die dieses Interface zur Verfügung stellt, wird anschließend über eine <<realize>>-Beziehung verbunden, die verwendende Komponente über eine <<use>>-Beziehung mit dieser Klasse. Eine abkürzende Schreibweise ist die Notation "Ball & Socket". Hier werden die angebotene Schnittstelle über eine Kugel (den so genannten Lollipop) und die benötigte Schnittstelle über einen Halbkreis dargestellt.

Prinzipiell sollte jede Komponente in der Komponentenhierarchie Schnittstellen besitzen, um die abstrakte Sicht auf die Zerlegung vollständig zu unterstützen. Wenn eine Komponente eine Schnittstelle anbietet, bedeutet dies nicht zwingend, dass diese die Schnittstelle direkt realisiert, also zum Beispiel ein Stück Code implementiert werden muss. Nehmen wir als Beispiel dafür die Schnittstelle einer Komponente auf unterster Ebene. Genau diese Schnittstelle möchten wir auch in der darüber liegenden Komponente sichtbar machen. In diesem Fall können Schnittstellen nach oben delegiert werden. Das bedeutet, eine Komponente stellt die Schnittstelle ihrer Subkomponente zur Verfügung, hat aber keinen Realisierungsanteil für diese Schnittstelle. So wird im Beispiel die Schnittstelle Lokale Steuerung vollständig von der Komponente Taster realisiert. Anders sieht es aus, wenn eine Komponente mehrere Schnittstellen ihrer Subkomponenten zusammenfasst, also eine Art Fassade bildet. Hier muss auch die darüber liegende Komponente einen Teil der Realisierung übernehmen.

Das Delegieren von Schnittstellen wird in der UML-Notation über eine Abhängigkeitsrelation mit dem Stereotyp <<delegate>> dargestellt. Diese Beziehung zeigt von der zu delegierenden Schnittstelle der Subkomponente auf die delegierende Schnittstelle der übergeordneten Komponente.

Da in der Systemarchitektur nicht nur reine Software betrachtet wird, ist es oft wichtig, alle Aspekte einer Schnittstelle zu beschreiben. Bisher haben wir die logischen Informationen betrachtet, die direkt mit den Mitteln der UML dargestellt werden können. Hinzu kommen physikalische Informationen bei elektrischen und mechanischen Schnittstellen und Informationen über Protokolle bei Software-Schnittstellen. Diese Informationen können in der UML über Stereotypen (<<electrical>>, <<mechanical>> etc.) und eine Erweiterung durch spezielle Attribute für die jeweiligen Stereotypen modelliert werden.

Der Ablauf der Zusammenarbeit der Komponenten für einen System-Use-Case, also das dynamische Nutzen der Schnittstellen untereinander, kann in der UML mit Hilfe von Sequenzdiagrammen dargestellt werden. Hier kann man formaler werden und mehr Informationen gerade über die Zusammenarbeit von Softwarekomponenten modellieren. Als Kommunikationspartner erscheinen die an der Realisierung eines Use-Case beteiligten Komponenten. Die Nachrichten in dem Sequenzdiagramm bilden dann die Aufgaben der Komponenten ab. Eine Nachricht kann entweder der Aufruf einer Operation sein (synchrone Nachricht) oder das Senden eines Signals/ Events (asynchrone Nachricht).

Wie geht es weiter im Projekt?

Während die gefundenen Hardwarekomponenten einer Systemarchitektur relativ losgelöst voneinander entwickelt werden können, kommt den Softwarekomponenten eine Sonderrolle zu. Die Use-Cases der Softwarekomponenten, die gemeinsam entwickelt werden sollen, werden in den meisten Fällen wieder in einen Topf geworfen und einer expliziten Softwareanalyse unterzogen. Es liegt nahe, dass sich gewisse Aufgaben der Softwarekomponenten wiederholen und somit eine getrennte Entwicklung nach Systemkomponenten eine unnötige Mehrarbeit bedeuten würde. Anschließend wird dann die zu entwickelnde Software in der Softwarearchitektur logisch zerlegt und danach zu den aus der Systemarchitektur geforderten Teilen zusammengesetzt.

Fazit

Die UML kann als Notation für die Darstellung einer Systemarchitektur eingesetzt werden. Ein zentraler Bestandteil ist dabei die Stereotypisierung sowohl im Bereich der Komponentenbildung als auch für die Schnittstellenklassifizierung. Außerdem lassen sich Analysetechniken wie die Use-Case-Analyse in der Systemarchitektur für eine nähere Untersuchung der Systemkomponenten verwenden.

Durch die Verwendung der UML als einheitliche Beschreibungssprache in den verschiedenen Phasen der Systementwicklung wird eine Kommunikation der beteiligten Organisationseinheiten unterstützt und die Möglichkeit gegeben, die häufig geforderte Verfolgbarkeit von Anforderungen von Systemanforderungen bis hin in die Implementierung zu realisieren.

Literatur

  • Buschmann, F.: Pattern-orientierte Software-Architektur, Addison-Wesley GmbH, 1998.

  • Queins, S.; Rupp, C.: Profile helfen bei der Arbeit mit UML, www.computerwoche.de/ 572838.

  • Rupp, C.; Hruschka, P.: Agile Softwareentwicklung - für Embedded Real-Time Systeme mit der UML, Hanser, 2002.

  • Rupp, C.; Hahn, J.; Queins, S., u.a.: UML 2 glasklar, Hanser, 2005.

  • Starke, G.: Effektive Software-Architekturen, Hanser, 2002.

Über den Autor:
Dr. Stefan Queins (SOPHIST) unterstützt die Einführung neuer Methoden bei der Entwicklung komplexer Systeme. Er ist Autor von UML-Glasklar und Requirements-Engineering und -Management.