Session D-TIER

3-Schichten-Architektur mit VFP

Sebastian Flucke
ASCI CONSULTING GmbH


Vorbemerkung

Softwareprodukte in einer mehrschichtigen Architektur zu erstellen, wird immer mehr zu einer Anforderung, vor die man sich als Softwareentwickler gestellt sieht.

Diese Anforderung kann direkt Bestandteil der Vorgaben eines Auftraggebers sein, sie kann sich aber auch indirekt entweder aus der Aufgabenstellung selbst oder aus den eigenen Vorstellungen des Entwicklers bezüglich der Art der Realisierung eines Softwareprojektes ergeben.

 

Was ist eine Schichten-Architektur?

Die Grund-Funktionalität eines Software-Bausteins

Ein Software-Baustein ist ein Element einer Software-Applikation mit einem beliebigen Komplexitäts-Niveau.  Als Software-Baustein in diesem Sinn kann man sowohl eine dreizeilige Prozedur als auch eine komplette Applikation betrachten.

Die Grund-Funktionalität eines Software-Bausteins besteht aus drei Phasen:

Die Eingangsdaten können verschiedener Herkunft sein:

Die Verarbeitung der Daten erfolgt durch Algorithmen, die in dem Softwarebaustein als Programmteile hinterlegt sind. Die Ergebnisdaten können analog den Eingangsdaten in transienter oder persistenter Form vorliegen oder exportiert werden (z.B. als Bildschirmausgabe, als Ausdruck, als Export-Datei usw.).

Ein Softwarebaustein aus Sicht seines Anwenders

Aus Sicht des Anwenders gliedert sich eine Software in zwei Teile:

Die Benutzeroberfläche kann in diesem Zusammenhang allerdings zwei sehr unterschiedliche Funktionen erfüllen:

Hinter dem nichtvisuellen Teil verbergen sich wiederum zwei weitere Aspekte:

Client-Server-Architektur

Eine Client-Server-Architektur (C/S) ist eine Form der technischen Gliederung eines Software-Bausteins, die sehr eng an die Sicht eines Anwenders angelehnt ist.

Diese Architektur ist gekennzeichnet durch die Verteilung von Benutzeroberfläche einerseits und nichtvisuellem Teil andererseits auf zwei verschiedene Computer (den Client und den Server), die miteinander verbunden sind.

Der Server hat folgende Merkmale:

Der Client ist durch folgende Merkmale gekennzeichnet:

Das dritte Glied im Bunde der Client-Server-Architektur ist der Kommunikationsweg zwischen Client und Server:

Die Client-Server-Architektur ist also eine Form der Schichten-Architektur.

Sie ist bei der Programmierung von Anwendungssoftware historisch gesehen die erste Schichten-Architektur, die in breiter Front zu Einsatz kam.

Gründe dafür war im wesentlichen ein Kostenminimierung durch den Einsatz weniger leistungsfähiger und damit teurer Server sowie vieler einfacher und damit preiswerter Clients.

 
TIP: Weiterführende Betrachtungen zum Thema Client-Server mit Visual FoxPro können den Sessions der Sektion C/S entnommen werden.

Die 3-Schichten-Architektur

Die 3-Schichten-Architektur ist zeitlich gesehen der Nachfolger der Client-Server-Technologie.

Allerdings steht bei der 3-Schichten-Architektur nicht eine Schichten-Verteilung auf unterschiedliche Computer im Vordergrund, sondern eine inhaltlich-technische Gliederung von Software-Bausteinen, die mehr aus der Sicht des Software-Entwicklers herrührt:

Unter Benutzer-Oberfläche ist die komplette Kommunikation zwischen der Software und dem Anwender zu verstehen. Dazu gehören im klassischen Sinne Eingaben per Tastatur und Maus sowie Ausgaben auf dem Bildschirm, aber auch neuere Möglichkeiten wie z.B. Spracheingabe und -ausgabe.

Dabei ist zu beachten, daß  die Benutzerschnittstelle sowohl ablaufsteuernde Interaktionen beinhaltet als auch echte Dateneingaben und -ausgaben zum Bestandteil haben kann.

Die inhaltliche Verarbeitungslogik umfaßt das inhaltliche Verarbeiten von Benutzer-Aktivitäten sowie daraus resultierende Aktivitäten bezüglich Datenspeicherung und bezüglich Ausgaben für den Benutzer.

Unter dem Begriff Datenspeicherung sind alle technischen Aktivitäten zusammengefaßt, die mit dem Speichern persistenter Daten zusammenhängen.

