Читать книгу Prinzipien des Softwaredesigns - John Ousterhout - Страница 21

Modulares Design

Оглавление

Beim modularen Design wird ein Softwaresystem in eine Sammlung von Modulen unterteilt, die verhältnismäßig unabhängig voneinander sind. Module können viele Formen annehmen, zum Beispiel Klassen, Subsysteme oder Services. In einer idealen Welt wäre jedes Modul vollständig unabhängig von den anderen: Beim Entwickeln könnte man in jedem der Module arbeiten, ohne irgendetwas über eines der anderen Module wissen zu müssen. In dieser Welt wäre die Komplexität eines Systems die Komplexität seines schlimmsten Moduls.

Leider ist dieses Ideal nicht erreichbar. Module müssen zusammenarbeiten, indem sie Funktionen oder Methoden anderer Module aufrufen. Daher müssen Module etwas über andere wissen. Es wird Abhängigkeiten zwischen den Modulen geben: Ändert sich ein Modul, müssen sich eventuell auch andere Module ändern, damit wieder alles passt. So sorgen beispielsweise die Argumente einer Methode für eine Abhängigkeit zwischen der Methode und jeglichem Code, der diese Methode aufruft. Ändern sich die erforderlichen Argumente, müssen alle Aufrufe der Methode angepasst werden, damit diese der neuen Signatur entsprechen. Abhängigkeiten können viele andere Formen annehmen, und sie können ziemlich subtil sein. Als Beispiel sei eine Methode erwähnt, die nur dann korrekt funktioniert, wenn eine andere Methode zuvor aufgerufen wurde. Das Ziel des modularen Designs ist es, die Abhängigkeiten zwischen Modulen zu minimieren.

Um Abhängigkeiten erkennen und managen zu können, stellen wir uns vor, dass jedes Modul aus zwei Teilen besteht: einer Schnittstelle (Interface) und einer Implementierung. Die Schnittstelle setzt sich zusammen aus allem, was man beim Entwickeln in einem anderen Modul wissen muss, um das gegebene Modul zu verwenden. Typischerweise beschreibt die Schnittstelle, was das Modul tut, aber nicht, wie es das tut. Die Implementierung dagegen besteht aus dem Code, der die durch die Schnittstelle gemachten Versprechungen umsetzt. Arbeitet man an einem bestimmten Modul, muss man die Schnittstelle und die Implementierung dieses Moduls verstehen, dazu aber auch die Schnittstellen aller anderen Module, die vom gegebenen Modul aufgerufen werden. Beim Entwickeln sollte man die Implementierungen von anderen Modulen mit Ausnahme des aktuell bearbeiteten nicht kennen müssen.

Stellen Sie sich ein Modul vor, das balancierte Bäume implementiert. Es enthält vermutlich ausgeklügelten Code, um sicherzustellen, dass der Baum balanciert bleibt. Aber diese Komplexität ist beim Einsatz des Moduls nicht sichtbar. Beim Anwenden sieht man nur eine recht einfache Schnittstelle, um Operationen zum Einfügen, Entfernen und Auslesen von Knoten aufrufen zu können. Um eine Einfügeoperation aufzurufen, müssen lediglich Schlüssel und Wert für den neuen Knoten geliefert werden – die Mechanismen zum Durchlaufen des Baums und zum Aufteilen der Knoten sind in der Schnittstelle nicht sichtbar.

Im Rahmen dieses Buchs verstehen wir ein Modul als eine Codeeinheit, die eine Schnittstelle und eine Implementierung besitzt. Jede Klasse in einer objektorientierten Programmiersprache ist ein Modul. Methoden in einer Klasse oder Funktionen in einer nicht objektorientierten Sprache können auch als Module angesehen werden – jede hat eine Schnittstelle und eine Implementierung, und auch auf sie können modulare Designtechniken angewendet werden. Subsysteme und Services auf höherer Ebene sind ebenfalls Module – ihre Schnittstellen mögen allerdings anders aussehen, wie zum Beispiel Kernelaufrufe oder HTTP-Requests. Ein Großteil der Diskussion von modularem Design wird sich in diesem Buch auf das Designen von Klassen konzentrieren, aber die Techniken und Konzepte lassen sich auch auf andere Arten von Modulen anwenden.

Die besten Module sind diejenigen, deren Schnittstellen viel einfacher als ihre Implementierungen sind. Solche Module haben zwei Vorteile. Zum einen minimiert eine einfache Schnittstelle die Komplexität, die ein Modul für den Rest des Systems freisetzt, und zum anderen sorgt eine Veränderung eines Moduls, die dessen Schnittstelle nicht beeinflusst, dafür, dass kein anderes Modul davon beeinflusst wird. Ist die Schnittstelle eines Moduls viel einfacher als dessen Implementierung, wird es viele Aspekte des Moduls geben, die geändert werden können, ohne dass andere Module beeinflusst werden.

Prinzipien des Softwaredesigns

Подняться наверх