Johannes Kepler Universität Linz
System Software Group

Seminar Softwareentwicklung - Programmierstil WS 2002/2003

Modularisierung

Autor: Helmut Schmidauer
Leitung: Prof. Hanspeter Mössenböck

Abstract

Viele Dinge des täglichen Gebrauchs bestehen aus einzelnen Modulen. Module helfen dabei die Funktionsweise eines Systems schrittweise zu erforschen und dienen dazu neue Systeme durch Wiederverwendung von Komponenten einfacher und schneller aufzubauen. Diese Konzepte sind natürlich für die Softwareentwicklung ebenso wichtig und erforderlich. Dieses Dokument beschreibt einige Prinzipien und Kriterien bei der Modularisierung von Softwaresystemen.

Wozu Modularisierung von Software ?

Modularisierung ist eine wichtige, wenn nicht sogar die wichtigste Technik des Software Entwicklungsprozesses. Sie unterstützt folgende Eigenschaften eines Systems:

Modul

Definition des Modulbegriffs [BlPo93]:

Als praktische Anwendung dieser Definition kann versucht werden, zu erproben welche, häufig als Modul bezeichnete, Begriffe dieser Beschreibung entsprechen.

Prozedur / Methode: - Nein
Die drei letzten Definitionen treffen sehr wohl auf Prozeduren zu. Eine (nicht triviale) abgeschlossene Aufgabe wird aber bei vernünftiger Modularisierung wahrscheinlich auf mehrere Prozeduren verteilt sein. Modularisierung geschieht natürlich auf verschiedenen Ebenen und auch ein Modul ist meist modular aufgebaut. Laut dem ersten Satz der Definition zählt die unterste Ebene aber nicht zu den hier behandelten Modulen.

Klasse: - Ja
In der objektorientierten Programmierung ist die Klasse das Modul schlechthin. Damit eine Klasse aber tatsächlich der obigen Definition entspricht, ist wohl überlegtes Klassendesign von Nöten. Eine Klasse ist also ein besonders gutes Mittel zur Modularisierung von Softwaresystemen. Zu beachten ist die eindeutige Schnittstelle eines Moduls, die bei Klassen durch die Möglichkeit der Vererbung oft erweitert wird.

Java Package: - Nein
Packages werden sehr oft als Module bezeichnet, entsprechen dem aber, meiner Meinung nach, laut dieser Definition überhaupt nicht. In erster Linie ist bei Packages eine wohldefinierte Schnittstelle meist nicht gegeben.

Komponente: - Ja
Softwarekomponenten wurden dazu geschaffen als Module einsetzbar zu sein. Während bei einer Klasse erst das richtige Design ein "echtes" Modul ergibt, entspricht eine Komponente schon per Definition dem obigen Modulbegriff.

Subsystem: - Jein
Wie schon erwähnt geschieht die Moduleinteilung in verschiedenen Ebenen. Subsysteme sind sicher die oberste Ebene der Gliederung eines Systems. Die Gliederung in Subsysteme geschieht oft nach unterschiedlichen Gesichtspunkten. Man kann daher nicht allgemein sagen, ob ein Subsystem ein Modul laut dieser Definition ist.

Information Hiding

Wenn es darum geht ein modulares System zu entwickeln, so ist Information Hiding ist ein wesentliches Entwurfsprinzip. Man versperrt beziehungsweise versteckt die wichtigsten Informationen und stellt kontrollierte Vorgangsweisen zur Verfügung, um den Zugriff darauf zu ermöglichen. Nur so wird ermöglicht, dass die Verbindung und Kommunikation zwischen Modulen übersichtlich und in geregelten Bahnen geschieht.

Es ist wichtig, die "geheimen Bereiche" eines Systems zu identifizieren. Es handelt sich hierbei in erster Linie um die Daten (Datenkapselung siehe unten) und um Bereiche bei denen häufige Änderungen zu erwarten sind.

Beispiele[McCo93]:

Datenkapselung

Datenkapselung ist die am meisten verbreitete und wichtigste Form von Information Hiding. Man trennt die konkrete Implementierung einer Datenstruktur von ihren sichtbaren Eigenschaften. Das Ergebnis nennt man Abstrakte Datenstruktur. Die Datenstruktur selbst ist verborgen. Man greift nur auf die Schnittstelle zu. Diese besteht aus Operationen, die den Umgang mit der Datenstruktur beschreiben.

Modularisierung

Modularisierung ist die Zerlegung eines Systems in einzelne Module. Eine Entscheidung, welche Teile in einem Modul zusammengefasst werden und welche Teile in unterschiedliche Module aufgeteilt werden, soll unter Berücksichtigung folgender Kriterien erfolgen:

Modulgeschlossenheit

Ein Modul soll für eine geschlossene Aufgabe zuständig sein. Die Definition dieser Aufgabe kann nach unterschiedlichen Aspekten geschehen.

Bibliothek Algorithmus Daten

Modulbindung - Modulkopplung

Die Modulbindung Ist ein Wert, der die Summe der Beziehungen zwischen den einzelnen Operationen und Daten eines Moduls repräsentiert. Eine hohe Modulbindung deutet auf eine gute Zusammenstellung eines Moduls hin.

Die Modulkopplung stellt die Summe der Beziehungen zwischen den einzelnen Modulen eines Systems dar. Eine geringe Modulkopplung ist ein Zeichen für eine gute Modularisierung eines Systems. Verteilte Funktionen und globale Daten führen zu einer hohen Modulkopplung.

Für beide Maßzahlen gibt es allerdings Extreme. Ein System, das aus nur einem Modul besteht hat eine hundertprozentige Modulbindung und eine Modulkopplung von Null. Betrachtet man die beiden Eigenschaften als Funktion der Modulanzahl, so findet sich ein Punkt in der Summenkurve, in dem die Komplexität des Systems am Geringsten ist.

Minimalität der Schnittstelle

Die Schnittstelle auf Daten eines Moduls sollte so klar und minimal wie möglich ausfallen. Der schlimmste Fall einer offenen Schnittstelle eines Moduls sind globale Daten. Sie führen zu einem totalen Verlust der Kontrolle und sollten nur in begründeten Ausnahmefällen verwendet werden.

Geht man von einer hohen Modulbindung eines Moduls aus, so sind die Prozeduren des Moduls stark miteinander verbunden. Je mehr dieser Prozeduren exportiert werden, desto größer ist die Wahrscheinlichkeit einer falschen Verwendung des Moduls.

Ein weiterer Faktor beim Export von Funktionen ist die Anzahl und Art der Parameter. Viele oder komplizierte Parameter erlauben viele Variationen und verkomplizieren die Verwendung eines Moduls. Dies führt zu einer schlechteren Testbarkeit des Moduls und zu einer höheren Fehleranfälligkeit bei der Modulverwendung.

Eine gute minimale Schnittstelle sollte also keine globalen Daten, wenige Funktionen und wenige einfache Parameter enthalten.

Testbarkeit

Der letzte Punkt der obigen Moduldefinition besagt, dass die Korrektheit des Moduls ohne Kenntnis seiner Einbettung in das Gesamtsystem nachprüfbar sein soll. Wird dieser Grundsatz eingehalten, so ist das eine gute Voraussetzung für eine gute Testbarkeit.

Der spezielle Modultest in einer vom Gesamtsystem abgekapselten Umgebung (eigener Testrahmen) ist sicher der beste Weg zur Durchführung aller nötigen Testfälle. Man kann die Testfälle direkt erzeugen und ist nicht auf die Richtigkeit des Gesamtsystems angewiesen. Eine solche Vorgehensweise wird vor allem durch eine Bottom Up Entwicklung gefördert, da zum Zeitpunkt der Erstellung des Moduls das Gesamtsystem noch gar nicht existiert.

Eine gute Testbarkeit ist auch von anderen, bereits diskutierten Faktoren abhängig. Die Forderung nach einer minimalen Schnittstelle minimiert auch die möglichen Testfälle. Eine hohe Modulbindung führt wahrscheinlich rascher zu einer höheren Testabdeckung innerhalb des Moduls.

Interferenzfreiheit

Von Interferenzfreiheit eines Moduls spricht man, wenn das Ausführen von Prozeduren des Moduls keine Nebenwirkungen auf andere Module hat. Solche Nebenwirkungen sind etwa das Modifizieren von globalen Daten oder das Ausführen modifizierender Funktionen in anderen Modulen. Interferenzfreiheit ist auch nicht gegeben wenn ein Modul mehrere Aufgaben erfüllt oder eine Aufgabe auf mehrere Module verteilt ist.

Man kann davon ausgehen, dass ein interferenzfreies Modul jederzeit durch ein anderes Modul mit der identischen Schnittstelle ausgetauscht werden kann. Die Interferenzfreiheit ist daher ein Kriterium für die Änderbarkeit und Erweiterberkeit eines Systems.

Importzahl, Verwendungszahl

sind zwei Maßzahlen aus denen sich Schlüsse über die Art oder Qualität der Modularisierung ableiten lassen.

Die Importzahl sagt aus, wie viele Module vom Modul verwendet werden. Ist sie sehr hoch, so deutet dies auf eine sehr hohe Modulkopplung hin. Interferenzen sind dann sehr wahrscheinlich. Ist sie niedrig, könnte das Modul eventuell zu groß sein. Es wurde vielleicht immer wieder erweitert.

Man sieht hier schon, dass man keine direkten Schlüsse ziehen kann. Gemessene Werte geben nur die Richtung an, nach der ein Modul überprüft werden sollte.

Die Verwendungszahl ist die Anzahl der Module die das Modul verwenden. Ist sie hoch, dann ist das Modul wahrscheinlich sehr allgemein und hat eine hohe Wiederverwertung. Es könnte sich aber auch um eine Sammlung nicht zusammenhängender Funktionen handeln. Bei einer hohen Verwendungszahl sollte auch eine starke Modulbindung herrschen.

Entwurfstechniken

Die Modularisierung eines Systems hängt besonders von den verwendeten Entwurfstechniken ab. Es gibt verschiedene Aspekte, nach denen man Entwurftechniken einteilen kann. Hier sind zwei Einteilungen mit den Auswirkungen auf die Modularisierung.

Einteilung nach der Richtung der Abstraktion:

Einteilung nach Kriterien nach denen abstrahiert wird:

Entwurfsmuster

Entwurfsmuster[Gamm96] stellen vorgefertigte Lösungen für wiederkehrende Entwurfsprobleme bereit. Will man mit Entwurfsmustern arbeiten, ist es wichtig den Grundschatz an Mustern zu kennen, beziehungsweise zu erlernen. So ist es möglich, während des Entwurfs Anwendungssituationen für Entwurfsmuster zu erkennen und diese anzuwenden. Man kann auch hier vom oft strapazierten Begriff "Wiederverwendung" gebrauch machen. Es handelt sich um Wiederverwendung von Problemlösungen.

Ein wichtiger Faktor bei Entwurfsmustern ist auch deren Name. Durch die Benennung wird eine Terminologie für die Kommunikation über Entwurfsprobleme (z.B. "Ist das ein Adapter oder eine Fassade ?") geschaffen.

Es gibt Erzeugungsmuster, Strukturmuster und Verhaltensmuster.

Wie lösen Muster Entwurfsprobleme ?

Literatur

[BlPo93] Günther Blaschek, Gustav Pomberger: Software-Engineering, Hanser, 1993
[McCo93] Steve McConnell: Code Complete, Microsoft Press, 1993
[Gamm96] Erich Gamma: Entwurfsmuster, Addison Wesley, 1996