Die 3-Schichten-Architektur ist ein Mittel zum Erreichen einer höheren Programmier-Flexibilität. Dabei geht es durchaus auch um die Austauschbarkeit der Implementation einzelner Schichten.

Eine saubere 3-Schichten-Architektur ermöglicht es, die Implementation einzelner Schichten durch andere Varianten auszutauschen, die ggf. auch in anderen Programmiersprachen erstellt sind.

3-Schichten-Architektur in der VFP-Praxis

Eine "normale" VFP-Maske

Eine typische Eingabe-Maske könnte z.B. wie folgt aussehen:

  In dieser Maske ist der folgende Minimal-Code hinterlegt:

 

DEFINE CLASS form1 AS form

   ...

   PROCEDURE Load

      USE xyz

   ENDPROC

 

   PROCEDURE txtdatum.Valid

      * Füllen der Alter-Textbox

      This.Parent.txtAlter.Value = ( DATE() - CTOD( This.Value ) ) / 365

   ENDPROC

 

   PROCEDURE cmdok.Click

      IF This.Parent.txtAlter.Value > 66

         WAIT WINDOW "Unzulässiges Alter <s>!"

      ELSE

      SELECT xyz

      TABLEUPDATE()

         ThisForm.Release

      ENDIF

   ENDPROC

 

   PROCEDURE cmdabbrechen.Click

   SELECT xyz

      TABLEREVERT()

      ThisForm.Release

   ENDPROC

 

   PROCEDURE Unload

      USE IN xyz

      ENDPROC

 

ENDDEFINE

Dieses Beispiel zeigt die Umsetzung eines Software-Bausteins mit Visual FoxPro, wie es entstehen könnte, wenn man sich um architektonische Gesichtspunkte keine Gedanken macht.

Betrachtet man dieses Beispiel aus Sicht objekt-orientierter Programmentwicklung, dann ist leicht zu erkennen, welche Schwächen dieser Ansatz schon aus OOP-Sicht hat, denn es handelt sich um keine glückliche Plazierung von "Wissen" und "Verantwortung".

Das Hauptproblem besteht dabei in einer unglücklichen Verknüpfung vor Wissen und Verantwortung:

TIP: Weiterführende Betrachtungen zu dieser Thematik können Sie den Sessions der Sektionen OOP und PROG entnehmen (beachten Sie auch die entsprechenden Sektionen der vergangenen Jahre)!

Eine oop-like strukturierte VFP-Maske

Ein Schritt in die richtige Richtung ist z.B. eine Auslagerung des Wissens um die Aktualisierung von txtAlter in eine entsprechende Methode der Form und die Auslagerung des Wissens um das Rückgängigmachen von Änderungen aus cmdAbbrechen.Click ebenfalls in eine Form-Methode:
 

DEFINE CLASS form1 AS form

   ...

   PROCEDURE Load

      USE xyz

   ENDPROC

 

   PROCEDURE DatumChanged( newDate )

      * Füllen der Alter-Textbox

      This.txtAlter.Value = ( DATE() - CTOD( m.newDate ) ) / 365

   ENDPROC

 

   PROCEDURE txtdatum.Valid

      ThisForm.DatumChanged( This.Value )

   ENDPROC

 

   ...

   PROCEDURE Revert

   SELECT xyz

      TABLEREVERT()

   ENDPROC

 

   PROCEDURE cmdabbrechen.Click

      ThisForm.Revert

      ThisForm.Release

   ENDPROC

   ...

ENDDEFINE

Eine VFP-Maske in 3-Schichten-Architektur

Eine Maske in 3-Schichten-Architektur muß sich in Objekte gliedern, die eindeutig einer der drei Schichten zuzuordnen sind.

D.h. man benötigt Objekte für die Benutzerschnittstelle, Objekte für die Verarbeitungslogik und Objekte zum Abwickeln des eigentlichen Zugriffs auf die persistenten Daten, wie das folgende Fragment zeigt.

 

DEFINE CLASS form1 AS form

   ...

   PROCEDURE Load

      USE xyz

   ENDPROC

 

   PROCEDURE BusinessLogic.DatumChanged( newDate )

      ...

      * NB: die folgende Zeile allein ist natürlich nicht ausreichend!

      lnNeuesAlter = ( DATE() - CTOD( m.newDate ) ) / 365

      ...

   ENDPROC

 

   PROCEDURE txtdatum.Valid

      ThisForm.BusinessLogic.DatumChanged( This.Value )

   ENDPROC

 

   ...

   PROCEDURE DataHandling.Revert

   SELECT xyz

      TABLEREVERT()

   ENDPROC

 

   PROCEDURE cmdabbrechen.Click

      ThisForm.DataHandling.Revert

      ThisForm.Release

   ENDPROC

   ...

