Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
Teil I - Übersicht

2 Kurze Einführung am Beispiel Speichern Unter - Dialog

In diesem Kapitel wird an Hand eines einfachen Beispiels die Tango-Beschreibungsmethodik vorgestellt. Das Beispiel wird Stück für Stück rekonstruiert, dabei werden Sprachelemente erläutert, soweit dies zum Verständnis des Beispiels notwendig ist. Eine detailliertere Besprechung der Tango-Beschreibungsmethodik ist späteren Kapiteln vorbehalten.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

2.1 Beispiel: Speichern Unter - Dialog

In den meisten Software-Anwendungen wird über einen Menüpunkt ähnlich Datei | Speichern unter die Möglichkeit zur Speicherung von Arbeitsergebnissen angeboten. Es kann vorausgesetzt werden, dass die prinzipielle Funktionsweise dieses Menüpunktes dem Leser vertraut ist. Eine vereinfachte Version dieser Programmfunktion wird im Folgenden mit Tango beschrieben. Dies ist das klassische Lern-Beispiel, um mit möglichst wenig Aufwand eine Tango-Beschreibung lesen zu können.

Die Beschreibung soll beginnen, wenn ein Anwender den Menüpunkt Datei | Speichern unter ausgewählt hat. Es erscheint ein Dialogfenster.


Beispiel einer Tango-Spezifikation: Speichern Unter-Dialog

!#WnSpeichernUnterDialog
    .$Inhalt <- EXTERN.{zu speichernde Daten}
    .EtDateiMitPfad : [ leer | FormatFalsch | VerzeichnisExistiertNicht |
                        DateiExistiert | DateiIstNeu ]
        .+CR                             // Return-Taste
            =>  .@PrüfeSpeichern
    .+BtSpeichern
        =>  .@PrüfeSpeichern
    .+BtAbbrechen
        =>  .WnSpeichernUnterDialog.CLOSE


!@PrüfeSpeichern
    =>  ? WnSpeichernUnterDialog.EtDateiMitPfad =
            = leer
                =>  .BEEP
            = FormatFalsch
                =>  .USER << "Kein gültiges Dateinamen-Format"
            = VerzeichnisExistiertNicht
                =>  .USER << "Verzeichnis existiert nicht"  // Wird nicht automatisch angelegt
            = DateiExistiert
                =>  .? USER << "Datei existiert, überschreiben?" =
                        = "Ja, überschreiben"
                            =>  .@JetztSpeichern
                        = "Nein, nicht überschreiben"
                            =>  .WnSpeichernUnterDialog.EtDateiMitPfad.MARKIEREN
                                    .{ganzen Inhalt des Feldes selektieren und Focus drauf setzen}
                        = "Aktion abbrechen"
                            =>  .NOP
            = DateiIstNeu
                =>  .@JetztSpeichern


!@JetztSpeichern
    =>  .$DateiMitPfad <- WnSpeichernUnterDialog.EtDateiMitPfad
        .$Inhalt <- WnSpeichernUnterDialog.Inhalt
        .?{Datei $DateiMitPfad angelegt oder ersetzt mit $Inhalt} =
            = "OK, erfolgreich gespeichert"
                =>  WnSpeichernUnterDialog.CLOSE
            = "NOK, etwas ging schief"
                =>  USER << "Speichern war nicht erfolgreich"
Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

2.2 Erläuterung der Spezifikation

Die Spezifikation des Speichern Unter-Dialogs wird im Folgenden interpretiert und rekonstruiert. Die komplette Spezifikation kann, wenn gewünscht, in einem eigenen Fenster neben diesem Text geöffnet werden. Die relevanten Teile der Spezifikation werden hier nochmals wiedergegeben, bevor sie interpretiert und nachfolgend erklärt werden. Die Begriffe der Tango-Beschreibungssprache werden im Folgenden als Literale markiert, die Bezüge auf das bearbeitete oder andere Beispiele als Code.

Erster Schritt: Einstieg

!#WnSpeichernUnterDialog
    .$Inhalt <- EXTERN.{zu speichernde Daten}
    .EtDateiMitPfad
    .+BtSpeichern
    .+BtAbbrechen

