Woran erkennt man eine gute Softwarearchitektur?

In einem Gastbeitrag zum Blog "Modernes C++" schreibt Alexander Eisenhuth über seine Passion: gute Softwarearchitektur.

In Pocket speichern vorlesen Druckansicht

(Bild: AlexAnton / Shutterstock.com)

Lesezeit: 8 Min.
Von
  • Rainer Grimm
Inhaltsverzeichnis

Heute möchte ich einen Gastbeitrag von Alexander Eisenhuth präsentieren, der sich damit beschäftigt, was eine gute Softwarearchitektur ausmacht. Alexander ist seit 1996 selbstständig im Software-Engineering tätig. Seit mehr als zehn Jahren unterstützt er als Softwarearchitekt Entwicklungsteams in ihrer Softwarearchitekturarbeit von Embedded Systems. Alexander schreibt über seine Passion: gute Softwarearchitektur.

Modernes C++ – Rainer Grimm

Rainer Grimm ist seit vielen Jahren als Softwarearchitekt, Team- und Schulungsleiter tätig. Er schreibt gerne Artikel zu den Programmiersprachen C++, Python und Haskell, spricht aber auch gerne und häufig auf Fachkonferenzen. Auf seinem Blog Modernes C++ beschäftigt er sich intensiv mit seiner Leidenschaft C++.

"Woran erkennt man eine gute Softwarearchitektur?" Das war die Frage am Ende meines Webinars zum Thema "Agile Softwarearchitektur". Zuvor hat der Teilnehmer diese Geschichte erzählt: „Wir kommen mit unserer Embedded Software an den Punkt, an dem wir sie nicht mehr erweitern können. Die Software unterstützt unsere Gerätefamilien seit über zehn Jahren. Nach Änderungen für ein Produkt kommt es zu unerwartetem Verhalten in anderen Produkten“.

Haben Sie von einer ähnlichen Geschichte auch schon mal gehört? Der Zustand einer Software wird dann auch als „historisch gewachsen" oder "big ball of mud“ bezeichnet.

Die Frage nach der guten Softwarearchitektur ist einfach beantwortet: Eine gute Softwarearchitektur erkennt man daran, dass sie die geforderten Qualitätsmerkmale umsetzt. Im Falle der obigen Geschichte fällt es unter das Qualitätsmerkmal der Wartbarkeit von Software. Wobei wartbar ist die "historisch gewachsene" Software ja prinzipiell, nur ist es teuer, diese wieder in den gewünschten, fachlich korrekten Zustand zu überführen. Das Ergebnis ist in jedem Fall unbefriedigend:

  • hoher Aufwand und
  • die notwendigen Erweiterungen an der Funktionalität verteilt sich vermutlich über viele Stellen in der Software.

Qualitätsmerkmale werden im Qualitätsmodell ISO 25010 ausführlich beschrieben. Man erkennt, dass sich Qualitätsmerkmale auf unterschiedliche Phasen des Lebenszyklus von Software auswirken.

Es gibt einen wichtigen Aspekt bei der Priorität von Qualitätsmerkmalen. Man kann sie in wichtige, kritische und nicht relevante Qualitätsmerkmale unterteilen.

Die kritischen Qualitätsmerkmale müssen gewährleistet sein, da ohne diese der Betrieb und Verkauf der Software oder des Systems unzulässig ist. Die Einhaltung dieser Qualitätsmerkmale muss sichergestellt sein.

Wichtige Qualitätsmerkmale müssen bei der Softwarearchitekturarbeit auf jeden Fall auch beachtet werden, haben aber nicht eine unmittelbare Kritikalität.

Die Wartbarkeit ist meist ein wichtiges Qualitätsmerkmal. Die Auswirkung einer schlechten Wartbarkeit machen sich über die Jahre bemerkbar, wie unser Beispiel von Beginn zeigt.

Unter dem Qualitätsmerkmal Wartbarkeit versteht man die Güte, mit welchem zeitliche Aufwand Wartungstätigkeiten an einer Software durchgeführt werden können.