ENDDEFINE

Strukturiert man eine VFP-Maske auf diese Art und Weise, kann man Objekte einzelner Schichten z.B. durch andere Implementationsvarianten austauschen:

Austauschbarkeit von Schichten

Schichten und Protokolle

Wenn man unter Nutzung der 3-Schichten-Architektur Softwarebausteine entwickeln will, ist die oben erwähnte eindeutige Zuordnung von Objekten mit ihrem Wissen und ihrer Verantwortung zu jeweils genau einer der Schichten eine wesentliche Grundvoraussetzung.

Diese Verteilung von Wissen und Verantwortung bedeutet damit aber auch zugleich die Notwendigkeit, die  Interfaces zwischen den Objekten und damit zwischen den Schichten festzulegen.

Die Gesamtheit der Objekt-Interfaces für die Kommunikation zwischen zwei der beteiligten Schichten wird als Protokoll bezeichnet und soll im folgenden näher erläutert werden.

Die Anforderungen an das Protokoll zwischen zwei Schichten ergeben sich zwangsläufig aus der Aufgabenverteilung zwischen diesen Schichten.

Generell muß man bei einem Protokoll zwei Ebenen unterscheiden:

Die inhaltliche Ebene eines Protokolls resultiert direkt aus der Aufgabenverteilung zwischen den zwei betroffenen Schichten. Wenn z.B. die Verarbeitungslogik den geänderten Wert eines Feldes verarbeiten soll, muß sie Informationen darüber bekommen, um welches Feld und um auf welchen Wert es sich handelt

Bei der Definition der inhaltlichen Ebene eines Protokolls muß man sich also im wesentlichen von den inhaltlichen Notwendigkeiten leiten lassen.

Die technische Implementation eines Protokolls hängt in hohem Maße von der Spannbreite der einzusetzenden Implementationsvarianten der betroffenen Schichten ab.

Dabei muß man sich auf den kleinsten gemeinsamen Nenner der zu erwartenden Varianten beschränken. Das führt allerdings oft dazu, daß man auf bestimmte Möglichkeiten der leistungsfähigeren Schichten verzichten muß.

Technische Implementation von Protokollen

Technische Protokoll-Implementation innerhalb von Visual FoxPro

Da die technischen Implementationsmöglichkeiten mitunter die inhaltliche Seite eines Protokolls einschränken können, sollen sie zuerst behandelt werden.

Zu unterscheiden ist dabei einerseits zwischen Protokoll-Teilen, die in der jeweils anderen Schicht Aktivitäten auslösen und Protokoll-Teilen, die notwendige Informationen übertragen.

Das Auslösen von Aktivitäten in einer Schicht B durch eine Schicht A kann auf zwei Wegen erfolgen:

Für die aktive Einwirkung von einer auf eine andere Schicht innerhalb von Visual FoxPro gibt es technisch zwei Möglichkeiten:

Die passive Variante ist technisch gesehen eine Erweiterung der aktiven Variante:

Komplexere Kombinationen dieser Varianten werden als "Messaging" bezeichnet

Die Übertragung von Informationen kann auf verschiedenen Wegen erfolgen:

Dabei ist es selbstverständlich möglich, diese verschiedenen Varianten miteinander zu kombinieren. Dies betrifft sowohl die Möglichkeiten des Auslösens von Aktivitäten und des Übertragens von Informationen jeweils für sich genommen als auch in beliebigen Kombinationen von Auslöse- und Übertragungsmechanismen

Ein in bestimmten Fällen besonders praktisches Verfahren ist das sogenannte CallBack-Verfahren. Hierbei löst Schicht A bei Schicht B eine Aktivität aus, die wiederum Schicht B dazu veranlaßt, Methoden von Schicht A aufzurufen, um Details für die auszuführenden Aktion zu ermitteln usw.

Technische Protokoll-Implementation zwischen VFP und anderen Sprachen

Bisher wurden Möglichkeiten für Protokolle innerhalb von Visual FoxPro diskutiert. Steht allerdings der Einsatz von Implementationsvarianten für Schichten außerhalb von Visual FoxPro zur Debatte, sind weitere Restriktionen zu beachten.

Diese potentiellen Restriktionen resultieren im wesentlichen aus der Beschränkung der möglichen Datentypen für die Kommunikation von VFP-Schichten mit in anderen Programmiersprachen erstellten Schichten.

Für die Kommunikation zwischen Schichten, die mit VFP erstellt wurden, und mit anderen Systemen erstellten Schichten kann technisch über folgende Wege ablaufen:

