Im Rahmen meines Studiums habe ich eine wissenschaftliche Ausarbeitung zum Thema "Modularisierung in der Programmierung" verfasst, die ich euch in diesem Blog-Artikel zur Verfügung stelle. Diese Ausarbeitung habe ich auch in einem Verlag veröffentlicht (https://doi.org/10.5281/zenodo.12681070), sodass diese in anderen wissenschaftlichen Ausarbeitungen genutzt werden kann.
Eine Liste weiterer wissenschaftlicher Ausarbeiten, sowie deren Nutzungsbedingungen, sind auf dieser Seite verlinkt.
Motivation
The most fundamental problem in software development is complexity. There is only one basic way of dealing with complexity: divide and conquer
– Bjarne Stroustrup
Zitiert wurde hier eine bekannte Aussage von Bjarne Stroustrup, der vor allem für seine Erweiterung von C um diverse Aspekte, unter anderem der Objektorientierung bekannt geworden ist. Zwei Punkte werden in dem Zitat angesprochen:
Zum einen wird das fundamentale Problem der Komplexität in der Softwareentwicklung genannt. Immer größer und komplexer werdende Software erschwert die fehlerfreie Entwicklung, Wartung und Erweiterung von Anwendungen. Neue Probleme treten zum anderen auch dann zu tage, wenn an immer größer werdenden Anwendungen auch immer mehr Entwickler beteiligt sind. Es kann schnell vorkommen, dass Änderungen eines Entwicklers tiefgreifende Auswirkungen auf die Arbeiten anderer Entwickler haben.
Für das Problem der immer größer werdenden Komplexität hat Bjarne Stroustrup auch eine Lösung genannt: Das „divide and conquer“-Verfahren (auf deutsch: „teile und herrsche“) – seiner Meinung nach die einzige einfache Lösung.
Mit divide and conquer meint Stroustrup das Zerlegen eines komplexen Problems in viele einfachere Probleme. Auch diese können solange aufgeteilt werden, bis die Probleme dann mit überschaubarem Aufwand implementiert werden können – dieses Vorgehen wird allgemein Modularisierung genannt.
Die Idee der Modularisierung ist keine Neue. Bereits Ende der 1970er Jahre kam mit Modula die erste modularisierte Programmiersprache auf, die als Vorbild für viele, aktuell verbreitete Programmiersprachen gilt.
Die moderne Softwareentwicklung ist ohne die Modularisierung unvorstellbar. Eine Reihe von Vorgehensweisen, wie zum Beispiel die Nutzung generalisierter Softwarebibliotheken (engl. "libraries"), setzen die Modularisierung voraus.
Diese Arbeit beschäftigt sich mit der Definition und der näheren Beschreibung der Modularisierung. Des weiteren werden die Vorteile, die die Verwendung einer korrekt angewendeten Modularisierung mit sich bringt erörtert. Wichtig ist hierbei auch die Definition der korrekten Anwendung dieser. Beschrieben wird des weiteren der Stellenwert der Modularisierung im Bereich der Componentware.
Definition Modularisierung
Das Prinzip der Modularisierung kann als eine Art Werkzeug für Wiederverwendbarkeit, für die Erleichterung von Wartung und für das Vereinfachen von Problemen angesehen werden. Anwendungen werden dabei in einzelne Module unterteilt.
Ein Modul ist eine für sich eigenständige und nach außen kontextunabhängige Menge von Objekten, Klassen und Funktionen. Entscheidend ist hierbei, dass nur semantisch zusammengehörende Elemente als Modul gruppiert werden.
Das Single Responsibility Principle schreibt dabei vor, dass ein Modul nur eine Verantwortung besitzen darf. Die Vorteile der Modularisierung können nicht ausgenutzt werden, wenn ein Modul mehrere unterschiedliche Verantwortlichkeiten übernimmt.
Die Kommunikation zwischen den einzelnen Modulen erfolgt über Schnittstellen. In diesen werden die nach außen hin öffentlichen Funktionen definiert. Die dort beschriebenen Funktionen müssen innerhalb des Moduls implementiert werden und können dann von außenstehenden Modulen verwendet werden.
Einige Eigenschaften modellbasierter Anwendungen hängen stark vom Prinzip der Schnittstellenkommunikation ab. Dazu gehört die Eigenschaft, dass die Implementierungen einzelner Module einfach ausgetauscht werden kann. Da ein Modul nur über die definierten Schnittstellen von anderen Modulen verwendet wird, kann dieses Modul einfach durch ein anderes Modul mit einer alternativen Implementierung ausgetauscht werden, solange dieses die selbe Schnittstelle implementiert.
Eine weitere wichtige Eigenschaft ist das Geheimhaltungsprinzip. Auch dieses wird erst durch die Kommunikation über Schnittstellen möglich. Bei diesem Geheimhaltungsprinzip werden nur die Informationen und Funktionen zum Lesen bzw. Schreiben freigegeben, die auch von außenstehenden Modulen genutzt werden sollen. So werden ungewollte Manipulationen, die zum Fehlverhalten führen können, vermieden. Es existieren verschiedene Stufen der Geheimhaltung. Zum einen besteht die Möglichkeit Informationen nur innerhalb eines Modulelements sichtbar zu machen, zum anderen können Sichtbarkeiten innerhalb eines ganzen Moduls bestimmt werden.
Damit es nicht zu sporadisch auftretenden und teils nur schwer durchschaubaren Fehlverhalten kommt, sollte sichergestellt werden, dass das Ausführen von Routinen eines Moduls keine Auswirkungen auf das Verhalten anderer Module hat. Diese Unabhängigkeit wird Interferenzfreiheit genannt.
Die Anzahl der Beziehungen der einzelnen Bestandteile innerhalb eines Moduls wird als Modulbindung oder auch als Kohäsion bezeichnet. Die Anzahl der Beziehungen eine Ebene höher, also unter den einzelnen Modulen, wird Modulkopplung genannt. Die Modulbindung sowie die Modulkopplung sind wichtige Indikatoren für die Hochwertigkeit und somit die Wirkung der Modularisierung. Wie genau hier das Ziel definiert ist, ist in Kapitel Ziele der Modularisierung näher erörtert.
Es existieren diverse Konzepte zur Umsetzung von Modularisierung. Eines der drei bekanntesten Konzepte ist das Datenmodul-Konzept, bei dem nur Daten zu Modulen verbunden werden. Dieses Vorgehen wird in modernen Programmiersprachen nicht mehr alleinstehend angewendet. Ein weiteres Konzept sieht das Zusammenfassen von Funktionalitäten vor. Das unter dem Namen Funktionsmodul bekannte Konzept bietet tiefgreifende Möglichkeiten und wird im Klassenmodul-Konzept nochmals um solche erweitert. In diesen besteht ein Modul aus Klassen (die nicht zwangsläufig öffentlich zugänglich sind) innerhalb derer die Geheimhaltung definiert wird.
Ziele der Modularisierung
Anhand der beiden Größen Modulkopplung und Modulbindung lässt sich die Wertigkeit der Modularisierung bestimmen. Allgemein wird eine geringe Modulkopplung und eine hohe Modulbindung angestrebt.
Eine geringe Modulkopplung hat den Vorteil, dass einzelne Module besser ausgetauscht oder verändert werden können. Umso geringer die Kopplung ausgeprägt ist, desto weniger müssen die importierenden Module (d.h. die Module, die das veränderte Modul benutzen) angepasst werden.
Bei der Verwendung vieler globaler Datenquellen oder verteilter Funktionen kommt es schnell zu einer hohen Modulkopplung.
Eine hohe Modulkopplung, also wenn es zu vielen Verbindungen innerhalb einer Menge an Modulen kommt, bringt ein neues Komplexitätsproblem mit sich – vor allem dann, wenn mehrere Module gegenseitig voneinander abhängig sind: sgn. zyklische Modulabhängigkeiten. Abhilfe liefert hier das Schichtenmodell, bei dem die Module zunächst in Schichten eingeteilt werden. Module einer Schicht haben nun ausschließlich auf die Module der selben und auf die Module aller untergeordneten Schichten Zugriff, nicht aber auf höhere Schichten. Vor allem die zyklischen Modulabhängigkeiten können sich so nun nur auf eine Schicht beschränken (siehe Abbildung oben).
Eine niedrige Modulbindung ist allgemein ein Zeichen für eine schlechte Gruppierung der Funktionen innerhalb eines Moduls. Die einzelnen Funktionen sollten dann in getrennte Module aufgeteilt werden.
Wird zu stark modularisiert spricht man von einer Fragmentierung, was mit einem Verlust an Ordnung und Sichtbarkeit gleichzusetzen ist. Sowohl qualitativ als auch quantitativ muss die Modulstruktur handlich, überschaubar und verständlich bleiben.
Das Gliedern von Funktionalitäten in Module erfüllt ihren Mehrwert allerdings nur, wenn die Gliederung in einem vernünftigen Rahmen erfolgt. Bei einer geringen Anzahl an Modulen ist der benötigte Aufwand für die Implementierung der Modulkopplungen relativ gering, während das Umsetzen der Modulbindung mit erheblichem Aufwand verbunden ist. Anders bei zu vielen Modulen – der Aufwand für die Implementierung der Modulkopplung steigt nun stark an, während der Aufwand für die Implementierung der Modulbindung stark abnimmt.
Vorteile der Modularisierung
Modularisierung ist ein wichtiges Konzept der modernen Softwareentwicklung und ist mittlerweile nicht mehr aus dieser wegzudenken. Je größer die Anwendungen werden, desto wichtiger wird der Einsatz der Modularisierung. Die Vorteile, die die Verwendung bietet werden im folgenden aufgezählt:
Immer größer werdende Anwendungen führen allgemein zu immer komplexeren Algorithmen die implementiert werden müssen. Der Einsatz der Modularisierung ermöglicht es, komplexe Algorithmen in kleinere Algorithmen zu unterteilen, sodass erhebliche Aufwandsreduzierungen erreicht werden können. Das Zerlegen von Problemen in immer kleinere Probleme beschleunigt sowohl die initiale Implementierung, als auch die Wartungsarbeiten und vermeidet zudem fehlerhafte Implementierungen. Bekannt ist dieses Vorgehen unter dem Namen divide and conquer.
Ein weiterer Vorteil der modularen Programmierung ist, dass unabhängige Teile eines Softwaresystems auch unabhängig voneinander entwickelt werden können. So wird die Implementierung deutlich überschaubarer, sodass die Wartbarkeit erheblich erleichtert wird.
Softwaresysteme werden mit der Zeit immer größer und umfangreicher, sodass bei der Umsetzung eine effektive Teamarbeit immer wichtiger wird, um Zeit und somit auch Kosten einzusparen. Modularisierung bietet Entwicklerteams die Möglichkeit, effektiver parallel an Softwareblöcken zu entwickeln, ohne sich gegenseitig zu behindern.
Einer der bedeutensten Vorteile ist die Möglichkeit, einzelne Funktionen einfach wiederverwenden zu können, wenn diese in ein eigenes Modul ausgelagert wurden. So kann doppelte Programmierung vermieden werden, was zu Zeit- und somit auch zu Kostenersparnissen führt. Auch im Fehlerfall müssen Ausbesserungen nur noch in einem Modul und nicht mehr an mehreren Stellen vorgenommen werden.
Eine Fortführung der Idee der Wiederverwendung ist das Aufbauen universell nutzbarer Bibliotheken (engl. libraries), die anwendungsübergreifend zum Einsatz kommen. Beispiele für solche universell einsetzbaren Bibliotheken sind Listen-Strukturen oder HTTP-Clients, da solche Anwendungen in einer Vielzahl von Softwarelösungen zum Einsatz kommen.
Das Modularisieren ermöglicht es den Softwareentwicklern, deutlich einfacher tiefgreifende Tests zu entwickeln. Grund hierfür ist, dass für ein Modul (durch seine klare Funktion und durch seine einfache Schnittstelle) einfacher Testszenarien definiert werden können, die dann getrennt von den anderen Modulen ausgeführt werden können.
Wechselwirkung der Modularisierung mit anderen Prinzipien
Das Prinzip der Modularisierung ist nur eins von vielen Prinzipien, die in der modernen Softwareentwicklung Verbreitung gefunden haben. Die Komplexität der einzelnen Prinzipien zeigt sich teilweise erst durch ihre Wechselwirkungen und Abhängigkeiten mit anderen Prinzipien. Das Prinzip der Modularisierung steht in direkter Wechselwirkung mit sechs anderen Prinzipien und spielt somit eine zentrale Rolle.
Eine direkte Abhängigkeit von der Modularisierung ist das Geheimhaltungsprinzip. Dieses wurde bisher als eine Eigenschaft der Modularisierung betrachtet, kann aber auch als eigenständiges Prinzip gewertet werden. Diese Blickweise betrachtet das Geheimhaltungsprinzip als eine Verschärfung der Modularisierung. Als eigenständiges Prinzip kann ebenfalls die Bindung und Kopplung gewertet werden.
Wichtig – besonders für große Anwendungen – ist das Prinzip der Verbalisierung. Dieses besitzt Wechselwirkungen mit dem Modularisierungsprinzip. Das Prinzip der Verbalisierung bezeichnet das Ausdrücken der Idee hinter einer Programmstruktur in Worte, sodass diese Idee gut dokumentiert werden kann. Die Idee der Verbalisierung ist für die Modularisierung von erheblicher Bedeutung, da die gewählte Modul-Struktur für eine gute Wartbarkeit dokumentiert werden muss.
Das Prinzip der Lokalität sieht das Zusammenfassen weniger aber dafür wichtiger Eigenschaften vor, um ein Problem konkret beschreiben zu können. Durch diese Reduzierung werden nicht notwendige Eigenschaften ausgeblendet, sodass diese "nicht erschlagend" wirken.
Eine Wechselwirkung besteht auch zwischen der Modularisierung und dem Prinzip der Strukturierung. Ähnlich wie auch die Lokalität beschreibt die Strukturierung eine Reduzierung der Darstellung eines Systems auf einige wenige Merkmale. Der Grund für die Reduzierung bei der Strukturierung ist jedoch die Darstellung eines Systems als Ganzes, um die wesentlichen Merkmale eines Systems herauszustellen. Häufig werden in den Schnittstellen der einzelnen Module nur die wichtigsten, im Rahmen der Strukturierung herausgearbeiteten Eigenschaften bereitgestellt.
Eine Wechselwirkung besteht außerdem mit dem Hierarchisierungsprinzip. Dieses ist als eine Unterordnung der Strukturierung zu betrachten und beschreibt die Sortierung einzelner Funktionen (bzw. im Rahmen der Modularisierung einzelner Module) nach deren Rangordnung in einzelne Ebenen. Die Einordnung von Modulen in Ebenen wurde bereits in der obigen Abbildung dargestellt.
Komponente, Modul und Beziehung zu Componentware
In diesem Kapitel sollen die Begriffe Modul, Komponente und Componentware definiert werden. Auf eine eindeutige Definition kann hier jedoch nicht zurückgegriffen werden, daher werden zwei verschiedene Definitionen aus zwei Quellen vorgestellt:
Eine verbreitete Definition beschreibt, dass Componentware sich mit der Entwicklung von Software beschäftigt, deren wesentlichen Bausteine Komponenten darstellen. Dabei besteht zwischen den Komponenten nur eine lose Kopplung.
Komponenten können als ein Teil bzw. ein Zerlegeprodukt einer Software betrachtet werden, die eine zentrale Aufgabe bzw. eine Funktion umsetzen. Den Komponenten wird dabei nur diese eine Funktion zugeteilt. Komponenten bestehen bei dieser Definition aus Objekten und – allgemeiner beschrieben – einer Menge an Prozessen.
Aus dieser Perspektive betrachtet ist eine Komponente eine spezifische Ausprägung eines Moduls. Ein Modul ist dabei als ein logischer Teil eines Softwaresystems zu sehen, während eine Komponente eine explizite Implementierung darstellt. Ein Modul kann hierbei aus mehreren Komponenten bestehen. Exemplarisch dargestellt ist eine solche Struktur in der folgenden Abbildung.
Alternativ kann den Begriffen Modul und Komponente die selbe semantische Bedeutung zugeschrieben werden. Diese Sichtweise sieht keine Differenzierung zwischen einem Logik- und einem Implementierungsbestandteil vor.
Fazit
In der Softwareentwicklung führen immer größer werdende Anwendungen zu einer immer steigenden Komplexität. Die steigende Komplexität ist ein fundamentales Problem für das die Modularisierung eine mögliche Lösung darstellt.
Die Idee "divide and conquer" ist das Aufteilen von großen, komplexen und nur schwer implementierbaren Problemen in immer kleiner werdende Probleme. Das Aufteilen wird rekursiv solange durchgeführt, bis die einzelnen Probleme einfach zu implementieren sind.
Das Prinzip der Modularisierung sieht die Aufteilung einzelner Probleme bzw. einzelner Funktionen in einzelne Module vor. Ein Modul besteht dabei aus einzelnen Klassen und kleineren Funktionen, die untereinander stark miteinander verbunden sind. Während die Bindung innerhalb eines Moduls relativ hoch ist, sollte die Kopplung der Module untereinander gering implementiert werden. Die Kommunikation der Module untereinander wird durch Schnittstellen implementiert.
Modularisierung ist eine elementare Basis für diverse weitere Prinzipien wie zum Beispiel die Strukturierung oder die Hierarchisierung.
Die Verwendung der Modularisierung bietet diverse Vorteile. Werden einzelne Funktionen in getrennten Modulen implementiert, können diese Funktionen zum Beispiel einfach wiederverwendet werden. So wird doppelte Programmierung vermieden, sodass Zeit und somit auch Geld gespart wird.
Außerdem wird durch das Trennen semantisch unabhängiger Funktionen in einzelne Module das Entwickeln durch mehreren Entwicklern stark vereinfacht.
Abschließend kann zusammengefasst werden, dass Modularisierung ein in der modernen Softwareentwicklung unverzichtbares Prinzip ist, das viele Vorteile bietet.
- Bildquelle erste Abbildung in Ziele der Modularisierung
- Ralf Guido Herrtwich und Günter Hommel. „Modularität“. In: Nebenläufige Programme. Berlin, Heidelberg: Springer Berlin Heidelberg, 1994, S. 29–46. isbn: 978-3-642-57931-8. doi: 10.1007/ 978-3-642-57931-8_3. url: https://doi.org/10.1007/978-3-642-57931-8_3
- Bildquelle erste Abbildung in Wechselwirkung der Modularisierung mit anderen Prinzipien
- Helmut Balzert. „Was ist Softwaretechnik?“ In: Lehrbuch der Softwaretechnik: Basiskonzepte und Requirements Engineering. Heidelberg: Spektrum Akademischer Verlag, 2009, S. 17–22. isbn: 978-3-8274-2247-7. doi: 10.1007/978-3-8274-2247-7_3. url: https://doi.org/10.1007/978-3-8274-2247-7_3