Loading...

BOTTOM-UP-PROGRAMMIERUNG

Original

Januar 1993

(Dieser Aufsatz stammt aus der Einleitung zu On Lisp .)

Es ist ein seit langem bestehendes Prinzip des Programmierstils, dass die funktionalen Elemente eines Programms nicht zu groß sein sollten. Wenn eine Programmkomponente über das Stadium hinauswächst, in dem sie leicht verständlich ist, wird sie zu einer Masse an Komplexität, die Fehler so leicht verbirgt, wie eine Großstadt Flüchtlinge verbirgt. Solche Software wird schwer zu lesen, schwer zu testen und schwer zu debuggen sein.

Nach diesem Prinzip muss ein großes Programm in Teile zerlegt werden, und je größer das Programm, desto mehr Teile müssen es zerlegt werden. Wie zerlegt man ein Programm? Der traditionelle Ansatz heißt Top-down-Design: Man sagt: „Der Zweck des Programms besteht darin, diese sieben Dinge zu tun, also zerlege ich es in sieben große Unterprogramme. Das erste Unterprogramm muss diese vier Dinge tun, also hat es wiederum vier eigene Unterprogramme“, und so weiter. Dieser Prozess wird fortgesetzt, bis das gesamte Programm den richtigen Grad an Granularität erreicht hat – jeder Teil ist groß genug, um etwas Wesentliches zu tun, aber klein genug, um als einzelne Einheit verstanden zu werden.

Erfahrene Lisp-Programmierer teilen ihre Programme anders auf. Neben dem Top-down-Design folgen sie einem Prinzip, das man als Bottom-up-Design bezeichnen könnte – die Sprache so zu verändern, dass sie zum Problem passt. In Lisp schreiben Sie Ihr Programm nicht nur in Richtung der Sprache, sondern Sie bauen die Sprache auch in Richtung Ihres Programms auf. Während Sie ein Programm schreiben, denken Sie vielleicht: „Ich wünschte, Lisp hätte diesen oder jenen Operator.“ Also schreiben Sie ihn. Später stellen Sie fest, dass die Verwendung des neuen Operators das Design eines anderen Teils des Programms vereinfachen würde, und so weiter. Sprache und Programm entwickeln sich gemeinsam. Wie die Grenze zwischen zwei verfeindeten Staaten wird die Grenze zwischen Sprache und Programm immer wieder gezogen, bis sie schließlich entlang der Berge und Flüsse, der natürlichen Grenzen Ihres Problems, endet. Am Ende wird Ihr Programm so aussehen, als wäre die Sprache dafür entwickelt worden. Und wenn Sprache und Programm gut zueinander passen, erhalten Sie einen Code, der klar, klein und effizient ist.

Es ist wichtig zu betonen, dass Bottom-up-Design nicht bedeutet, einfach dasselbe Programm in einer anderen Reihenfolge zu schreiben. Wenn Sie Bottom-up arbeiten, erhalten Sie normalerweise ein anderes Programm. Statt eines einzelnen, monolithischen Programms erhalten Sie eine größere Sprache mit abstrakteren Operatoren und ein kleineres Programm, das darin geschrieben ist. Statt eines Sturzes erhalten Sie einen Bogen.

Wenn Sie in einem typischen Code die Teile abstrahieren, die nur der Buchhaltung dienen, ist das, was übrig bleibt, viel kürzer. Je höher Sie die Sprache aufbauen, desto kürzer ist die Distanz, die Sie von oben nach unten zurücklegen müssen. Dies bringt mehrere Vorteile mit sich:

Indem die Sprache mehr Arbeit übernimmt, führt Bottom-up-Design zu kleineren und agileren Programmen. Ein kürzeres Programm muss nicht in so viele Komponenten aufgeteilt werden, und weniger Komponenten bedeuten Programme, die leichter zu lesen oder zu ändern sind. Weniger Komponenten bedeuten auch weniger Verbindungen zwischen Komponenten und damit weniger Fehlermöglichkeiten. Während Industriedesigner versuchen, die Anzahl der beweglichen Teile in einer Maschine zu reduzieren, verwenden erfahrene Lisp-Programmierer Bottom-up-Design, um die Größe und Komplexität ihrer Programme zu reduzieren.

Bottom-up-Design fördert die Wiederverwendung von Code. Wenn Sie zwei oder mehr Programme schreiben, sind viele der Dienstprogramme, die Sie für das erste Programm geschrieben haben, auch für die folgenden Programme nützlich. Wenn Sie erst einmal ein großes Substrat an Dienstprogrammen erworben haben, kann das Schreiben eines neuen Programms nur einen Bruchteil des Aufwands erfordern, den Sie benötigen würden, wenn Sie mit reinem Lisp beginnen müssten.

Durch das Bottom-Up-Design sind Programme leichter lesbar.

Ein Beispiel für diesen Abstraktionstyp verlangt vom Leser, einen Allzweckoperator zu verstehen. Ein Beispiel für eine funktionale Abstraktion verlangt vom Leser, eine Spezialsubroutine zu verstehen. [1]

Da Sie dadurch immer nach Mustern in Ihrem Code Ausschau halten, hilft Ihnen das Bottom-up-Arbeiten, Ihre Ideen über das Design Ihres Programms zu klären. Wenn zwei weit voneinander entfernte Komponenten eines Programms eine ähnliche Form haben, werden Sie dazu gebracht, die Ähnlichkeit zu bemerken und das Programm möglicherweise einfacher neu zu gestalten.

Bottom-up-Design ist bis zu einem gewissen Grad auch in anderen Sprachen als Lisp möglich. Wann immer Sie Bibliotheksfunktionen sehen, findet Bottom-up-Design statt. Lisp bietet Ihnen in diesem Bereich jedoch viel umfassendere Möglichkeiten, und die Erweiterung der Sprache spielt im Lisp-Stil eine proportional größere Rolle – so sehr, dass Lisp nicht nur eine andere Sprache, sondern eine völlig andere Art des Programmierens ist.

Es stimmt, dass sich dieser Entwicklungsstil besser für Programme eignet, die von kleinen Gruppen geschrieben werden können. Gleichzeitig erweitert er jedoch die Grenzen dessen, was von kleinen Gruppen geleistet werden kann. In The Mythical Man-Month stellte Frederick Brooks die These auf, dass die Produktivität einer Programmierergruppe nicht linear mit ihrer Größe wächst. Mit zunehmender Gruppengröße sinkt die Produktivität der einzelnen Programmierer. Die Erfahrungen mit der Lisp-Programmierung legen eine positivere Formulierung dieses Gesetzes nahe: Mit abnehmender Gruppengröße steigt die Produktivität der einzelnen Programmierer. Eine kleine Gruppe gewinnt relativ gesehen, einfach weil sie kleiner ist. Wenn eine kleine Gruppe außerdem die von Lisp ermöglichten Techniken nutzt, kann sie direkt gewinnen .

Neu: Kostenloser Download von On Lisp .

[1] "Aber niemand kann das Programm lesen, ohne alle Ihre neuen Dienstprogramme zu verstehen." Um zu sehen, warum solche Aussagen normalerweise falsch sind, siehe Abschnitt 4.8.