Es gibt einen Container, genauer ein Fenster WnSpeichernUnterDialog. Dieses besteht aus einem Zustand Inhalt, der von außerhalb gefüllt wird, des Weiteren aus einem Eingabetextfeld EtDateiMitPfad, sowie zwei Knöpfen BtSpeichern und BtAbbrechen.

Jede Tango-Spezifikation beschreibt eine Menge von Eigenschaften des Systems, bezeichnet als Aspekte. Aspekte können lokalisierbare Elemente sein (z.B. ein Bedienknopf auf einer grafischen Oberfläche) oder allgemeine Eigenschaften (z.B. maximale Antwortzeit auf eine Anfrage). Die Aspekte werden aufgezählt und verfeinert durch untergeordnete Aspekte.

Eine Tango-Spezifikation besteht aus einer Folge von Definitionsblöcken, die mit dem Ausrufezeichen ! eingeleitet werden. Die erste Zeile eines Definitionsblocks bezeichnet einen Aspekt, hier das Element WnSpeichernUnterDialog, das in den Folgezeilen des Definitionsblocks durch weitere Aspekte beschrieben wird. Die Unteraspekte sind unter der Kopfzeile eingerückt.

Die Markierung # kennzeichnet einen Container, also ein Element, das aus mehreren anderen Teilen besteht. Jedes Element in der Spezifikation kann aus vielen Teilen bestehen, dies ist keine ungewöhnliche Eigenschaft. Ein Container ist explizit als solcher markiert, weil die Zusammenfassung mehrerer Elemente an dieser Stelle für den Anwender von besonderer Bedeutung ist. Die Kennzeichnung als Container ist optional.

Wn ist ein Spezialisierungsprefix, der ein Fenster (Window) kennzeichnet. Spezialisierungsprefixe sind ein Teil des Aspektnamens. Sie müssen nicht verwendet werden, aber sie bieten die Möglichkeit, das Wesen des Aspekts genauer zu bezeichnen. Es gibt keine verbindliche Liste von Spezialisierungsprefixen, sie können je nach Anwendungsgebiet selbst vergeben werden. Die in diesem Beispiel verwendeten Zwei-Buchstaben-Prefixe sind üblich für die Beschreibung von Software.

Die einzelnen Unteraspekte sind als Aufzählung mit einem führenden Punkt . niedergeschrieben. Die Reihenfolge der Unteraspekte in einer Aufzählung ist nicht signifikant, die Abfolge der Unteraspekte könnte also beliebig vertauscht werden, ohne dass sich an der Aussage der Spezifikation etwas ändert.

Die Markierung + kennzeichnet einen Aktivator. Ein solches Element wird verwendet, um ein Ereignis entgegenzunehmen. Dies kann ein Knopf sein, der gedrückt wird, oder aber ein Tastendruck wie Control-S oder Return . Das Element WnSpeichernUnterDialog enthält die Aktivatoren BtSpeichern und BtAbbrechen.

Der Spezialisierungsprefix Bt kennzeichnet einen Knopf (Button) im Fenster.

Ein weiterer Unteraspekt von WnSpeichernUnterDialog ist das Eingabefeld EtDateiMitPfad. Der Spezialisierungsprefix Et kennzeichnet ein Feld, in das Text geschrieben werden kann (Editable text).

Der Unteraspekt Inhalt ist ein Zustand, der durch die Markierung $ als solcher gekennzeichnet ist. Inhalt verweist in diesem Beispiel auf Daten, die nicht innerhalb des spezifizierten Systems, sondern von außerhalb zur Verfügung gestellt werden. Das Verweis-Konstrukt

 lokalerAspekt <- andererAspekt 
bedeutet:
Der an dieser Stelle definierte Aspekt lokalerAspekt beschreibt ein Element, das an anderer Stelle als andererAspekt bereits beschrieben wurde, und dieses fremde Element kann unter der Bezeichnung lokalerAspekt so verwendet werden, als wäre es direkt hier definiert worden.