Die Reihenfolge der aufgeführten Varianten ist zugleich eine Rangfolge bezüglich der Eignung für die Schichten-Kommunikation bzw. bzgl. des Aufwandes, den man für die Nutzung betreiben muß.

D.h. wann immer eine COM-/DCOM-Schnittstelle möglich ist, sollte man sie auch nutzen.

Neben den technischen Unterschieden zwischen den vier Varianten sind im Moment zwei wesentliche Einschränkungen bezüglich der Übertragung von Informationen von und zu VFP-fremden Schichten zu beachten:

An dieser Stelle sei nochmals darauf hingewiesen, daß jeweils der kleinste gemeinsame Nenner aller zum Einsatz kommender Entwicklungstools die Möglichkeiten bestimmt, die für die technische Implementation der Protokolle zur Verfügung stehen.

Inhaltliche Implementation von Protokollen

Die inhaltliche Implementation von Protokollen folgt im wesentlichen den allgemeinen Regeln für Design und Implementation objektorientierter Interfaces (siehe Sessions der Sektionen OOP und SOFT).

Dabei sind hier nicht nur die zu übertragenden Daten-Inhalte zu bestimmen, sondern auch die Art und Weise des Aktivierens der jeweiligen Funktionalität.

Es ist dann auch den jeweiligen Restriktionen Rechnung zu tragen, die den einzelnen Schichten auferlegt werden, wie das Beispiel zeigt:

Das A und O der Implementation von Protokollen (sowohl technisch als auch inhaltlich) ist eine ausführliche Dokumentation der zugelassenen Schnittstellen.

Implementation und Instanzierung von Schichten

Geht man jetzt an die Analyse und das Design von Schichten, dann spielt das sorgfältige Design der Protokolle eine entscheidende Rolle.

Das kann durchaus dazu führen, daß man für die universelle Abwicklung der Protokolle zwischen den 3 Hauptschichten eigene Protokoll-Schichten benötigt, und so aus einer 3-Schichten-Architektur schnell eine 5-Schichten-Architektur werden kann:

Für die Kommunikation zwischen diesen 5 Schichten gelten auf etwas anderem Niveau die gleichen Regeln und Restriktionen, die weiter oben schon formuliert wurden.

Im Design-Modell zeigen sich übrigens sehr unterschiedliche Arten der Beziehungen der an der Implementation der Schichtenarchitektur beteiligten Objekte.

Oftmals ist es dabei so, daß Elemente verschiedener Schichten bezüglich des Containements zur Laufzeit sogar bunt gemischt erscheinen.

Die architektonische Gliederung in einzelne Schichten ist also ein Angelegenheit, die sich beim bloßen Anschauen von Klassen und Quelltext nicht ohne weiteres erschließt, sondern eher nur für Verwirrung beim Betrachter sorgt.

Auch deshalb sei nochmals auf die unbedingte Pflicht zur Dokumentation der Schichten-Architektur und der betreffenden Protokolle hingewiesen.

VFP-spezifische Aspekte der Implementierung eines Schichtenmodells

Die zwei Hauptaspekte einer VFP-spezifischen Implementierung des Schichten-Modells sind die folgenden zwei Einschränkungen:

Und damit heißt es eigentlich von zwei Dingen zumindest teilweise wieder Abschied zu nehmen, die zu den Hauptneuerungen von Visual FoxPro gegenüber den Vorgängerversionen gehörten (direkte Datenbindung durch DataBuffering sowie die Arbeit mit Objekt-Referenzen) - aber diese Problematik muß man wohl vom dialektischen Standpunkt aus betrachten!

Zusammenfassung

Die 3- bzw. Mehr-Schichten-Architektur zeigt sich also bei näherem Betrachten durchaus nicht nur als eine Mode-Erscheinung, sondern als eine Methode der Software-Architektur, die im Moment an Bedeutung heftig zunimmt.

Man ist als Software-Entwickler sicherlich gut beraten, sich mit dieser Technologie auseinanderzusetzen und damit auch bezüglich der Tools für die Erstellung von Oberfläche, Verarbeitungslogik und Datenspeicherung über den VFP-Tellerrand hinauszusehen...

...und nicht nur zu sehen, sondern sich mit anderen Tools auch aktiv auseinanderzusetzen ,dennVFP ist zwar ein Tool, welches man für alle drei Schichten als Entwicklungswerkzeug verwenden kann, aber Anforderungen von der Kundschaft ("Kann die Oberflächen nicht in Excel sein, daß kennen die Anwender schon so gut") bzw. fortschreitende Spezialisierung der einzelnen Tools werden es in absehbarer Zeit unmöglich machen, allein mit Visual FoxPro im Softwaregeschäft bestehen zu können!