Webanwendungen objektorientiert entwickeln mit Perl

Objektorientiert programmieren ist pure Praxis und angewandte Theorie

Webanwendungen objektorientiert entwickeln ist eine praktische Angelegenheit. Dabei kommt es gar nicht darauf an, umfangreiche Klassenhierarchien zu entwerfen oder langkettige Vererbungsprozesse in Gang zu setzen. Vielmehr hat eine praktische objektorientierte Entwicklung untenstehende Ziele bzw. Charakteristika:

  1. Programmcode übersichtlich strukturieren,
  2. Vermeidung globaler Variablen,
  3. Datenabstraktion,
  4. klar definierte klassenübergreifende Schnittstellen,
  5. zweckmäßige Fehlerbehandlung,
  6. einfaches Debuggen,
  7. Qualitätssicherung.

Typisch für Webanwendungen ist ein immer wiederkehrender Programmablauf vom Request bis zum Ausliefern der Response, genau darauf ist eine objektorientierte Herangehensweise ausgerichtet ohne ins Klischeehafte abzugleiten. Naheliegend ist es, den Programmablauf innerhalb einer Klasse über eine Instanz derselben zu kontrollieren und zu steuern.

Programmcode übersichtlich strukturieren

Allein dieses Ziel macht deutlich, dass keine umfangreichen Klassenhierarchien anzustreben sind. Ein Fall aus meiner beruflichen Praxis ist mir in Erinnerung, da war die Suche nch einer bestimmten Methode sehr zeitaufwändig weil die gesamte Erbfolge durchlaufen werden musste, bis die Datei mit der Funktionsdefinition endlich gefunden wurde. Besser ist es also, flache Hierarchien anzustreben.

Nun, grundsätzlich gibt es in Perl immer eine Klasse main. Andererseits sind die Aufgabenstellungen und Anforderungen an Webanwendungen sehr vielgestaltig, so dass es nicht möglich ist, sämtlichen Programmcode eines komplexen Webframeworks in der main unterzubringen. Nichts spricht jedoch dagegen, je nach Request-URL eine Subklasse abzuleiten welche von der Klasse main erbt. Somit besteht die Aufgabe der Vererbung darin, dass die Basisklasse eine Reihe von Methoden zur Verfügung stellt, die bei jedem Request ohnehin gebraucht werden und dasselbe gilt sinngemäß für die Vererbung von Eigenschaften.

Die von der Klasse main abgeleitete Subklasse hingegen qualifiziert die dem URL zugeordnete Anwendung. Sie definiert Methoden welche die darzustellenden Inhalte aus beliebigen Datenquellen beschaffen und sie definiert Methoden, die im Fall von Benutzer-Interaktionen Eingaben prüfen, verarbeiten und die entsprechende Response fertigstellen bzw. ausliefern.

Vermeidung globaler Variablen

Beispielsweise wird eine zentrale Konfiguration nicht als globaler Hash eingelesen sondern als Hashreferenz der eigenen Instanz bereits dem Konstruktor mitgegeben. Für einen schreibenden Zugriff auf die Konfiguration greift somit die Instanz in ein eigenes Attribut und kann ggf. am Programmende die geänderten Daten zurück auf die Festplatte schreiben (Destruktor, Cleanup).

Datenabstraktion

Zur persistenten Datenhaltung werden austauschbare Layer definiert. Konkret heißt das, dass im CODE der eigenen Klasse u.U. nicht mehr ersichtlich ist, wie der Layer oder dessen Klasse heißt und ob der die Daten in Dateien oder Datenbanken speichert.

Klar definierte klassenübergreifende Schnittstellen

An die Ausführungen Datenabstraktion anknüpfend: Die eigene Instanz ruft nur noch Methoden auf. Zum Beispiel eine Methode zur Beschaffung aller Daten eines Benutzers und eine Methode zum dauerhaften Speichern, Beispiel:

    # Variablenbindung an Klasse User
    tie my %user, 'User', username => 'Boo'
        or die 'Ubekannter Benutzer';

    # Eigenschaft ändern
    $user{tel} = 1234;

    # Daten wieder persistent machen
    tied(%user)->write;

