Drei Thesen zum Software-Entwurf:

Strukturierte Programmierung - und kein Ende

05.06.1981

Die Diskussion um die Strukturierte Programmierung geht oft genug am Thema vorbei. Äußerlichkeiten, Randprobleme erhalten in der Diskussion ein Übergewicht. Die zentralen Fragen werden verschleiert.

Vor nunmehr mehr als zehn Jahren konnten wir nicht verstehen, was Dijkstra uns mit seinem Verbot des Goto sagen wollte. Eine heftige Diskussion entbrannte: Programmierung ohne Sprungbefehl - das geht noch nicht! Die Flut ist abgeebbt; man hat sich in der Praxis auf die heute gängige Sprachregelung geeinigt: So wenige Gotos wie möglich.

In letzter Zeit ist in der COMPUTERWOCHE eine Diskussion entstanden, in der eine Reihe von Autoren versucht haben, neue Ideen zur Strukturierten Programmierung zu formulieren. Sie hat sich vor allem an der Darstellungstechnik entzündet - sollte dem Strukturdiagramm oder dem Pseudocode oder dem Nassi-Shneidermann-Diagramm in dieser oder jener Variante der Vorzug gegeben werden? Das Ergebnis der heutigen Diskussion ist ernüchternd:

Wir sitzen immer noch im falschen Zug; das Schlimme ist - wir merken es nicht einmal!

Wo liegt der Fehler? Warum macht es in der Praxis so viele Schwierigkeiten, die nun so sattsam bekannten drei Elemente des Struktursatzes - man wagt sie kaum mehr zu nennen: Sequenz, Selektion, Iteration- anzuwenden? Woher stammt die Notwendigkeit, doch manchmal noch einen Sprungbefehl zu brauchen; oder eine noch nicht vorhandene Konstruktion im Struktogramm erfinden zu müssen?

Ganz offensichtlich wissen wir immer noch nicht genau, was wir strukturieren müssen - das Resultat: Wir denken wie bisher in unseren Programm-Abläufen (ob wir sie nun zeichnen oder nicht) und versuchen

dabei, die von den Gurus der Strukturierten Programmierung zugelassenen Ablaufkonstrukte anzuwenden.

Heraus kommt ablauforientierter Code, der bestenfalls die Formalitäten erfüllt. Wir "strukturieren" also den Programmablauf. Was aber sollen wir wirklich strukturieren?

Wir haben Programme zu schreiben, die bestimmte Aufgaben zu erfüllen haben: Informationen in Listen oder Bildschirmen aufzubereiten, gewünschte Ergebnisse zu berechnen, Daten zu verwalten. Was geschieht nun, wenn wir unseren Programmentwurf ablauforientiert ausführen? Körnen wir uns auf das Wesentliche überhaupt konzentrieren - oder passiert nicht folgendes: Der Programmablauf stellt die Reihenfolge in den Vordergrund, in der die dem Programm zugewiesenen Aufgaben stattzufinden haben; die Aufgaben selbst gehen im Gestrüpp der Kontrollpfade unter.

Ich möchte daher drei Thesen aufstellen, die (obwohl sie keineswegs neu sind) von vielen Programmierern bei ihren Versuchen in Strukturierter Programmierung nicht genügend beachtet werden - und die dadurch Schwierigkeiten beim Verständnis und in der Anwendung haben.

1. These: Das Programm muß statisch entworfen werden.

Im Vordergrund des Programmentwurfs darf nicht der Ablauf stehen sondern die Aufgaben, die das Programm zu erfüllen hat. Heute fragt sich der Programmierer bei seiner Arbeit:

þWie soll das Programm laufen?

þWas kommt als nächstes dran?

Er müßte sich eigentlich statt dessen fragen:

þWelche Aufgaben hat das Programm?

þUnter welchen Bedingungen werden diese Aufgaben ausgeführt?

(Daß unsere heutigen Computer ablauforientiert funktionieren, sollte uns dabei überhaupt nicht stören - die Computer haben zu tun, was wir wollen und nicht umgekehrt!)

2. These: Eine Aufgabe wird durch die Daten bestimmt, die zu verarbeiten beziehungsweise zu erzielen sind.

