Passive Werkzeuge gehören technologisch zum alten Eisen

Intelligente Generatoren sollen SW-Designs erzeugen

26.10.1990

Bei herkömmlichen CASE-Konzeptionen liegt die aktive Arbeit immer noch bei den Entwicklern der Software. Es zeichnet sich jedoch ab, daß die weitere Entwicklung im CASE-Bereich auch in die Richtung aktiver, intelligenter Tools geht, die den Entwickler von operativen Tätigkeiten entlasten. Manfred Thiel beschreibt ein Konzept an einem konkreten Beispiel.

Worin besteht eigentlich der Vorteil des Einsatzes von CASE-Methoden und -Werkzeugen - dies ist eine der meist gestellten Frage über Computer Aided Software Engineering. Die Antworten lassen sich den Argumentationsbereichen Qualitäts- und Produktivitätssteigerung zuordnen.

Dabei steht das Argument "Qualität" nicht zufälligerweise an erster Stelle. Ob Qualität und Produktivität steigen oder fallen, hängt darüber hinaus von den Fähigkeiten, den Kenntnissen und den Erfahrungen der Mitarbeiter ab.

Derzeit verbreitete CASE-Konzeptionen zeichnen sich meist dadurch aus, daß sie (gehen wir davon aus, sie decken den gesamten Lebenszyklus ab) für einzelne Phasen Methoden und Werkzeuge zur Verfügung stellen und die Daten der (meisten) Phasen in einem Data Dictionary ablegen. Zu den bereitgestellten Werkzeugen gehören einerseits Reportgeneratoren und andererseits Editoren und Analysatoren, wobei letztere durchweg nur genau eine Phase im Lebenszyklus abdecken.

Software-Entwicklung mit intelligenten Werkzeugen

Beschäftigen wir uns ein wenig näher mit den Editoren: Sie sind passive Werkzeuge; denn sie treffen aus sich heraus keine intelligenten Entscheidungen über ihren Anwendungsbereich. Als Bediener macht der Software-Entwickler selbst die eigentliche Arbeit. Aktiv und damit notwendigerweise intelligent wären die Editoren, wenn sie zum Beispiel Methodenwissen hätten und dem Bediener Bereitstellen würden.

Hier soll nun die These vertreten werden, daß die weitere Entwicklung im CASE-Bereich auch in die Richtung aktiver, intelligenter Tools geht, die den Entwickler von operativen Tätigkeiten entlasten. Hierunter fällt auch das automatische Herstellen von logisch ableitbaren Zuständen. Damit stellt sich das Thema "Generatoren" in das Zentrum der nachfolgenden Überlegungen. Gehen wir also davon aus, daß das folgende Diagramm ein Modell ,eines Teils' einer möglichen zukünftigen Welt für Software-Entwickler sei Abbildung 1 demonstriert das unterschiedliche Verständnis von passiven und aktiven Systemen.

Zur besseren Einordnung des Ansatzes soll kurz die Vorgehensweise der Softwareentwicklung am Beispiel der Ward- und Mellor-Methode gezeigt werden. Innerhalb der Entwurfsphase unterscheidet man verschiedene Tätigkeiten, die sinnvollerweise aufeinander folgen müssen, sequentiell oder zyklisch. Nach einer Vorbereitungsphase, in der eine Aufgabenklärung und eventuell Voruntersuchungen durchgeführt werden, kann das essentielle, das heißt das logische Modell entwickelt werden, auf dem dann das Implementierungsmodell aufsetzt. Die Entwurfsphase wird abgeschlossen durch das Softwaredesign, wobei die Beschreibung der Daten und Prozesse aus den Spezifikationsmodellen in Softwarestrukturen und -daten umgesetzt wird.

In der professionellen Softwareentwicklung haben sich Methoden durchgesetzt, die im Umfeld der Structured Analysis (SA) entstanden sind. Andere Methoden, etwa die der algebraischen Spezifikation, werden zur Zeit noch eher im universitäten Umfeld eingesetzt oder, wie das objektorientierte Programmieren, erfolgsversprechend in den industriellen Markt eindringen.

In der SA stehen dem Analytiker mit Datenflußdiagrammen (Transformationsgraphen) Modellierungstechniken zur Verfügung, die Datenprozesse, Datenspeicher und Datenflüsse bereitstellen. Will er in Echtzeitanwendungen zeitliche Abhängigkeiten modellieren, stehen ihm aber lediglich die Primitive Process Specifications zur Verfügung, in denen er das Timing verbal - in einer natürlichen Sprache oder in Pseudocode - beschreiben kann.

Unglücklicherweise sind diese Beschreibungen aber nur lokal, das heißt für den gerade beschriebenen Prozeß gültig. Eine systemumfassende, bezogen auf den Graphen globale Synchronisation der Prozesse ist damit nicht möglich.

Dieses Problem wurde von Ward und Mellor dadurch gelöst, daß sie neben den Datenprozessen auch Kontrollprozesse einführten. Die Aufgabe der Kontrollprozesse ist es, andere Prozesse zu aktivieren oder zu deaktivieren. Kontrollprozesse werden durch Zustandsübergangsdiagramme verfeinert, die Technik, deren Grundlagen in der Theorie der formalen Sprachen liegen.

Während die Analyse (beziehungsweise Spezifikation) des Systems eine intellektuelle Arbeit im Sinne von kreativer Tätigkeit verlangt, ist das Softwaredesign eher eine Technik, das Implementierungsmodell der Spezifikation in einen Softwareentwurf umzusetzen. Sicherlich ist hierzu viel Know-how notwendig, das insbesondere über die Effizienz des Programmes entscheidet. Aber die eigentlich kreative Phase der Software-Entwicklung ist vorüber.

Gelingt es, dieses Know-how zu formalisieren (Stichwort "Wissenstransfer"), müßte eine automatische Erstellung des Softwaredesigns und dann auch eine automatische Codegenerierung möglich sein. An eine Codegenerierung (und zwar prinzipiell unabhängig davon, ob sie intellektuell oder maschinell durchgeführt wird) werden folgende Anforderungen gestellt:

- sie soll von einer Sprache (der Spezifikation) in eine Implementierungssprache (Programmiersprache übersetzen.

- die Abbildung (Übersetzung) muß bedeutungserhaltend sein.

- während eine Spezifikation klar sein soll, ist das Hauptkriterium für ein Programm die Effizienz. Folglich muß die Abbildung aus einer klaren Spezifikation ein effizientes Programm erstellen und dabei möglichst die Klarheit der Spezifikation auch in das Programm hinüberretten.

Voraussetzung für eine derartige Abbildung ist die semantische Eindeutigkeit der sprachlichen oder grafischen Konstrukte der Spezifikation und der generierten Programmiersprache.

Bei letzterer kann man davon ausgehen, daß dies erfüllt ist. Daher gehen wir davon aus, daß das Ergebnis des ausgeführten Programmes sozusagen eine Inkarnation der Bedeutung des Programmes (einschließlich seiner Eingabedaten) ist und somit intellektuell direkt mit der Spezifikation verglichen werden kann.

Bezüglich der Eindeutigkeit der Semantik der Konstrukte der Spezifikationssprache ist aber Vorsicht angeraten. Bei algebraischen Spezifikationen steht sie außer Zweifel, doch was ist zum Beispiel mit den in SA und bei Ward und Mellor üblichen grafischen Objekten und Texten? Nur wenn auch hier Eindeutigkeit hergestellt werden kann, ist der Einsatz einer automatischen Codegenerierung sinnvoll. Mit anderen Worten, den Regeln der Codegenerierung und dem Gebrauch der Spezifikationsprache durch den Systemanalytiker muß ein Konsens bezüglich der Bedeutung der Sprache zugrundeliegen.

Zwar wird beim Umgang mit dem Softwarelebenszyklus meistens mit dem Phasenmodell operiert, aber auch wenn dieses Modell grundsätzlich gute Dienste leistet, befriedigt es doch nicht alle Ansprüche. Nicht ohne Grund haben sich verschiedene Ausprägungen gebildet, nicht ohne Grund wurden nachträglich viele Wege im Lebenszyklus rückwärts eingeführt, nicht grundlos wurden Alternativen wie Prototyping und Spiralenmodell entwickelt.

Unabhängig davon, in welcher Phase sich die Beschreibung eines Systems befindet, es ist immer wieder das gleiche System. Wäre dies nicht so oder wäre die Semantik der Beschreibungen in den verschiedenen Phasen verschieden, hätte das fatale Folgen.

Phasen stellen somit verschiedene Sichten auf das Modell dar, die gemäß ihrer Perspektive über einem gleichbleibenden Modell verschiedene Ausschnitte in verschiedener Repräsentation zeigen. Diese verschiedenen Repräsentationen werden durch verschiedene Sprachen gewährleistet. Es ist einleuchtend: zur Implementierung wird eine andere Sprache benutzt als zur Systemanalyse. Auch wenn dies dem einen Leser zu trivial oder dem anderen zu theoretisch erscheinen mag, eine wenn auch zugegebenermaßen zur Zeit etwas utopische, aber dennoch ganz konkrete Schlußfolgerung für zukünftige CASE-Systeme läßt sich sofort ableiten.

Bei Veränderungen des Modells in einer der Sichten werden die anderen Sichten auf den gleichen Modellausschnitt in Echtzeit analog verändert. Voraussetzungen sind hierfür Generatoren und aktive, dynamische Systeme.

Ein Planspiel zur Generator-Entwicklung

Im folgenden soll eine Systematik dargestellt werden, nach der mögliche Generatoren abgeleitet werden können. Die verwendeten Tabellen können natürlich noch erweitert werden. Gehen wir von den Phasen Analyse, Design und Implementierung aus, wobei die Analysephase in die Erstellung des essentiellen und des Implementierungsmodells unterteilt werden soll.

Innerhalb dieser Phase bieten sich verschiedene Sichten auf das Modell, die ihrerseits wieder durch verschiedene Sprachen beschrieben werden können. Trägt man nun diese Phasen, Sichten und Sprachen in eine zweidimensionale Matrix ein, dann können paarweise Sprachen markiert werden, zwischen denen sinnvollerweise ein automatischer Übergang geschaffen werden sollte (vergleiche Abbildung 2).

In der Matrix sind mögliche Generatoren in Implementierungsrichtung eingetragen. Die unterlegten Felder markieren benachbarte Phasen. Generatoren, die in diesen Feldern liegen, verbinden also direkt nebeneinander liegende Phasen. Interessant sind nun diejenigen Generatoren, die außerhalb dieser Felder liegen. Entweder bilden sie innerhalb der gleichen Phase ab (wie Struktogramm nach Source) oder sie überspringen eine Phase.

Der Übergang von Struktogramm (STG) Source (SRG) ist unproblematisch, denn die Abbildung ändert lediglich die Sprache und bleibt zudem in der gleichen Sicht. Beachtenswert ist aber das Überspringen einer Phase. Darf dies erlaubt werden, kann das gutgehen? Darf man dies einem automatischen System überlassen? Gerade für den letzten, interessanten Fall gibt es ein Beispiel: X-Tract, der das Implementierungsmodell des Excelerator einliest und C- oder Ada-Code in Struktogrammform erzeugt. Dieses Werkzeug soll im folgenden kurz vorgestellt werden.

Das Tool ist in mehrere Bereiche untergliedert. In einem Front-end werden die Daten aus den Data Dictionary des Excelerator eingelesen und eine interne Repräsentation erzeugt. In einer Black-Box-Komponente laufen spezielle Analysen und das Ausbalancieren von Datenflüssen über alle Ebenen der Verfeinerung hinweg. Der Code-Generator ist danach für die Erzeugung der Struktogramme verantwortlich.

Kehren wir zurück zu der Generierung über direkt benachbarte Phasen hinweg, das heißt, zu der konkreten Frage: Darf Man es einem Generator überlassen, selbständig über das Softwaredesign zu entscheiden?

Um dies zu klären, müssen zwei Aspekte untersucht werden:

a) Kann der Benutzer in die Arbeitsweise des Generators eingreifen?

b) Welches Konzept steht hinter dem Softwaredesign, welche Modularisierung wird erzeugt?

Diese Aspekte können jedoch nur an jeweils konkreten Fällen untersucht werden.

So ist unter den Menüs von X-Tract der Punkt EDIT CONFIG zu finden. Von hier aus kann der Generator durch Parametrisierung gesteuert werden. Mit anderen Worten, der Benutzer definiert an dieser Stelle Zielvorgaben und das Werkzeug ist in der Lage, darauf zu reagieren. Darüber hinaus kann das lmplementierungsmodell um weitere Zielvorgaben erweitert werden.

Ziele lassen sich in drei Klassen einteilen

Diese Ziele lassen sich in drei Klassen einteilen. Zur Projektumgebung gehört die Festlegung der Directories für die Spezifikation, die interne Datenbasis und die generierten Struktogramme. Unter Umständen kann es vorteilhaft sein, die interne Datenbasis über die Laufzeit des Systems hinaus zu erhalten. Und schließlich kann die Namensvergabe für die Struktogramme formale Aspekte beisteuern.

Die formalen Aspekte betreffen die Form und den Aufbau der erzeugten Struktogramme und weitere Merkmale, die die Semantik der Struktogramme nicht verändern. Dies sind die Ausgabe von Meldungen, die Steuerung von Ausblendungsebenen (verfeinerungsebenen) die der Abbildung von Audit Attributes und der Abbildung von Descriptions dienen.

Da die einzelnen Compiler verschiedene Identifikationslängen verarbeiten können und der besseren Lesbarkeit willen die längstmöglichen Namen erzeugt werden sollen, kann die maximale Länge der zu erzeugenden Identifier angegeben werden.

Diese Zielvorgaben werden im Implementierungsmodell des Excelerators nach Ward und Mellor vorgenommen. Sie beeinflussen die Art und Weise, wie die Spezifikation auf Software abgebildet wird.

Es ist insbesondere möglich, zu definieren, welcher Prozeß auf Task-, und welcher auf Modulebene liegen soll Damit, so haben eigene Anwendungen gezeigt, ergeben sich faszinierende Anwendungsmöglichkeiten.

Es steht dem Entwickler frei, verschiedene Softwareentwürfe generieren zu lassen, um hinterher den besten zu nehmen und die anderen wieder zu verwerfen. Dies ist eine Vorgehensweise, die bei einer intellektuellen nicht automatisierten Codegenerierung viel zu teuer werden würde.

Die zentrale Frage bleibt aber diejenige nach der Qualität der Modularisierung. Denn besonders an automatisch erzeugten Code werden hohe Anforderungen bezüglich Modulkopplung und Modulfestigkeit gestellt. Daher sollen nun diese Aspekte näher untersucht werden.

Die Modularisierung ist ausschlaggebend

ln der Literatur werden verschiedene Arten der äußeren Bindungskraft, also der Kopplung zwischen den Modulen, vorgestellt. Prinzipiell gilt, je schwächer diese Kopplung ist, um so besser.

a) Inhaltskopplung (Kopplungsmechanismus): Ein Modul greift direkt auf ein Datenelement eines anderem Moduls zu oder verändert dort Adressen.

b) Systembereichskopplung (Schnittstellenbreite): Zwei Module benutzen gemeinsame Datenbereich, in Fortran zum Beispiel COMMON-Bereiche.

c) Externkopplung (Schnittstellenbreite): Zwei Module benutzen gemeinsame globale Daten. d) Zustandskopplung (Kommunikationsart): Zwischen zwei Modulen werden Steuerinformationen ausgetauscht.

e) Datenstrukturkoppelung (Schnittstellenbreite): Wird ein Modul mit einer zusammenhängenden Datenstruktur als Parameter aufgerufen, besteht eine schmalere Kopplung als wenn viele einzelne Datenelemente übergeben würden. Eventuell werden nicht alle Teile der Datenstruktur benötigt.

f) Datenelementkopplung (Schnittstellenbreite): Zwischen zwei Modulen werden einzelne Datenelemente ausgetauscht. Die Schnittstelle wird noch schmaler. Die Prinzipien der Modulkoppelung gelten nicht nur auf der Softwareebene, sondern auch im Implementierungsmodell.

Betrachten wir also das Implementierungsmodell, aus dem heraus der Code generiert wird. Dabei ist zu beachten daß Module immer nur aus einem vollständigen Graphen des Implementierungsmodells, also aus Explosionen des Prozesses, der der oberste Prozeß der Modulebene ist, entstehen.

Bei der Definition der Zielvorgaben des Beispielgenerators haben wir gesehen, daß im Implementierungsmodell definiert werden kann, ob ein Prozeß zur Task- oder zur Modulebene gehören soll. Wird ein Prozeß auf die Modulebene gelegt, müssen alle seine Explosionen (Verfeinerungen) ebenfalls auf Modulebene liegen. Ein in den Prozeß hineingehendes Signal wird als Aufruf realisiert. Alle in den obersten Prozeß hinein- oder hinausgehende Datenflüsse dürfen, wenn nicht schon die Spezifikation falsch ist, ausschließlich Datenstrukturen oder Datenelemente enthalten.

Somit kann X-Tract konzeptionell nur eine Datenstruktur- und eine Datenelementkopplung erzeugen. Eine ähnliche Situation ergibt sich bei der Betrachtung der inneren Bindungskraft der Module. Hier wird unterschieden zwischen:

a) zufällige Festigkeit: Was alles in einem Modul zusammengefaßt ist, beruht auf reinem Zufall.

b) logische Festigkeit: Hier sind Funktionen zusammengefaßt, die unter logischem und algorithmischem Aspekt ähnlich sind.

c) klassische (zeitliche) Festigkeit: Die Funktionen stehen zusätzlich zur logischen Festigkeit in einer bestimmten zeitlich Abfolge zueinander. Die einzelnen Aktivitäten selbst sind oft unabhängig voneinander

d) prozedurale Festigkeit: Zeitlich nacheinander auszuführende Funktionen sind willkürlich in einzelne Abschnitte zerlegt. Die Ursachen der Zerlegung sind inhaltsfremd, etwa Speicherplatzbedarf. Da die Zerlegung oft willkürlich ist, existiert keine saubere Datenschnittstelle.

e) kommunikative Festigkeit: Die in dem Modul zusammengefaßten Funktionen haben die gleichen Ein- oder Ausgabedaten. Die Reihenfolge der einzelnen Funktionen ist oft nicht festgelegt. Falls sie es aber ist, kann man von sequentieller Festigkeit sprechen.

f) funktionale Festigkeit: Hier dienen alle im Modul enthaltenen Funktionen genau einer einzigen definierten Aufgabe. Dies ist die stärkste Form der Modulfestigkeit.

Im Implementierungsmodell wird, wie oben schon beschrieben wurde, über die Verfeinerungsstufen aus dem obersten (quasi Modul-) Prozeß der komplette Baum der Explosionen entwickelt.

Alle Prozesse und Graphen dieser Verfeinerungen dienen der eines Aufgabe des obersten Modulprozesses. Da der Generator alle Verfeinerungen dieses obersten Prozesses zu einem Modul zusammenfaßt, müssen alle Funktionen in diesem Modul zwangsläufig genau dieser einen Aufgabe des obersten Prozesses dienen.

Aus den Betrachtungen ist zu schließen, daß zumindest für den hier vorgeführten Fall unser Beispiel-Generator eine akzeptable Modularisierung erzeugt. Das Produkt gehört zu denen, die nach der Matrix in Abbildung 2 außerhalb der Generierung zwischen den paarweisen Phasen liegen. Bei diesen hatte sich die Frage gestellt, ob so etwas überhaupt theoretisch im Sinne einer guten Qualität erlaubt werden dürfte.

Bei näherer Betrachtung ergibt sich nun, daß die Phase des Softwaredesign nicht übergangen oder gar vergessen wird sondern daß X-Tract selbst ein Softwaredesign durchführt und daraufhin Code generiert. Das Design selbst liegt aber nicht in einer Form vor, die man unmittelbar niederschreiben könnte sondern sie ist implizit im Laufe der Anwendung des regelbasierten Systems vorhanden. Generatoren und intelligente Werkzeuge werden immer weiter entwickelt und breiter eingesetzt.

Für die Entwicklung solcher Tools ist großes theoretisches Wissen und eine Menge Erfahrung notwendig, und zwar nicht nur im Tool-Bereich selbst, sondern auch in der Anwendung sowie bei der Software-Entwicklung im Anwendungsbereich der Tools, also Projekterfahrung.

Dr. M. Thiel ist Entwicklungsleiter mit Aufgabengebiet Software-Entwicklung CASE-Bereich und kundenspezifische Software-Entwicklungen der AiD, Ingenieurgesellschaft für Mikrocomputer Hard- und Software mbH, Nürnberg