In diesem Fall ist jdoch der Name es Layers (hier die Klasse User) bekannt. Eine weitere Abstraktion bedient sich der Fabrik-Methode, Methode im Sinne der Herangehensweise: Anstelle im eigenen CODE explizite Instanzen nicht verwandter (fremde) Klassen zu erstellen und mit diesen Instanzen Methoden der fremden Klassen aufzurufen, ruft die eigene Instanz nur noch eigene Methoden auf:

Herkömmlich

    require bSerialize;
    my $bs = bSerialize->new;
    $bs->serialize;

Fabrik

    $self->serialize;

    # in Datei serialize.pm ausgelagerte Methode
    sub serialize{
        my $self = shift;
        require bSerialize;
        $self->{BS} = bSerialize->new
            unless exists $self->{BS};
        return $self->{BS}->serialize(@_);
    }

Konkret: Die fremde Klasse wird in der eigenen Methode eingebunden und diese Methode ggf. in eine eigene Datei ausgelagert. Dadurch wird der CODE wartungsfreundlicher, der eingebundene Layer wird austauschbar und etwaige Änderungen sind nur noch an einer einzigen Stelle erforderlich.

Als ein weiteres wesentliches Merkmal der Fabrikmethode ermöglicht diese eine spätere Einbindung und das Delegieren an Instanzen fremder Klassen (Lazy Delegation).

Zweckmäßige Fehlerbehandlung

Es ist zu unterscheiden zwischen Fehlern welche beispielsweise aufgrund fehlerhafter Benutzereingaben entstehen oder Fehler aufgrund höherer Gewalt wie z.B. Serverausfälle. Diese Unterscheidung wird bereits beim Entwickeln der Klassen getroffen.

Einfaches Debuggen

Für Debugausgaben muss lediglich ein einziger Dump der Instanz erzeugt werden wobei die Ausgabe dessen direkt und ohne Umschweife im Browser erfolgt. Ein aufwändiges und zeitraubendes Durchforsten von Logdateien entfällt weitestgehend, im Zweifelsfall kann an jedem beliebigen Haltepunkt der Inhalt von Variablen direkt im Browser ausgegeben werden.

Qualitätssicherung

Das Einbinden fremder Klassen erfolgt ausschließlich über ausgelagerte Funktionen/Methoden die per AUTOLOAD eingebunden werden. Dadurch ist es möglich, diese Methoden mit Instanzen beliebiger Klassen aufzurufen, d.h., dass das Aufrufen der Methoden ebenso über eine Attrappe (Mock) erfolgen kann. Und dies wiederum ermöglicht sogenannte Unit-Tests für eine automatisierte testgetriebene Entwicklung.

Vom Request bis zur Response

spielt sich alles in einer einzigen Klasse ab. Deren Instanz ist so beschaffen, dass Methoden zur Entgegennahme des Request einschließlich aller gesendeten Request-Header und Parameter zur Verfügung stehen. Wobei unabhängig vom gesendeten Content-Type die Instanz im Regelfall stets dieselben Methoden verwendet zum Parsen der Parameter.

Aufgrunddessen, dass der Programmablauf immer wieder derselbe ist, definiert die Basiklasse main ein Interface und die von der Basisklasse abgeleiteten Subklassen führen die Methoden des Interface aus: Nacheinander in einer festgelegten Reihenfolge. Verzweigungen ergeben sich, wenn der Benutzer der Webanwendung aktiv wird.

Literatur

Eric Foster-Johnson, Perl Module. ISBN 3-8266-0570-5


Die rein persönlichen Zwecken dienende Seite verwendet funktionsbedingt einen Session-Cookie. Datenschutzerklärung: Auf den für diese Domäne installierten Seiten werden grundsätzlich keine personenbezogenen Daten erhoben. Das Loggen der Zugriffe mit Ihrer Remote Adresse erfolgt beim Provider soweit das technisch erforderlich ist. @: Rolf Rost, Am Stadtgaben 27, 55276 Oppenheim, nmq​rstx-18­@yahoo.de