EXTERN in Großbuchstaben kennzeichnet einen terminalen Aspekt. Terminale Aspekte werden in der Domäne, also dem Themenbereich oder Fachbereich einer Tango-Spezifikation als bekannt vorausgesetzt und müssen deshalb nicht näher erläutert werden. EXTERN erlaubt per Konvention den Zugriff auf Information, die von irgendwoher angeliefert wurde, und das spezifizierte System kann sich darauf verlassen, dass diese Information zur Verfügung steht. Ein formlos beschriebener Unteraspekt {zu speichernde Daten} von EXTERN erlaubt den Zugriff auf diese Daten. Die zu speichernden Daten stehen durch Nutzung des Verweis-Konstrukts unter der Bezeichnung Inhalt zur Verfügung.

Aspekte müssen nicht unbedingt durch Namen benannt werden, sie können auch durch eine formlose Beschreibung in geschweiften Klammern angegeben werden. Die durch einen Punkt getrennte Angabe von Aspekten EXTERN.{zu speichernde Daten} ist ein Pfad, der auf einen Unteraspekt von EXTERN verweist.

Nächster Schritt: Details 1

!#WnSpeichernUnterDialog
    .+BtSpeichern
        =>  .@PrüfeSpeichern
    .+BtAbbrechen
        =>  .WnSpeichernUnterDialog.CLOSE
    ...

Wenn in WnSpeichernUnterDialog der Knopf BtSpeichern gedrückt wird, dann wird die Aktion PrüfeSpeichern ausgeführt. Wenn der Knopf BtAbbrechen gedrückt wird, dann ist das Fenster WnSpeichernUnterDialog anschließend geschlossen. WnSpeichernUnterDialog enthält noch weitere Beschreibungsteile.

Die Ellipse ... zeigt an, dass diese Beschreibung unvollständig ist. Die Einrückung der Ellipse sagt, dass Unteraspekte von WnSpeichernUnterDialog fehlen.

Der Wirkungspfeil => unter einem Aktivator kennzeichnet einen Aktivitätsblock, in dem die Wirkungen niedergeschrieben sind, die beim Auslösen des Aktivators eintreten. Die einzelnen Aktivitäten sind Unteraspekte des Aktivitätsblocks. In diesem Ausschnitt des Beispiels hat jeder Aktivitätsblock nur eine einzige Aktivität.

CLOSE ist ein terminaler Aspekt, genauer ein als bekannt vorausgesetztes Ereignis, das am Fenster WnSpeichernUnterDialog ausgelöst werden kann. CLOSE ist nicht als Ereignis markiert, da es als bekannt vorausgesetzt wird, es könnte aber im Falle von Unklarheiten als Ereignis *WnSpeichernUnterDialog.CLOSE markiert werden.

Die Markierung @ im Aktivitätsblock von BtSpeichern kennzeichnet eine Aktion namens PrüfeSpeichern. Diese Aktion besteht aus einem Aktivitätsblock, der an anderer Stelle der Spezifikation in einem eigenen Definitionsblock beschrieben ist. Die Nutzung des Namens der Aktion erspart an dieser Stelle die explizite Niederschrift des Aktivitätsblocks der Aktion .PrüfeSpeichern

Nächster Schritt: Details 2

!#WnSpeichernUnterDialog
    .EtDateiMitPfad : [ leer | FormatFalsch | VerzeichnisExistiertNicht |
                        DateiExistiert | DateiIstNeu ]
        .+CR                             // Return-Taste
            =>  .@PrüfeSpeichern
    ...

Das Eingabetextfeld EtDateiMitPfad enthält einen Aktivator CR , d.h. mit dem Drücken der Return-Taste im Eingabetextfeld kann die Aktion PrüfeSpeichern ausgelöst werden.

Das Feld EtDateiMitPfad kann mehrere Zustände einnehmen: Das Feld kann leer sein, das Format des eingegebenen Textes ist falsch, das angegebene Verzeichnis existiert nicht, die angegebene Datei ist vorhanden oder nicht vorhanden.