Wir sollten uns von dem großen Methodenstreit (hie funktionsorientiert - hie datenorientiert) nicht verwirren lassen. Jede Aufgabe innerhalb eines Programmes (und wir können hierfür auch "Funktion" sagen) besteht darin, Eingabedaten über bestimmte Regeln in Ausgabedaten zu transformieren - jede Funktion ist eine solche Transformationsregel. Wichtig für uns ist, daß wir die Aufgaben in unseren Programmen sehr weitgehend zerlegen können: Bis hin zum einfachsten Verarbeitungsbefehl, dem Übertragungsbefehl - immer bleibt dieser Zusammenhang zwischen Ein-/Ausgabedaten und der zugehörigen Transformationsregel erhalten!

Dabei ist es nun unerheblich, ob die Ausgaben einer Aufgabe ein für den Anwender des gesamten Programmes bestimmten Endergebnis sind oder nur aus Zwischenergebnissen bestehen, die über weitere Regeln hinweg zu bearbeiten sind.

3. These: Der Ablauf muß aus den Aufgaben eines Programmes abgeleitet werden (und nicht umgekehrt!).

Die Reihenfolge der Aufgaben und damit der Ablauf, der Prozeß ergibt sich aus:

þden Zusammenhängen der Datentransformationen (jede Information kann nur dann einer Aufgabe zur Verfügung stehen, wenn sie entweder von außen stammt oder zuvor an anderer Stelle produziert wurde)

þaus den Bedingungen, unter denen eine Aufgabe ausgeführt werden soll.

Wenn wir genau wissen, was wir tun sollen, dann ist der Ablauf unseres Programmes "zwangsläufig" und spiegelt die innere Logik unserer Aufgaben wider; unsere Hoffnung ist, daß das Ergebnis unserer Arbeit nicht mehr so änderungsanfällig ist wie zuvor. Damit ist jedoch der Ablauf nicht mehr das grundlegende Entwurfsprinzip, sondern eher ein beiläufiges Resultat der Entwurfsarbeit.

Unser Vorgehen gemäß obiger Thesen können wir in drei konkurrierenden Darstellungsformen dokumentieren:

þStrukturdiagramm

þStruktogramm oder Nassi-Shneidermann-Diagramm

þPseudocode

Alle Darstellungsformen können die Ergebnisse unserer Methode der Strukturierten Programmierung (oder sollten wir besser "strukturierende Programmierung" sagen) darstellen. Genau darin liegt aber auch ihr grundsätzlicher Mangel: Sie erzwingen nicht die geforderte aufgabenorientierte Denkweise. Eine "falsche" Denkweise fällt nur dann ins Auge, wenn bei Änderungen plötzlich da, gesamte Gebilde wie ein Kartenhaus zusammenbricht - für die meisten dann (fataler - wie fälschlicherweise) ein Punkt gegen die Strukturierte Programmierung.

Die Folgerungen für die Praxis sind eindeutig: Für welche Darstellungsform wir uns entscheiden, hängt beinahe vom persönlichen Geschmack ab; die Vor- und Nachteile der einzelnen Formen sind nicht so schwerwiegend. Immerhin hat sich folgende Vorgehensweise als sehr brauchbar erwiesen: In der Phase des Programmentwurfs wird das Strukturdiagramm benutzt, gekoppelt mit dem EVA-Diagramm für die Beschreibung der einzelnen Aufgaben; diese Kombination scheint einen für diesen Zweck guten Detaillierungsgrad zu erlauben. Für den Feinbau des Programmes auf Bausteinebene (beschrieben jeweils durch ein EVA-Diagramm beim Programmentwurf) hat sich der Pseudocode wegen seiner Nähe zum späteren Code und seiner hervorragenden maschinellen Dokumentationseigenschaften als nützlich erwiesen.

Was immer wir auch als Darstellungstechnik auswählen, es kommt nicht auf graphische Varianten oder Spielereien an. Entscheidend ist, daß wir uns an das blockorientierte, die Aufgaben strukturierende Konzept gewöhnen und das ablauforientierte Denken grundsätzlich aufgeben - auch wenn's uns am Anfang schwerfällt!

*Peter Raysz ist Bereichsleiter für Beratung bei der Integrata GmbH, Tübingen. Sowohl in der praktischen Arbeit als auch in Seminaren beschäftigt er sich mit Fragen der Strukturierten Programmierung.