Wartungstätigkeiten sind:

  • Funktionalität erweitern: neue funktionale Anforderungen umsetzen,
  • Analysen durchführen: Fehleranalyse oder statische Codeanalyse durchführen oder interpretieren,
  • Programmierfehler beseitigen und
  • Verifikationen durchführen: Ausschließen von Fehlern nach Änderungen.

Damit ein Team effizient die oben aufgelisteten Tätigkeiten durchführen kann, ist vor allem wichtig, dass der Quellcode eine grundlegend passende Strukturierung hat. Dem Team muss klar sein, wo sich Funktionalitäten im Quellcode befinden und in welcher Art und Weise Software entwickelt wird, damit die Software weiterhin gut wartbar bleibt. Dies ist grob gesagt das Ergebnis der Softwarearchitekturarbeit:

  • Architekturentscheidungen
  • Entwurfsarbeit
  • Konzeptarbeit

Technische Konzepte bezeichnen die grundsätzliche Lösung auf eine Anforderung, die sich auf mehrere Bausteine (Komponente, Modul, Klasse) der Software auswirkt. Man bezeichnet ihre Wirkungsweise als querschnittlich. Sie beeinflussen die Wartbarkeit, weil es genau eine technische Lösung für eine Anforderung geben soll. Technische Konzepte beschreiben die konkrete Umsetzung in der Technologie der verwendeten Plattform oder Programmiersprache.

In der folgenden Tabelle sind typische technische Konzepte aufgelistet, um die Wartbarkeit von Software zu erreichen:

Zu Beginn der Entwurfsarbeit wird die grundlegende Organisation der Software festgelegt. Ein Architekturstil beschreibt diesen grundlegenden Aufbau. Architektur-Pattern sind die technisch konkrete Ausgestaltung des Architekturstils.

Um zu veranschaulichen, welche Aspekte bei der Auswahl des Architektur-Pattern eine Rolle spielen, möchte ich das anhand eines medizinischen Thermometers betrachten.

Ein digitales medizinisches Thermometer ist ein Embedded-System, das im Architekturstil eines hierarchischen Systems organisiert ist. Auf der oberen Ebene befindet sich die Software, die die darunter liegende Hardware benutzt. Auch die Software selbst ist hierarchisch gegliedert. Das ergibt sich daraus, dass in der untersten Schicht der Software sich die Hardwareabstraktion befindet, mit der die Hardware angesteuert wird.

Die Auswahl des Architektur-Pattern ist eine Architekturentscheidung. Architekturentscheidungen werden vor dem Hintergrund eines Entwicklungsprojektes in einem Unternehmen getroffen, das mit seinen technischen und organisatorischen Randbedingungen den Rahmen für die Entscheidung schafft.

Ich werde zwei Architektur-Pattern vorstellen und Aspekte in Hinblick auf Wartbarkeit beschreiben. Die Struktur der beiden Architektur-Pattern habe ich in sehr vereinfachter Form mit Blöcken ohne Darstellungen der Abhängigkeiten in den folgenden Diagrammen dargestellt.

Das Strukturieren von Software in Schichten gibt es schon seit vielen Jahren. Das grundlegende Konzept ist, Abstraktionsebenen zu schaffen, um Funktionen zu organisieren. Bei den Schichten dürfen die oberen Schichten nur auf die unterhalb liegenden Schichten zugreifen. Damit ist ausgeschlossen, dass es zyklische Abhängigkeiten gibt. Schichten könnten ausgetauscht werden und die Gesamtfunktionalität bleibt erhalten. Bei Embedded Systems ist folgendes Architektur-Pattern gängig:

Die Software des Thermometers wird bei meiner Betrachtung in drei Schichten aufgeteilt:

  1. Applikation: Beinhaltet die Anwendungsfälle des Systems. In diesem Fall die Fiebermessung und das Verhalten, wenn die Batterie zur Neige geht.
  2. Service: Liefert den Zugriff auf fachliche Abstraktionen, mit der sich Applikationen umsetzen lassen. Hier die Möglichkeit Temperaturen zu messen, diese darzustellen und einen Ton zum Signalisieren auszugeben. Wichtig ist hier, dass die Abstraktionsebene eingehalten wird und keinerlei Wissen über die Art des Hardwarezugriffs für die Applikation notwendig ist.
  3. Hardware Abstraction Layer: Bietet eine Schnittstelle an, um die Hardware anzusteuern

Anmerkungen:

  • ADC: Messung von Spannungen
  • LCD: Ansteuerung der Anzeige
  • HAL: Hardware Abstraction Layer

Komponenten stellen eine für das System spezifische Funktionalität über angebotene Schnittstellen zur Verfügung. Zu Ihrer Funktion benötigen Komponenten weiter Funktionalität, die sie über benötigte Schnittstellen erhalten.

Komponenten können unabhängig voneinander entwickelt werden, wenn die benötigten und angebotenen Schnittstellen deklariert sind. Darüber hinaus benötigen Komponenten technische Funktionalitäten wie Laufzeitbibliotheken der Programmiersprache. Bei Embedded Systems ohne Betriebssystem werden Komponenten als statische Bibliotheken realisiert.

Die Wiederverwendbarkeit ist die treibende Kraft bei dem Aufbau einer Software aus Komponenten.

Bei der hier dargestellten Komponentenarchitektur handelt es sich ebenfalls um einen hierarchischen Architekturstil. Die Applikationsschicht ist die oberste Schicht und benutzt die dargestellten Komponenten. Die Komponenten besitzen eine Serviceschicht und einen HAL.

Der auffälligste Unterschied ist, dass die Software der Komponentenarchitektur auf der ersten Ebene in sechs und die Schichtenarchitektur in drei Blöcke aufgeteilt ist. Man hat im Fall der Komponentenarchitektur eine feinere Aufteilung der Software.

Ein weiterer Unterschied ist, dass die Komponentenarchitektur funktionale Blöcke mit Kohäsion bildet. Die Kohäsion bezeichnet die Zusammengehörigkeit innerhalb eines Blocks. Die Kohäsion wird durch die Funktionalität der Komponente vorgegeben.

Bei der Komponentenarchitektur kommt der Block ADC mehrfach vor.

Die potenziellen Vorteile der Komponentenarchitektur erkauft man sich mit einem erhöhten Aufwand bei der Implementierung von Komponentenschnittstellen. Für die Auswahl des Architektur-Pattern ist auch nicht alleine das Qualitätsmerkmal der Wartbarkeit ausschlaggebend. Es kommt wie bereits erwähnt auf den Hintergrund eines Entwicklungsprojektes an.

Bei einem sehr einfachen System wie dem Thermometer wird sich der Aufwand, die Software in Komponenten aufzuteilen, nicht lohnen. Aber bei Systemen mit höherer Komplexität oder wenn es um Varianten in den Produkten oder Geräten geht, kann auch bei einfachen Systemen eine Komponentenarchitektur durchaus Sinn ergeben.

Auf jeden Fall ist Softwarearchitekturarbeit ein wichtiger Teil eines Entwicklungsvorhabens. Qualitätsmerkmale im Nachhinein in eine Software zu implementieren ist teurer als diese zu Beginn zu berücksichtigen.

  • Wartbarkeit ist ein Qualitätsmerkmal von Software,
  • je besser eine Software wartbar ist, desto geringer ist der zeitliche Aufwand für Wartungsaufgaben (Analyse, Erweiterung, Verifikation) und
  • die Auswahl des Softwarearchitekturstils ist eine wichtige Architekturentscheidung mit großer Tragweite.

Wartbarkeit erhält man durch

  • einen passenden Softwarearchitekturstil,
  • gute technische Konzepte für Wartbarkeit und
  • dem Problem angemessene Entwurfsarbeit.

In meinen nächsten Artikel werde ich tiefer auf die Architektur-Pattern Schichtenarchitektur, Pipes-and-Filters, Broker, Model View Controller, und Reactor eingehen. (rme)