Das Feld EtDateiMitPfad kann verschiedene Zustände einnehmen, die zu unterschiedlichen Reaktionen des beschriebenen Systems führen. Die Aufzählung der verschiedenen Zustände an dieser Stelle ist optional. Es würde genügen, die einzelnen Fälle dort zu unterscheiden, wo tatsächlich unterschiedliche Wirkungen eintreten, in diesem Beispiel in der Aktion @PrüfeSpeichern.

Die Inhaltsbeschreibung

   einElement : möglicheInhalte

erlaubt Aussagen über die Werte, die der Zustand einElement annehmen kann. Die Beschreibung möglicheInhalte kann eine Auswahlliste sein:

   [ alternative1 | alternative2 | alternative3 ]
Die Auswahlliste enthält die Werte selbst oder Beschreibungen der Werte von einElement, und für jeden möglichen Wert muss mindestens eine der Alternativen zutreffen. Wenn sich die Alternativen überschneiden, wenn also ein Wert in mehr als eine Alternative passt, so ist dies ohne Bedeutung.

Die Markierung // kennzeichnet einen Kommentar bis zum Ende der Zeile. Ein Kommentar ist nur für den Leser bestimmt, er ist kein Teil der Spezifikation. Soll die Information in der Spezifikation Berücksichtigung finden, kann stattdessen eine formlose Beschreibung verwendet werden.

Nächster Schritt: PrüfeSpeichern

!@PrüfeSpeichern
    =>  ? WnSpeichernUnterDialog.EtDateiMitPfad =
            = leer
                =>  .BEEP
            = FormatFalsch
                =>  .USER << "Kein gültiges Dateinamen-Format"
            = VerzeichnisExistiertNicht
                =>  .USER << "Verzeichnis existiert nicht"  // Wird nicht automatisch angelegt
            = DateiExistiert
                =>  .? USER << "Datei existiert, überschreiben?" =
                        = "Ja, überschreiben"
                            =>  .@JetztSpeichern
                        = "Nein, nicht überschreiben"
                            =>  .WnSpeichernUnterDialog.EtDateiMitPfad.MARKIEREN
                                    .{ganzen Inhalt des Feldes selektieren und Focus drauf setzen}
                        = "Aktion abbrechen"
                            =>  .NOP
            = DateiIstNeu
                =>  .@JetztSpeichern

Es gibt eine Aktion PrüfeSpeichern. Hier wird geprüft, welchen Zustand der Inhalt von WnSpeichernUnterDialog.EtDateiMitPfad hat.

Die Verzweigung

    ? Wertlieferant =
        = wert1
            =>  .machWas
        = wert2
            =>  .machWasAnderes
erlaubt Wirkungen zu beschreiben, die nur unter bestimmten Bedingungen eintreten. Die Wirkungen werden in einem Aktivitätsblock unter der jeweiligen Alternative beschrieben Es können beliebig viele Alternativen angegeben werden. Die Wirkungen der ersten zutreffenden Alternative treten ein, alle nachfolgenden Bedingungen werden ignoriert. Es wird also immer genau ein Aktivitätsblock wirksam. Wenn der Wertlieferant einen Wert annehmen könnte, so dass keine der Bedingungen gültig ist, dann wäre dies ein Fehler in der Spezifikation.

Wenn die Datei bereits existiert und der USER (terminaler Aspekt, deshalb selbsterklärend) die Frage nach dem Überschreiben unbeantwortet lässt und stattdessen die Aktion abbricht, dann soll das System keine Handlung ausführen. Dazu wird die terminale NOP-Aktivität (No Operation) in den Aktivitätsblock geschrieben.

Das Versenden von Information oder Werten an einen beliebigen Empfänger im beschriebenen System oder außerhalb wird durch das folgende Konstrukt beschrieben:

    Empfänger << Information
Die Information wird an den Empfänger übermittelt, die Entgegennahme oder Bearbeitung ist Aufgabe des Empfängers. Aus Sicht des Empfängers ist diese übersandte Information über den terminalen Aspekt EXTERN zugänglich. Dem Empfänger steht frei, ob und wann er die Information nutzt. Die Meldung "Kein gültiges Dateinamen-Format" wird dem USER zur Verfügung gestellt, und der USER kann diese Meldung sofort, später oder überhaupt nicht zur Kenntnis nehmen.

