An dieser Stelle möchte ich mich bei meinen Eltern und allen bedanken, die mich bis hierhin unterstützt haben. Ein besonderer Dank gebührt meinen Betreuern Professor Dr. Thomas Preuß und Mark Rambow, die mich bei der Entstehung dieser Diplomarbeit begleitet haben.
Weiterhin bedanke ich mich bei Christine Porath für ihre moralische Unterstützung und hilfreiche grammatikalische Tipps, Bernd Lehmann für die Bereitstellung eines Test- servers sowie einigen Kommilitonen für aufschlussreiche, fachliche Diskussionen.
iii
Inhaltsverzeichnis
1 Einleitung 1
2 Grundlagen 3
2.1 Programmierparadigmen. 4
2.1.1 Prozedurale Programmierung. 4
2.1.2 Objektorientierte Programmierung 6
2.1.3 Aspektorientierte Programmierung 11
2.1.4 Generative Programmierung 12
2.1.5 Übersicht 15
2.2 Architekturmuster. 16
2.2.1 MDA. 17
2.2.2 MVC. 19
2.2.3 PAC 22
2.3 Frameworks 25
2.3.1 Prado. 26
2.3.2 Symfony 30
2.3.3 Zend Framework 33
2.3.4 Fehleranalyse. 35
2.3.5 Zusammenfassung. 36
3 Individualsoftware 38
3.1 Performance versus Flexibilität. 39
3.2 Generierung. 47
3.3 Tests 58
3.3.1 Testverfahren. 58
3.3.2 Integrationstests auf der Zielplattform 67
3.3.3 Selbsttests nach Generierung 68
3.4 Anpassung 70
3.4.1 Anpassbarkeit bei Installation 70
3.4.2 Anpassbarkeit im Betrieb 72
3.4.3 Architekturmuster. 75
3.5 Aktualisierung 80
3.6 Praktischer Nachweis 85
3.6.1 Projekt ConfMaster 85
3.6.2 Generierung. 86
3.6.3 Performancevergleich. 88
4 Zusammenfassung. 95
5 Ausblick. 97
6 Literaturverzeichnis. 99
7 Abbildungsverzeichnis 103
8 Tabellenverzeichnis. 104
9 Listingverzeichnis. 105
Anhang I
A. Glossar. I
B Tabellarische Testergebnisdarstellung 6
1 Einleitung 1
1 Einleitung
Nachdem die Entwicklung der Computer- und Softwaresysteme in der zweiten Hälfte des letzten Jahrhunderts zunehmend komplexer wurden, fing man an, nach Mitteln und Wegen zu suchen, um die zunehmend weiter steigende Komplexität beherrschbar zu machen. Um 1970 wurde für dieses Problem der Begriff Softwarekrise [Dij72] geprägt. Seit dem kamen neue Technologien und Anforderungen hinzu und die Computertechnik drang in immer mehr Bereiche des täglichen Lebens vor. Das Internet verbreitete sich in exponentieller Geschwindigkeit und mit ihm eine Flut von kommunikativen Möglichkeiten und Technologien. Gleichzeitig stieg die Komplexität der benötigten Software mit der Folge, dass die Softwarekrise weiterhin bestand hat. Um die steigende Komplexität der benötigten Software beherrschen zu können, wurde Software-Engineering eingeführt, welches sich mit „[…] Prinzipien, Methoden und Werkzeugen“ ([Bal96] S.36) der Softwareentwicklung beschäftigt. Seit einiger Zeit ist ein vermehrter Bedarf nach entfernt nutzbarer Software zu verzeichnen. Dabei wird der Webbrowser immer mehr als Universalausgabe für jede Art entfernt verwendeter Software verwendet.
Diese Arbeit befasst sich mit der Entwicklung und Wartung webbasierter, individualisier- und anpassbarer Applikationen. Vorhandene Methoden und Werkzeuge werden untersucht, evaluiert und Lösungen dargestellt. Dabei liegt der Schwerpunkt auf flexibler und effizienter Applikationsgenerierung unter Verwendung prozeduraler und ob-jektorientierter sowie generativer Ansätze und Methoden. Die Arbeit stellt keine Dokumentation eines klassischen Software Engineering Projektes dar. Vielmehr werden Methoden dargestellt und auf ihre Anwendbarkeit hin untersucht, wobei das Gewicht auf Flexibilität bei hoher Performance gelegt wird. Am Schluss der Arbeit wird ein Teil der theoretischen Lösungen praktisch anhand der Anforderungen einer bestehenden Applikation durch eine beispielhafte Implementierung und den Vergleich mit dieser auf Effektivität und Effizienz geprüft.
1 Einleitung 2
Zur Verdeutlichung der beschriebenen Methoden und Vorgehensweisen werden kurze, in der Skriptsprache PHP geschriebene Implementierungsbeispiele angeführt. Diese sind sehr einfach gehalten und dienen ausschließlich einer besseren Verständlichkeit. Die Verwendung von PHP ist damit begründet, dass diese Skriptsprache in der aktuellen Version 5 objektorientierte und prozedurale Programmierung gleichermaßen unterstützt und sich daher gut für Demonstrationszwecke eignet sowie stark im Webumfeld verbreitet ist. Ein kompletter Wechsel zu einer anderen Programmier-sprache wird dadurch vermieden. Des Weiteren wird der Quelltext interpretiert und bedarf keiner Kompilierung. Dieser Umstand ermöglicht Vorgehensweisen, die ansonsten nicht ohne Einschränkungen oder zusätzliche Bedingungen möglich wären. Um deutlicher auf ob-jektorientierten oder prozeduralen Quelltext hinzuweisen wird die Version 5 bzw. 4 angegeben.
Die große Popularität und die einfache Erlernbarkeit der Sprache hat in den letzten Jahren dazu geführt, dass sehr viele Menschen ohne fundierte Programmierkenntnisse, Hintergrundwissen zu sicherheitsrelevanten Themen sowie zur Qualitätssicherung in PHP programmiert haben. Die Ergebnisse ihrer Bemühungen wurden frei zugänglich ins Web gestellt. Die Folge war, dass eine große Anzahl von Hackern die Möglichkeit hatte, Angriffe auf solche Systeme zu starten und durch mangelndes Fachwissen der Programmierer entstandene Schwachstellen zu finden. Dadurch ist das Bild von der unsicheren Programmiersprache PHP in der Öffentlichkeit entstanden, wogegen jedoch die sehr große, weltweite Verbreitung, Offenheit der Quellen sowie die Verwendung für große Projekte wie das CMS 1 Typo3 spricht.
Die konsequente Verwendung dieser Programmiersprache legt den Entschluss nahe, bei dem Einsatz weiterer Software ebenfalls frei verfügbare Open Source 2 Software zu be-vorzugen.
1 CMS ist die Abkürzung für Content Management System. Mit solchen Systemen lassen sich digitale
Inhalte verwalten und pflegen.
2 Open Source bezeichnet Software, deren Quellen frei verfügbar sind. Je nach verwendeter Lizenz kann
der Quelltext für eigene Zwecke modifiziert, kostenlos weitergegeben und in eigene Anwendungen in-
tegriert werden.
2 Grundlagen 3
2 Grundlagen
Dieses Kapitel befasst sich mit den Grundlagen der Webentwicklung. Anfangs wird auf Programmierparadigmen eingegangen, deren Eigenschaften wesentlich die anwendbaren Methoden für den Entwurf und die Realisierung von Software beeinflussen. Folgend werden ein Vorgehensmodell und zwei Architekturmuster besprochen. Anschließend werden drei Frameworks beschriebenen und evaluiert, welche auf einigen der vorhergehenden Grundlagen aufbauen und Einblicke in die Verwendung einiger besprochener Grundlagen geben.
Die fachliche Tiefe der Darstellung einzelner Grundlagen variiert in Abhängigkeit von der Bedeutung für den aktuellen Stand der Softwareentwicklung und den Hauptteil dieser Arbeit. So wird objektorientierte und generative Programmierung sowie das MVC- Muster stärker gewichtet.
2.1 Programmierparadigmen 4
2.1 Programmierparadigmen
In diesem Kapitel werden die Kerneigenschaften von vier Programmierparadigmen besprochen. Sie bilden die Grundlage für alle weiteren Betrachtungen und Überlegungen. Neben der weit verbreiteten prozeduralen und objektorientierten Programmierung wird noch auf weitere Paradigmen, die auf diesen aufbauen und sie ergänzen, eingegangen.
2.1.1 Prozedurale Programmierung
Der Fokus prozeduraler Programmiersprachen liegt auf der Umsetzung von Algorithmen (vgl. [Vo04]). Wie Maschinensprachen ermöglichen sie weiterhin eine plattformnahe Programmierung bei optimaler Ausnutzung der Hardware. In solchen Sprachen geschriebene Programme werden vor der Ausführung durch einen Compiler in den Maschinencode übersetzt oder durch Interpreter interpretiert. Prozedurale Programmiersprachen sind, wie alle höheren Programmiersprachen, „[…] am menschlichen Verständnis und an der Struktur der zu bearbeitenden Aufgaben orientiert“ ([Vo04] S.230). Die enthaltenen Sprachkonstrukte abstrahieren, im Vergleich zu Maschinensprachen, stärker von der Plattform, wobei der Abstraktions-grad je nach Programmiersprache variiert.
Der Kern des Paradigmas liegt darin, ein Problem in Teilprobleme aufzuteilen. Sie werden als Prozeduren implementiert, welche in Abhängigkeit von den übergebenen Parametern das Teilproblem oder eine Menge von Teilproblemen lösen können. In der aufrufenden Hauptprozedur kann der Unterprozeduraufruf beliebig platziert werden und mehrfach vorkommen. Die Kontrolle wird nach einem Aufruf an die Unterprozedur abgegeben. Wie in Abbildung 2.1-1 dargestellt, wird diese nach dem Ende der Unterprozedur wieder an die Hauptprozedur zurückgeben, die ggf. mit den Rückgabewerten der aufgerufenen Prozedur weiterarbeitet. Diese Aufgabenteilung ermöglicht eine fle- xible Programmierweise und fördert die Code-Wiederverwertung (vgl. [Vo04]).
2.1 Programmierparadigmen 5
Abbildung 2.1-1: Prozedurale Programmierung
Das folgende Codebeispiel stellt einige Elemente prozeduraler Programmiersprachen, am Beispiel von PHP 4, da.
Listing 2.1-1: Prozedurale Programmierung
Die Vorteile dieses Programmierparadigmas sind, verglichen mit Maschinen- und Assemblersprachen, einfachere Problemzerlegung, höherer Abstraktionsgrad sowie besse- re Unterstützung der Codewiederverwendung.
2.1 Programmierparadigmen 6
2.1.2 Objektorientierte Programmierung
Die objektorientierte Programmierung erfordert ein, in Bezug auf prozedurale Programmierung, grundlegendes Umdenken des Programmierers. Der Fokus des Paradigmas liegt auf der Manipulation von Daten (vgl. [Vo04]).
Das Paradigma sieht vor, das Problem ebenfalls in Teilprobleme aufzuteilen, wobei in vielen objektorientierten Programmiersprachen ähnliche oder gleiche Sprachkonstrukte, wie bei prozeduralen Programmiersprachen, vorhanden sind. Darüber hinaus werden Gruppen aus Lösungen dieser Teilprobleme und benötigten Variablen gebildet. Diese Gruppen werden als Klassen bezeichnet, ihre Teile als Methoden dieser Klassen. Durch die Bildung von Objekten werden Klassen instanziert. Diese Instanzen sind komplexe Datenstrukturen, die Referenzen auf die Methoden der Klasse sowie auf den Speicherbereich für Objektvariablen enthalten, wie es in der Abbildung 2.1-2 dargestellt ist. Über spezielle Methoden, sog. Konstruktoren, können diese Objektvariablen initialisiert und ggf. weitere Methoden aufgerufen werden. Ausnahmen hiervon bilden Klassenmethoden und -variablen, welche Bestandteile der Klasse selbst sind und nicht instanziert werden. Sie ermöglichen eine, der prozeduralen Programmierung ähnliche Programmierweise.
Abbildung 2.1-2: Objektorientierte Programmierung
Über Zugriffsrechte, auch als Sichtbarkeit bezeichnet, wird der Zugriff durch andere Klassen auf die Methoden und Daten gesteuert. So können differenziert Zugriffe erlaubt oder verboten werden, wodurch sich die Möglichkeiten der Datenmanipulation ein-
2.1 Programmierparadigmen 7
schränken lassen. Dieses Prinzip wird als Geheimnisprinzip bezeichnet. Dadurch ist es möglich, an wenigen bekannten Stellen Änderungen der Variablenwerte zu beobachten und Fehler aufzuspüren, was zu mehr Übersicht und robusterem Code führt. Das folgende Listing 2-2 stellt einige Grundkonzepte und Elemente objektorientierter Programmiersprachen, am Beispiel von PHP 5, da.
Listing 2.1-2: Objektorientierte Programmierung
Ein weiteres wichtiges Merkmal ist die Vererbung. Klassen können ihre Eigenschaften von anderen Klassen ableiten und enthalten somit implizit die Methoden und Variablen der Elternklasse. Diese müssen nicht noch einmal in der Kindklasse explizit deklariert werden. Diese Beziehung wird als Generalisierungsbeziehung bezeichnet. Dabei ist die Elternklasse in diesem Fall eine Generalisierung der Kindklasse. Die Kindklasse kann die Elternklasse durch eigene Methoden erweitern, sie spezialisiert also die Elternklasse. Das ist auch der Grund dafür, warum sie als Spezialisierung der Elternklasse be- zeichnet wird. Die Zugriffsrechte spielen hierbei ebenfalls eine Rolle, da in den Eltern-
2.1 Programmierparadigmen 8
klassen festgelegt werden kann, welche Methoden über eine oder mehrere Generationen vererbt werden dürfen.
Durch das Vererbungskonzept wird die Code- Wiederverwendung im hohen Maße gefördert. Der Programmierer hat nun die Möglichkeit, neue Klassen zu erstellen und nur noch die Unterschiede zu der Klasse, welche beerbt wird, zu implementieren. Es können gleich benannte Methoden in verschiedenen Klassen unterschiedliche Funktionalitäten aufweisen. Dieses, als Überladen von Methoden bekannte Vorgehen, bietet eine Reihe von Vorteilen. So können z.B. mehrere gleichnamige Methoden durch Unterschiede in der Parameterliste (Signatur) eine ähnliche oder spezialisierte Funktionalität enthalten.
Die folgende Abbildung 2.1-3 stellt eine Vererbungshierarchie über zwei Generationen da.
Abbildung 2.1-3: UML 1 Darstellung einer Vererbung über zwei Generationen.
Das folgende Listing 2.1-3 demonstriert die Nutzung der Vererbung und Polymorphie.
1 Unified Modeling Language, einer Beschreibungs- und Darstellungssprache für das objektorientierte
Design.
2.1 Programmierparadigmen 9
Listing 2.1-3: Vererbung und Polymorphie
Eine Objektvariable kann zur Laufzeit auf unterschiedliche Objekte verweisen. Diese Eigenschaft wird als Polymorphie, die Variablen als polymorph, bezeichnet. Polymorphe Variablen werden in statische und dynamische Typen unterteilt. Wie im oberen Listing 2.1-3 zu sehen, ist die Objektvariable „obj“ zunächst als vom Typ Haus statisch deklariert. Zur Laufzeit ändert sich die Ausprägung und die Objektvariable verweist auf die Klasse Wohnhaus. Dabei wird eine dynamische Deklaration vorgenommen und die Klasse Wohnhaus nicht vor der Bezeichnung der Variable angegeben (vgl. [Vo04]). Abstrakte Klassen sind ein weiteres Merkmal objektorientierter Programmiersprachen. Eine Klasse gilt als abstakt, wenn diese ausschließlich oder partiell Methodenprototypen mit allen benötigten Argumenten, jedoch keine konkrete Implementierung dieser und keine Variablen, sondern nur Klassenkonstanten enthält. Komplett abstrakte Klassen werden auch, in einer ähnlichen Form, als Interfaces bezeichnet. Die Implementierung einer abstrakten Klasse bzw. Interface erfolgt unter Verweis auf die jeweilige abstrakte Klasse bzw. Interface in einer separaten Klasse (vgl. [Vo04]). Beispielsweise werden diese Konstrukte verwendet, wenn mehrere Programmierer in einem Team zusammenarbeiten. Auf diese Art weiß z.B. Programmierer A, welche Methoden mit Signaturen und Rückgabewerten in der Klasse von Programmierer B vorhanden sind, noch bevor diese konkret implementiert wurden. Mithilfe von sog. Stub 2 , Dummy 3 oder Mock-Objekten 4 kann das Verhalten der konkreten Implementie-
2 „EinStub (dt. Stummel) ist ein bislang nur rudimentär implementierter Teil der Software, der später
durch die richtige Implementierung ersetzt werden soll. Die Aufgabe eines Stub-Objekts ist die eines
Platzhalters für geplante, aber noch nicht umgesetzte Funktionalität“ ([Li02] S. 92).
3 „Ein Dummy (dt. Attrappe, Schaufensterpuppe) […] kann die echte Implementierung für Testwerkzeu-
ge ersetzen“ ([Li02] S. 92).
2.1 Programmierparadigmen 10
rung simuliert und getestet werden (vgl. [Li02]). Programmierer A kann diese Methoden also aus seinem Code heraus verwenden, ohne die konkrete Implementierung dieser kennen oder auf das Tempo von B Rücksicht nehmen zu müssen. Die konkrete Implementierung der benutzten Interfaces kann sich im Laufe der Zeit ändern. Dadurch ist es möglich, einzelne Teile des Systems ohne Änderungen am Gesamtsystem auszutauschen. Das ermöglicht z.B. relativ flexible Bugfixes 5 und Anpassungen bei geänderten funktionalen Anforderungen. Geeignete Testverfahren, wie Unit Tests sowie sorgfältige Planung und Kommunikation vermindern das dadurch entstehende Fehlerpotenzial.
Die Konzepte der objektorientierten Programmierung erleichtern und beschleunigen die Entwicklung von Softwaresystemen. Entwicklungstools und Beschreibungssprachen wie UML verschaffen einen schnelleren Überblick. Mehr Flexibilität wird mit weniger Performance erkauft, weil z.B. die gesamte Klasse instanziert und Speicherplatz für Objektvariablen reserviert werden muss, obwohl vielleicht nur eine Methode der Klasse verwendet wird. Die gestiegene Komplexität von Systemen, inklusive Echtzeitsystemen, macht in manchen konkreten Fällen den Einsatz von objektorientierten Sprachen unumgänglich. Diese Lücke wird durch hybride Sprachen, wie C++ geschlossen. In C++ kann sowohl prozedural als auch objektorientiert programmiert werden. Des Weiteren bietet C++ aufgrund von z.B. direkten Registermanipulationen (Zeigervariablen) weniger Plattformabstraktion als andere objektorientierte Sprachen wie Java. Mehr Hardwarenähe erlaubt eine bessere Feinabstimmung des Systems und damit ggf. per-formantere Gesamtsysteme.
4 Mock bedeutet aus dem Englischen übersetzt soviel wie Schein-, Pseudo-, Attrappe und bezeichnet ein
Pseudo-Objekt, welcher eine Simulation des konkreten Objekts für Testzwecke darstellt. „Ein Mock
[…] unterscheidet sich vom Dummy durch zusätzliche Funktionalität: Ein Mock-Objekt erlaubt, falls
nötig, die Einstellung der von ihm gewünschten Reaktionen und das Verifizieren des Korrekten Ver-
haltens seines ‚Klienten’“ ([Li02] S. 92).
5 Als Bugfix wird eine Korrektur im Quellcode bezeichnet. Der fehlerhafte Codeteil wird ersetzt.
2.1 Programmierparadigmen 11
2.1.3 Aspektorientierte Programmierung
Aspektorientierte Programmierung ist ein noch junges und ergänzendes Programmierparadigma, welches sowohl bei der prozeduralen als auch bei der objektorientierten Programmierung angewendet werden kann.
Software kann vereinfacht in zwei grundsätzliche Bereiche unterteilt werden: Kern-oder funktionale Anforderungen (engl. Core-Level-Concerns) und technische Randbedingungen (engl. System-Level-Concerns). Ersteres kann gut in Funktionen oder Methoden und Klassen gekapselt werden, Letzteres jedoch nicht. Die „verwobenen“ Kombinationen Beider schneiden durch alle Systemschichten (Crosscutting-Concerns) (vgl. [PA06]).
„Anschaulich kann man sich das Prinzip wie folgt vorstellen: ein Programm, gleichgültig ob
prozedural oder objektorientiert, folgt einem Programmablaufplan, d. h. der Programmfluss ist
an jeder Stelle durch lineare Folgen von Anweisungen (Codeblöcke) und Sprünge zwischen die-
sen (z. B. Methodenaufrufe) festgelegt. Ein Aspekt wäre hier soviel wie eine Schablone, die über
diesen Originalplan gelegt wird und verschiedene Änderungen oder Ergänzungen am Ablauf-
schema vornimmt. Änderungen an der Schablone lassen den Originalplan unangetastet, die
Schablone lässt sich jederzeit austauschen, mit anderen kombinieren oder wieder entfernen.“
[WP06]
So wird z.B. Logging beim Debugging in alle Methoden einer Klasse eingesetzt, um Schwachstellen zu finden. Wenn der Programmierer alle Methodenaufrufe temporär protokollieren möchte, bedeutet dies, dass er gezwungen ist, diesen Aspekt des Loggings, also den Methodenaufruf der Loggermethode, in jede Methode einzuprogrammieren und diese nach dem Debugging wieder zu entfernen. Um diese Arbeit zu automatisieren, kann auf aspektorientierte Programmierung zurückgegriffen werden (vgl. [La03]).
Für die Automatisierung müssen einige Punkte definiert werden. Mit dem Join Point wird ein Aufrufereignis definiert, welches die Stelle bezeichnet, an die der Aspekt eingewoben wird, z.B. wie in der Abbildung 2.1-4 das Betreten und Verlassen einer oder mehrerer Methoden. Nachdem das Aufrufereignis definiert wurde, muss der auszuführende Code angegeben werden, was als Pointcut bezeichnet wird. In einem Pointcut kann z.B. der Methodenaufruf des Loggers stehen. Das kann nun auf alle Methoden einer Klasse angewandt werden. Die Beschreibung dieser Definitionen ähnelt anderen Methoden einer Klasse mit einer festgelegten Syntax und entsprechenden Schlüssel-
2.1 Programmierparadigmen 12
wörtern. Per Precompiler 6 wird der Code im Pointcut an alle im Join Point definierten Stellen geschrieben und durch Compiler oder Interpreter zur Laufzeit mit den Klassen verwoben. (vgl. [CzEi04], [PA06], [WP06]).
Abbildung 2.1-4: Aspektorientierte Programmierung nach [WP06]
Durch Aspekte kann aber das Verhalten von Methoden verändert werden. Pointcuts können beliebigen Code enthalten, also auch Aufrufe der Set und Get Methoden der Klasse, was zu Änderungen der Variablenwerte führt (vgl.[CzEi04]).
2.1.4 Generative Programmierung
Die generative Programmierung beschäftigt sich mit der Generierung angepasster Software aus der Codebibliothek einer Softwarefamilie. Es werden keine Einzelapplikationen, sondern die Codebibliothek sowie das Generatorsystem 7 selbst entwickelt. Die Codebibliothek (Bibliotheksdaten) beinhaltet eine Menge von Codeteilen, aus denen nach Kundenwunsch eine angepasste Applikation automatisch, durch einen Gene-
6 EinPrecompiler bearbeitet den Code vor der eigentlichen Übersetzung durch einen Compiler.
7 Ein Generator (lat. Erzeuger) ist eine ausführ- oder interpretierbare Applikation, welche eingaben- und
regelabhängig Code erzeugt.
2.1 Programmierparadigmen 13
rator, generiert werden kann. Die Codebibliothek ist dabei domain-spezifisch 8 . Sie enthält Codeteile, welche allgemeine und spezielle Anforderungen an eine Gruppe von Anwendungen erfüllen. Diese Gruppe (engl. Domain) kann z.B. Businesswebsite, Webshop oder Blog sein.
Das Ziel ist die Erstellung angepasster Applikationen mit minimalem Aufwand. Das Erreichen dieses Ziels wird durch generative Programmierung mehrfach begünstigt. Durch die Generierung aus bestehenden elementaren Komponenten wird der Program-mieraufwand sowie der damit verbundene Testaufwand reduziert, sofern die Komponenten bei der Generierung nicht verändert werden.
Abbildung 2.1-5: Elementenschema des generativen Domänenmodells nach [CzEi04]
Wie in der Abbildung 2.1-5 dargestellt, besteht das generative Domänenmodell aus einem Problemraum, in dem das Problem mit domänenspezifischen Begriffen in Form einer geeigneten DSL 9 beschrieben wird. Diese Beschreibung wird zusammen mit dem Konfigurationswissen (Konfigurationsdaten) des Generators von diesem dazu verwendet, um elementare Komponenten aus dem Lösungsraum zu konfigurieren und zu einer Applikation zu kombinieren. Das Paradigma wird z.B. für die Transformation in der Model Driven Architecture (siehe Kap. 2.2.2) verwendet, wobei das jeweilige Modell als DSL verwendet wird.
8 Eine Softwarefamilie wird als Domain bezeichnet.
9 Domain-Specific Language, Beschreibungssprache für eine bestimmte Softwarefamilie (Domain). Sie
ist nur innerhalb der Grenzen der Softwarefamilie gültig und anwendbar.
2.1 Programmierparadigmen 14
Der Generator überprüft bei der Erstellung alle Inkompatibilitäten und Abhängigkeiten. So können z.B. nicht zwei verschiedene Anzeigen denselben Anzeigebereich verwenden, wenn beide gleichzeitig zu sehen sein sollen. Wenn außerdem ein Teil eines Systems auf einem anderen aufbaut oder diesen verwendet, d.h. von diesem abhängig ist, so müssen beide Teile im System vorhanden sein. Danach werden diese Probleme aufgelöst. Die Art und Weise, wie der Generator dieses Auflösen bewältigt, wird durch dessen Programmierung, interne Regeln und die DSL-Beschreibung festgelegt. Anschließend wird der eigentliche Code generiert (vgl. [CzEi04]). Der generierte Code ist nicht zwangsläufig ausführbar. Es kann sich genauso um Zwischencode, interpretierbaren Code, eine weitere DSL-Beschreibung für eine andere Domäne, eine spezielle Formatierung der ausgegebenen Informationen oder menschenlesbare Dokumentation handeln.
Der Generator muss in der Lage sein, ausführliche Kompatibilitätstests der einzelnen Bestandteile durchzuführen, um entstehende Probleme bewältigen zu können. Sollten Probleme auftreten, die nicht automatisch gelöst werden können, wird eine manuelle Lösung notwendig. Der dabei anfallende Aufwand kann auch für die Weiterentwicklung des Generators verwendet werden.
Um aufgetretene, aber nicht automatisch erkannte Fehler zu entdecken, können abschließende Tests des generierten Gesamtsystems erfolgen. Weiterhin können Fehler im Generator selbst dazu führen, dass augenscheinlich fehlerfreie Software generiert wird, welche jedoch fehlerhaft ist. Die Tests können dabei statischen und dynamischen Typs sein sowie teilweise automatisiert werden (vgl. 3.3).
Sollten Fehler auftreten, so wird die Codebasis überarbeitet, die Anwendung in der Regel neu generiert und ein Bugfix oder Patch 10 herausgegeben. Der Generator arbeitet konsequent, entweder konsequent richtig oder konsequent falsch, sofern das Generatorsystem selbst fehlerfrei ist. Alle bis zu diesem Zeitpunkt generierten Applikationen, die mit diesem fehlerhaften Codeteil generiert wurden, enthalten zwangsläufig denselben Fehler. Da dieser Fehler in einer großen Anzahl von Applikationen vorkommt, werden die Auswirkungen nach kurzer Zeit festgestellt. Ein Bugfix beseitigt dann das Vor-
10 Ein Patch (dt. Flicken) ersetzt eine oder mehrere (fehlerhafte) Dateien einer Applikation.
2.1 Programmierparadigmen 15
kommen des Fehlers sowohl in bisherigen, als auch in zukünftig generierten Applikationen.
Bei vielen ähnlichen Applikationen, die zu einer Domain zusammengefasst werden können, führt dieses Paradigma zu erheblicher Zeitersparnis. Die Entwicklung der Codebibliothek und des Generators nimmt zwar eine nicht geringe Menge Zeit in Anspruch, dieser Code kann aber dann für eine große Menge an Applikationen genutzt werden. Bleibt das Verhältnis zwischen Aufwand und Nutzen gewahrt, so ist der anfangs benötigte Aufwand gerechtfertigt (vgl. [CzEi04]).
2.1.5 Übersicht
Zusammenfassend lassen sich die Kerneigenschaften der einzelnen Paradigmen in einer Tabelle darstellen.
Tabelle 2.1-1: Kerneigenschaften der Programmierparadigmen
Prozedurale Pro-grammierung
Objektorientierte
Programmierung
Aspektorientierte
Programmierung
Generative Pro-
grammierung
2.2 Architekturmuster 16
2.2 Architekturmuster
Die zuvor beschriebenen Programmierparadigmen liefern die Antwort auf die Frage, welche Mittel zur Kodierung der Problemlösung angewendet werden können. Softwarearchitektur (engl. Software Architecture), Architekturmuster (engl. Architecture Pattern) und Entwurfsmuster (engl. Design Pattern) bestimmen die Struktur einer Software maßgeblich. Diese beantworten die Frage nach möglichen Strukturen für den Aufbau der Software.
Eine Softwarearchitektur beschreibt den Aufbau der Software und das Zusammenwirken der einzelnen Teile (vgl. [PoBiGe04], [St02]). Das Modell einer bestimmten Softwarearchitektur, also ein Architekturexemplar (vgl. [HoRe02]) ist in der Regel an eine bestimmte Software gebunden und kann meistens nur für die Strukturierung dieser oder ähnlicher Software verwendet werden.
Das zugrunde liegende Architekturmuster lässt sich auch auf unterschiedliche Architekturmodelle anwenden. Beispielsweise stellt die Strukturierung einer Software in mehrere grobe, funktionale Schichten, wie Model, View, Controller (vgl. 2.2.2 MVC), ein Architekturmuster da.
Jedes Architekturmuster besteht aus Entwurfsmustern. Sie werden mehrfach angewendet und beschreiben den Aufbau der einzelnen Teile. Entwurfsmuster sind nicht an eine bestimmte Software gebunden und können für die Strukturierung von Bestandteilen anderer Software wieder verwendet werden (vgl. [St02]). Beispielsweise kann ein Modul in mehreren Schichten strukturiert sein und bei Bedarf in unterschiedlichen Softwaresystemen zum Einsatz kommen.
Einer Architektur können eines oder mehrere Architekturmuster zugrunde liegen. Ein Architekturmuster kann wiederum aus einem oder mehreren Entwurfsmuster bestehen. Dieses Verhältnis wird in der Abbildung 2.2-1 dargestellt. Die mögliche Einsatzflexibilität verhält sich umgekehrt proportional zu dieser Hierarchie. Ein Entwurfsmuster kann demnach in verschiedensten Systemen zum Einsatz kommen, sofern es dienlich ist.
2.2 Architekturmuster 17
Abbildung 2.2-1: Verhältnis zwischen Architektur, Architekturmuster und Entwurfsmuster
Zum Einstieg wird auf die Modellgetriebene Architektur (MDA) eingegangen. Es ist kein Architekturmuster im eigentlichem Sinn, sondern ein Vorgehensmodell zur Erstellung von Architekturmodellen. Anschließend wird auf das weit verbreitete MVC-Muster, welches auch für die Strukturierung von kompletten Architekturen verwendet wird und das weniger bekannte PAC-Muster eingegangen.
2.2.1 MDA
Die Model Driven Architecture (MDA) 13 wurde eingeführt, um „[…] die reguläre Entwicklung von Applikationen nicht zu sehr von der Entwicklung der Architekturen zu entkoppeln“ ([Ma05] S. 249). Die Plattformunabhängigkeit der Architekturen soll in den Applikationen erhalten bleiben.
Innerhalb des Modells sind 3 Bestandteile definiert: Computation Independendent Model (CIM), Platform Independent Model (PIM) und Platform Specific Model (PSM). Diese Bestandteile stellen Sichten auf das Gesamtsystem da und haben verschiedene Abstraktionsgrade. Das CIM ist die Sicht mit dem höchsten Abstraktionsgrad. In ihr wird das System völlig unabhängig von der möglichen Zielplattform, dessen Möglichkeiten und der Realisierbarkeit des Systems dargestellt. Es dürfen keinerlei Details der Implementierung auftauchen, damit der Abstraktionsgrad erhalten bleibt. Ein CIM „[…]stellt im traditionellem Sinne die Fachspezifikation dar“ ([Ma05] S. 252).
13 MDA wurde von der Object Management Group (vgl. [OMG06]) als Vorgehensmodell definiert
2.2 Architekturmuster 18
Das PIM ist weit weniger abstrakt und enthält ebenfalls keinerlei Plattformspezifikationen. Auf dieser Abstraktionsebene kann das Zielsystem als eine virtuelle Maschine angesehen werden, die bestimmte definierte Eigenschaften hat. So können die Eigenschaften z.B. aus der Schnittmenge der Eigenschaften aller in Frage kommender Zielplatt-formen abgeleitet werden. Unter dieser Annahme kann eine Implementierung des Systems erfolgen, welche konkrete Problemlösungen enthält, jedoch einen hohen Abstraktionsgrad der Hardware besitzt.
Das PSM enthält die eigentliche Implementierung, also auch sämtliche Details, welche für diese notwendig sind. Teile des PIMs werden in ausführbaren Code transformiert. Dieser Code ist plattformspezifisch und kann in der Regel nicht auf anderen Plattformen verwendet werden. Diese Transformation kann manuell, computergestützt oder komplett automatisiert ablaufen (vgl. [PoBiGe04]).
Wie in der Abbildung 2.2-2 dargestellt, besteht das als Transformation bezeichnete Vorgehensmuster aus der wiederholten Anwendung einer auf Regeln basierenden Um-wandlung eines Metamodells in ein Modell (vgl. [OMG06]). Ein Metamodell ist dabei „[…] ein Modell, dass die möglichen Elemente eines Modells definiert […]“([KlKl06] S.149).
Abbildung 2.2-2: Transformation in der MDA nach [Ma05]
Dieses Vorgehensmuster wird auf alle Transformationen angewendet. Die Regeln können bei verschiedenen Transformationen differieren. So ist auch eine Transformation von einem PIM-Modell in ein anderes PIM-Modell möglich, um die Leistungsfähigkeit zu steigern.
2.2 Architekturmuster 19
Damit ein Austausch und Kommunikation zwischen den einzelnen MDA-Modellen möglich ist, müssen sie zueinander kompatibel sein. Die Gesamtheit aller kompatiblen MDA-Modelle lässt sich in einer Meta Object Facility (MOF) beschreiben. Die MOF ist ein standardisiertes und abstraktes Metamodell, welches Elemente, Struktur und Syntax der MDA-Modelle darstellt. Lässt sich ein MDA-Modell mit MOF beschreiben, so entspricht es den Richtlinien und ist zu anderen MDA-Modellen kompatibel (vgl. [OMG06]).
Die Kommunikation zwischen den einzelnen Modellen findet mithilfe des XML Metadata Interchange Standards statt. Dabei werden die Eigenschaften eines MDA-Modells in XML repräsentiert. Die Standards ermöglichen einheitliche Zugriffsmöglichkeiten zur Darstellung und Manipulation der einzelnen Modelle (vgl. [Ma05]).
2.2.2 MVC
Das MVC-Muster 14 ist vergleichsweise einfach und ein oft verwendetes Muster. Es kann auf die komplette Software, im Sinne eines Architekturmusters, und auf alle einzelnen Teile, im Sinne eines Entwurfsmusters, angewendet werden. Dabei ist es nicht an ein Programmierparadigma gebunden. Wegen der aktuellen Dominanz objektorientierter Programmierung wird jedoch im Folgenden dieses Paradigma zur Beschreibung bevorzugt.
MVC beschreibt die Strukturierung der Software in drei Schichten: die Datenmodellschicht (engl. Model), die Präsentationsschicht (engl. View) und die Steuerungsschicht (engl. Controller) (vgl. [PoBiGe04]). Eine einheitliche Definition von MVC existiert allerdings zurzeit nicht. Die Beschreibungen in der Literatur variieren in einigen Punkten. Dessen Schnittmenge ist die Unterteilung des Modells die genannten Schichten und ihre nachfolgend besprochene Funktion, wobei die Interaktionen im konkreten Anwendungsfall abweichen können.
Die Datenmodellschicht enthält alles Notwendige für den Zugriff und die Verwaltung der Daten. Diese Schicht kann einfache Modell-Klassen bis hin zu komplexen Klassen mit Datenquellenabstraktion enthalten.
14 Model View Controller
2.2 Architekturmuster 20
Die Präsentationsschicht beinhaltet für die Darstellung benötigte Klassen und medienspezifische Ausgabedefinitionen. Verschiedene Instanzen (Views) können die Daten in unterschiedlicher Art anzeigen. So kann, z.B. ein Datensatz als Balken- oder Kreisdiagramm angezeigt werden. Die Views registrieren sich bei der Modellschicht und aktualisieren sich selbstständig, sobald sich die Daten ändern diese haben also einen Lesezugriff auf die Modellschicht. Die Gesamtheit aller grafikbasierten Views einer Software stellt, im klassischen Sinne, ein GUI 15 da (vgl. [St02]). Die Steuerungsschicht verwaltet die Interaktionen zwischen den Schichten und hat schreibenden Zugriff auf die Modellschicht. In dieser Schicht sind die Möglichkeiten beschrieben, welche die Views haben, um auf Benutzereingaben zu reagieren. Die nachfolgende Abbildung 2.2-3 stellt die Schichten im MVC-Muster und ihre Interaktionen untereinander dar.
Abbildung 2.2-3: Schichten im MVC-Muster mit Interaktionen nach [TuSaSc01] MVC kann auch auf webbasierte Systeme angewendet werden. In dieser Umgebung müssen die zugrunde liegenden Technologien beachtet werden. Das zustandslose HTTP Protokoll bildet die Kommunikationsgrundlage zwischen Benutzer und System. Dieser Umstand bedarf requestorientierter Systeme, wie es in der Abbildung 2.2-4 dargestellt wird.
15 Graphical User Interface
Arbeit zitieren:
Arthur Kaiser, 2006, Web-Engineering unter besonderer Berücksichtigung von Individualisier- und Anpassbarkeit, München, GRIN Verlag GmbH
Dieser Text kann über folgende URL aufgerufen und zitiert werden:
Einbetten
DOI
SWOT-Analyse für den Einsatz von Open Source Software
Informatik - Wirtschaftsinformatik
Seminararbeit, 29 Seiten
Web Engineering für asynchrone Anwendungen
Informatik - Internet, neue Technologien
Diplomarbeit, 98 Seiten
Arthur Kaiser hat den Text Web-Engineering unter besonderer Berücksichtigung von Individualisier- und Anpassbarkeit veröffentlicht
Arthur Kaiser hat einen neuen Text hochgeladen
Der Schutz bekannter Marken unter besonderer Berücksichtigung der zivi...
Vertrags- und Haftungsfragen u...
Enzo Baiocchi
0 Kommentare