Skip to main content
swissICT Booster  |  M&F Academy  |  M&F Events   |  +41 44 747 44 44  | 
5 Minuten Lesezeit (1078 Worte)

Modularisierung und komponentenorientierte Entwicklung

Die meisten Menschen, die mit Applikationen arbeiten, welche Plugins unterstützen, haben die Vorteile und Flexibilität von Komponenten-basierten Systemen erfahren dürfen. Selbst wenn eine Applikation keine Erweiterungen oder Modifikationen in Form von Plugins unterstützen soll, ist es sehr vorteilhaft, die Applikation komponentenorientiert aufzubauen. Dies ermöglicht Teile der Applikation auszutauschen oder umzuschreiben, ohne dass sich die Änderungen durch den ganzen Code ziehen. Zu diesem Thema gab Dr. Matin Bättig von der Hochschule Luzern uns ein Workshop, den ich hier zusammenfasse.

Was ist eine Komponente?

Das Plugin "System" aus der Einleitung war bereits ein Beispiel für Komponenten. Aber bevor wir weiter über diese Komponente sprechen, müssen wir diese erst definieren. Eine Komponente ist eine eigenständige Software-Einheit. Das heisst, sie funktioniert ohne Wissen über andere Komponenten. Die Interaktion mit den weiteren Komponenten geschieht über klar definierte Schnittstellen. Die verschiedenen Komponenten werden anschliessend durch eine Orchestration miteinander verbunden und ergeben so das gesamte System. Diese Definition lässt sich auch rekursiv anwenden.

Darstellung eines komponentenbasierten Systems

Damit alle Komponenten miteinander interagieren können, müssen sie das gleiche Komponenten-Modell haben. In diesem ist der Komposition-Standard, der definiert, wie die Komponenten ausgeliefert und anschliessend zusammengefügt werden. Zudem beinhaltet es den Interaktionsstandard, welcher die Schnittstellenspezifikationen enthält. Die Komponenten interagieren unterschiedlich miteinander und sind abhängig, ob diese lokal gespeichert aber auch, ob Schnittstellen als Java oder C# Interfaces, Google Protocol Buffers oder OpenAPI definiert sind. 

Schnittstellen Design

Schnittstellen sind ein zentraler Bestandteil von Komponenten. Sie helfen die Komponenten voneinander zu entkoppeln. Bildlich kann man sich eine Schnittstelle wie einen Vertrag vorstellen. Eine Komponente, die eine Schnittstelle anbietet, ist sozusagen der Handwerker, der gemäss eines Vertrages etwas herstellt. Der Konsument der Schnittstelle ist der Kunde, der erwartet, dass er das erhaltet, was im Vertrag definiert ist. Diese Separierung erlaubt auch die Wiederverwendung und den Austausch von Komponenten. Anders gesagt, wenn ein neuer Handwerker den Vertrag erfüllt oder wenn in einem anderen Projekt die gleiche Handwerksarbeit gebraucht wird, kann man den Vertrag duplizieren und auch für das neue Projekt verwenden.

Damit solche Schnittstellen gut verwendet werden können, sollte beim Entwerfen auf folgende Kriterien geachtet werden:

  • Eine Schnittstelle soll schmal sein, um sie optimal wiederverwenden zu können. Das heisst, sie soll so wenig Funktionen wie möglich enthalten. Es ist einfacher, ein Interface zu erweitern anstatt Funktionen zu entfernen, da dies den anderen Code nicht beeinflusst. Zudem sind kleine Interfaces einfacher zu benützen, weil sie einen kleineren Implementationsaufwand mit sich ziehen. 

  • Eine konsistente und intuitive Benennung ist wichtig. Ein Interface soll einfach zu verwenden sein, um Fehler bei der Verwendung zu minimieren.

  • Eine Schnittstelle soll immer dokumentiert sein. Selbst ein gut gewählter Name macht nicht alles ersichtlich. Es ist wichtig, in einem Interface anzugeben, welche Bedingungen für die Eingabeparameter gelten und welches Ergebnis die Ausführung liefert.

  • Eine Schnittstelle soll stabil sein. Das heisst, die Schnittstelle soll sich nicht gross ändern. Da sonst alle Komponenten, welche die Schnittstelle verwenden, ebenfalls angepasst werden müssen. Dies würde viel zusätzlicher Aufwand generieren.

 

Dieser Ausschnitt aus der Dokumentation der Java util.Date Klasse zeigt ein schlechtes Beispiel eines Interfaces, da sowohl der Monat und das Jahr nicht intuitiv verwendet werden.

 

Modularisierung

Wenn wir ein Softwareprojekt starten, beginnen wir oft mit den Spezifikationen für das gesamte System. Um nun für dieses System Komponenten zu bekommen, müssen wir es modularisieren. Der Standardansatz, der gewählt wird, ist oft eine Partitionierung entlang der technischen oder fachlichen Aufgaben. 

Schemenhafte Darstellung, wie Komponenten einer technischen und fachlichen Partitionierung aussehen können.

Das Ziel einer Modularisierung ist es, eine kleine Kopplung zwischen den Komponenten zu haben. Gleichzeitig soll die Kohäsion innerhalb einer Komponente hoch sein. Dies bedeutet, die Anzahl der Abhängigkeiten zwischen den Komponenten soll so klein wie möglich und innerhalb einer Komponente so gross wie möglich sein.

Zusehen ist hier eine schemenhafte Darstellung von Komponenten. Die linke Seite zeigt ein schlecht modularisiertes Beispiel, bei dem die Komponenten intern wenig Kohäsion haben und stark miteinander gekoppelt sind. Die rechte Seite zeigt ein gut modularisiertes Beispiel mit viel Kohäsion innerhalb der Komponenten und wenig Kopplung zwischen den Komponenten.

Bei einer technischen Partitionierung ist die Kopplung zwischen den technischen Schichten oft hoch, da es zwischen den Schichten oft starke Abhängigkeiten gibt. Zudem sind die Komponenten verschiedener fachlichen Bereichen in einer Schicht für das Gleiche zuständig und haben so zumindest eine logische Abhängigkeit. Nichtsdestotrotz haben sie aber oft keine funktionale Abhängigkeit. Somit ist auch die Kohäsion nicht ideal.

Bei einer fachlichen Partitionierung sind Kopplung und Kohäsion sehr viel besser. Da ist aber oft das Problem, dass eine Wiederverwendbarkeit nicht gegeben ist. Häufig müssen sogar gewisse Teile des Codes dupliziert werden.

Um eine gute Modularisierung zu erhalten, sollte man bei der Aufspaltung des Systems auf folgende Punkte achten:

  • Ein Softwareproblem soll in weniger komplexe Teilprobleme zerlegt und so verknüpft werden, dass die Teile möglichst unabhängig voneinander bearbeitet werden können. Dabei soll darauf geachtet werden, dass zwischen den Teilproblemen eine möglichst geringe Abhängigkeit besteht.

  • Ein kombinierbares Software-Element soll möglichst frei sein und sich auch in einem anderen Umfeld wieder einsetzen lassen.

  • Die resultierenden Teilsysteme sollen unabhängig voneinander zu verstehen und zu unterhalten sein. Dies erleichtert die Einarbeitung neuer Mitarbeitenden und hält den Aufwand für den Softwareunterhalt tief.

  • Da sich die Anforderung an eine Software mit der Zeit wandelt, sollte eine kleine Änderung der Anforderungen auch nur dazu führen, dass ein kleiner Teil der Module angepasst werden muss.

Daraus lässt sich der folgende Algorithmus für eine Modularisierung herleiten:

  1. Zerlegung des Systems durch Abspaltung wiederverwendbarer Komponenten oder Abspalten eines vom Rest mehrheitlich unabhängigen Teilsystems.

  2. Beurteilung der Modularisierung hinsichtlich der Kriterien:

    1. Haben die Komponenten die erwünschte Grösse und Komplexität?

    2. Kann ich Komponenten weiter aufteilen, um einen der zuvor genannten Punkte zu verbessern?

    3. Würde eine weitere Aufteilung der Komponenten die Komplexität des System erhöhen oder entstehen  Vorteile dadurch?

  3. Falls alle Kriterien zufriedenstellend sind: fertig. Ansonsten zurück zu Punkt 1.

Schlussgedanken

Es erfordert zwar zusätzlichen Aufwand, eine Anwendung aus solchen Komponenten aufzubauen, aber es lohnt sich oft, diesen Aufwand zu betreiben. Die unabhängigen Komponenten ermöglichen eine einfache Teamarbeit, da sich jeder auf eine Komponente konzentrieren kann, ohne von den anderen abhängig zu sein. Ausserdem ermöglichen die Schnittstellen eine einfache Wiederverwendung von Komponenten, wenn dieselbe Funktionalität an anderer Stelle in der Software oder sogar in anderen Softwareprojekten benötigt wird. Dadurch wird der Entwicklungsaufwand reduziert.

Es gibt möglicherweise bereits Open-Source-Komponenten, welche die gewünschten Funktionen bereitstellen, sodass sie nicht selbst entwickelt werden müssen. Die Möglichkeit, Komponenten auszutauschen, erleichtert es zudem, auf zukünftige Änderungen der Anforderungen zu reagieren. Diese Vorteile sorgen dafür, dass der Mehraufwand durch die Modularisierung kurzfristig durch die reduzierte Entwicklungszeit und langfristig durch die einfachere Wartbarkeit ausgeglichen wird.

0
Jubiläum bei der EBP - 10. Trainee startet seinen ...
Ein Toast auf unser Team und unser eigenes Bier!

Ähnliche Beiträge

 

Kommentare

Derzeit gibt es keine Kommentare. Schreibe den ersten Kommentar!
Sonntag, 28. April 2024

Sicherheitscode (Captcha)