Existiert die Datei, so wird der USER gefragt, wie weiter vorzugehen ist. In diesem Fall wird wie bei jedem Versenden Information an den USER versandt, aber das System wartet jetzt, bis der USER antwortet. Das Senden-Konstrukt ist hier der Wertlieferant für eine Verzweigung:

            = DateiExistiert
                =>  .? USER << "Datei existiert, überschreiben?" =
                        = "Ja, überschreiben"
                            ...

Mit der Verzweigung werden die drei USER-Antwortalternativen bearbeitet.

Eine formlose Wertbeschreibung wird von Gänsefüßchen eingefasst, sie beschreibt den Wert eines Zustandes oder allgemein irgendeine Information. Die Beschreibung entspricht nicht notwendigerweise dem tatsächlichen Inhalt, sie soll die Bedeutung des Wertes wiedergeben. Deshalb kann nicht davon ausgegangen werden, dass der USER tatsächlich eine wörtliche Meldung "Kein gültiges Dateinamen-Format" erhält. Die möglichen USER-Antworten sind ebenfalls als formlose Wertbeschreibungen notiert, und auch hier ist der Sinn der Antwort beschrieben. Ergänzende Information zu der Bedeutung der Alternativen ist üblich und einem trockenen Ja oder Nein vorzuziehen.

Wenn eine existierende Datei nicht überschrieben werden soll, dann wird das Eingabefeld WnSpeichernUnterDialog.EtDateiMitPfad zur Bearbeitung vorbereitet, indem der Inhalt selektiert wird und der Focus auf dieses Feld gesetzt wird:

                        = "Nein, nicht überschreiben"
                            =>  .WnSpeichernUnterDialog.EtDateiMitPfad.MARKIEREN
                                    .{ganzen Inhalt des Feldes selektieren und Focus drauf setzen}

Das MARKIEREN ist ein terminaler Aspekt, weil dieses Ereignis für Eingabetextfelder üblich ist. Trotzdem wird hier mit einer Verfeinerung klargestellt, was mit MARKIEREN eigentlich gemeint ist. Jeder Aspekt, auch ein terminaler, kann durch Unteraspekte genauer beschrieben werden.

Letzter Schritt: JetztSpeichern

!@JetztSpeichern
    =>  .$DateiMitPfad <- WnSpeichernUnterDialog.EtDateiMitPfad
        .$Inhalt <- WnSpeichernUnterDialog.Inhalt
        .?{Datei $DateiMitPfad angelegt oder ersetzt mit $Inhalt} =
            = "OK, erfolgreich gespeichert"
                =>  .WnSpeichernUnterDialog.CLOSE
            = "NOK, etwas ging schief"
                =>  .USER << "Speichern war nicht erfolgreich"

Die Aktion JetztSpeichern legt eine neue Datei an oder sie ersetzt eine vorhandene Datei. Der Inhalt wird in diese Datei geschrieben. Wenn diese Aktivität erfolgreich war, dann wird das Fenster WnSpeichernUnterDialog geschlossen, ansonsten erhält der USER eine Mitteilung, dass das Speichern nicht erfolgreich war.

DateiMitPfad und Inhalt sind Verweise auf andere Zustände im beschriebenen System. Diese wären auch ohne die Verweise zugänglich, so dass die Nutzung von Verweisen an dieser Stelle nur eine Schreibvereinfachung ist.

Die wesentliche Aktivität ist als formlose Beschreibung notiert: {Datei $DateiMitPfad angelegt oder ersetzt mit $Inhalt}. Eine formlose Beschreibung oder ein anderer terminaler Aspekt sind der übliche Endpunkt einer Verfeinerung in einer Tango-Spezifikation, denn irgendwann überwiegen die Implementierungsdetails, die nicht Teil dieser Spezifikation sind.

Das Schreiben in die Datei kann erfolgreich sein oder nicht, deshalb ist diese Aktivität ein Wertlieferant. Abhängig vom Erfolg dieser Handlung wird der jeweilige Aktivitätsblock ausgeführt. Das Schließen des Fensters WnSpeichernUnterDialog ist gleichzeitig das Ende der Aktivitäten am beschriebenen System, denn es ist jetzt nichts mehr vorhanden, was bedient werden könnte. Damit ist auch das Ende der Beschreibung erreicht.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

2.3 Anmerkungen zum Beispiel

Globale Sichtbarkeit von Elementen

Auffällig ist, dass in der Beschreibung von jeder Stelle aus auf jeden Aspekt außerhalb eines Aktivitätsblocks zugegriffen werden kann und tatsächlich auch zugegriffen wird. Alle Aspekte sind immer gültig, die beschriebenen Elemente sind immer vorhanden und für die Beschreibung zugänglich, es gibt also keinen Namensraum (jedenfalls in diesem Beispiel). Die Gruppierung von Elementen in Objekte oder andere Grenzen wird als Implementierungsdetail angesehen und ist deshalb nicht Teil der Spezifikation. Es soll hier nicht festgelegt werden, wie spätere Objekte, Module oder Komponenten aussehen sollen, sondern nur, wie sie gemeinsam funktionieren.

Artikulationsprobleme bei Aktivitäten

Formlose Beschreibungen von Aktivitäten haben das grundsätzliche Problem, dass hier eigentlich keine Aktivitäten beschrieben werden, sondern Wirkungen von durchgeführten Aktivitäten. Wenn exakt formuliert wird, dann klingt die Beschreibung hölzern: {$DateiMitPfad angelegt oder ersetzt mit $Inhalt}. Diese Formulierung enthält, dass eine Aktivität vorausging und jetzt das Ergebnis überprüft werden soll. Lesbarer wäre: {$DateiMitPfad anlegen oder ersetzen mit $Inhalt}. Dies impliziert aber eine Aktion, die an dieser Stelle erst durchgeführt wird, also eine Aufforderung. Üblicherweise wird die geschmeidige letzte Variante der Formulierung gewählt, es muss aber berücksichtigt werden, dass in einer Tango-Spezifikation immer die Ergebnisse betrachtet werden, niemals die Aktivitäten, die zu den Ergebnissen führen. Die im Beispiel verwendete Formulierung {ganzen Inhalt des Feldes selektieren und Focus drauf setzen} ist also üblich, aber etwas missverständlich.

Aktivitäten an ungewöhnlichen Stellen

Das Fenster WnSpeichernUnterDialog wird in der Aktion JetztSpeichern geschlossen, was in einem Programmcode eine merkwürdige Stelle wäre. Im Code würde niemand damit rechnen, dass in einer Prozedur JetztSpeichern irgendwelche Fenster geschlossen werden.

Aktionen oder Aktivitätsblöcke sind keine Prozeduren und keine Funktionen, sondern lediglich Zusammenstellungen von Wirkungen. Hier gilt der Grundsatz "Was an dieser Stelle passiert (genauer: beobachtet wird), wird an dieser Stelle hingeschrieben". Aus Sicht eines Programmierers ist diese Vorgehensweise zumindest kaltblütig, in einer Tango-Spezifikation ist diese Art der Niederschrift der Normalfall.

Implizite Schleife

In diesem Beispiel wird eine Schleife beschrieben, denn solange das Fenster WnSpeichernUnterDialog offen bleibt, können weitere Aktivitäten durchgeführt werden. Der insgesamt beschriebene Vorgang ist erst dann abgeschlossen, wenn WnSpeichernUnterDialog geschlossen wurde, einfach deshalb, weil ab diesem Zeitpunkt keine weiteren Bedienschritte mehr möglich sind. Die Programmschleife hinter diesem Verhalten ist für einen Programmierer relevant, für Tango entsteht sie als Folge von Bedienschritten am beschriebenen System, und sie ist deshalb irrelevant. Aus diesem Grund gibt es in Tango keine expliziten Schleifenkonstrukte.
Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor