Diplomarbeit Entwicklung eines webbasierten Zeiterfassungssystems mit vergleichender Untersuchung von Datenbanktechniken Eingereicht von Clemens Schweter am Lehrstuhl Softwaretechnik an der Technischen Universität Berlin WS 2003/2004 1. Gutachter: Prof. Dr.-Ing. Stefan Jähnichen 2. Gutachter: Dr. Stephan Herrmann Berlin, Mai 2004 i Eidesstattliche Erklärung Die selbstständige und eigenhändige Anfertigung versichere ich an Eides statt. Berlin, den 27.05.2004 - Clemens Schweter Unterschrift ii Inhaltsverzeichnis 1 Motivation und Einleitung 1.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Die zu lösende Aufgabe . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3 Vorgehensweise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Requirements Engineering 2.1 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Definitionen . . . . . . . . . . . . . . . . . . . . . . . . 2.2.1 Was sind Requirements? . . . . . . . . . . . . . 2.2.2 Definition: Requirement . . . . . . . . . . . . . 2.2.3 Bedingungen an ein Requirement . . . . . . . . 2.2.4 Was ist Requirements Engineering? . . . . . . . 2.3 Das Requirements Document . . . . . . . . . . . . . . 2.3.1 Einleitung . . . . . . . . . . . . . . . . . . . . . 2.3.2 Requirements beschreiben . . . . . . . . . . . . 2.3.3 Systemmodellierung . . . . . . . . . . . . . . . 2.3.4 Struktur des Requirements Documents . . . . . 2.4 Anforderungen erheben (Elicitation) . . . . . . . . . . 2.4.1 Einleitung . . . . . . . . . . . . . . . . . . . . . 2.4.2 Erste Schritte . . . . . . . . . . . . . . . . . . . 2.4.3 System Stakeholder identifizieren und befragen . 2.4.4 Unterstützende Analysetechniken . . . . . . . . 2.5 Anforderungen analysieren und neu verhandeln . . . . 2.5.1 Anforderungen sprachlich überarbeiten . . . . . 2.5.2 Checklisten zur Überprüfung . . . . . . . . . . . 1 1 2 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5 6 6 6 7 7 8 8 8 9 10 10 10 10 10 12 14 14 15 3 Analyse mit Requirements Engineering 3.1 Anforderungen erheben . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.1 Erste Schritte . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.2 Analyse des Ist-Zustandes . . . . . . . . . . . . . . . . . . . 3.1.3 Befragung der Stakeholder mit verschiedenen Techniken . . . 3.1.4 Beschreibung der Stakeholder . . . . . . . . . . . . . . . . . 3.1.5 Unterstützende Analysetechniken . . . . . . . . . . . . . . . 3.2 Analyse der Anforderungen . . . . . . . . . . . . . . . . . . . . . . 3.2.1 Anforderungen sprachlich überarbeiten . . . . . . . . . . . . 3.2.2 Checklisten zur Überprüfung . . . . . . . . . . . . . . . . . . 3.3 Requirements Document . . . . . . . . . . . . . . . . . . . . . . . . 3.3.1 Systemmodelle . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.2 Struktur eines Requirements . . . . . . . . . . . . . . . . . . 3.3.3 Struktur des Requirements Documents nach [IEEE830-1998] 3.4 Abschließende Worte zum Requirements Engineering . . . . . . . . . . . . . . . . . . . . . . 17 17 17 19 20 22 23 24 25 26 27 27 30 30 31 iii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Konzepte von ASP.NET 4.1 Grundlagen . . . . . . . . . . . . . . 4.1.1 3-Tier-Architektur . . . . . . 4.1.2 .NET - Framework . . . . . . 4.1.3 Businessobjekte . . . . . . . . 4.1.4 Die Programmiersprache C# . 4.1.5 ASP.NET Page-Framework . 4.2 Codebehind-Technologie . . . . . . . 4.3 Webforms . . . . . . . . . . . . . . . 4.3.1 Einleitung . . . . . . . . . . . 4.3.2 HTML Server Controls . . . . 4.3.3 Web Server Controls . . . . . 4.4 Zustandsmanagement . . . . . . . . . 4.5 Lebenszyklus eines Page-Objekts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Architektur und Entwurf der Webapplikation 5.1 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Architektur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3 Persistenz-Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3.1 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3.2 Persistenz Manager . . . . . . . . . . . . . . . . . . . . . . . . 5.3.3 Persistente Objekte . . . . . . . . . . . . . . . . . . . . . . . . 5.3.4 Die Klasse Controller . . . . . . . . . . . . . . . . . . . . . . . 5.3.5 Zusammenfassung und Übersicht über alle persistenten Objekte 5.4 Entwurf des Web-Interfaces . . . . . . . . . . . . . . . . . . . . . . . 5.4.1 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4.2 Struktur der GUI . . . . . . . . . . . . . . . . . . . . . . . . . 5.4.3 Problem bei Web-Applikationen . . . . . . . . . . . . . . . . . 5.4.4 Verwendung eines Datagrids . . . . . . . . . . . . . . . . . . . 5.4.5 Entwurf eines User Controls . . . . . . . . . . . . . . . . . . . 5.5 Zustandsmanagement . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.5.1 PageNavigator . . . . . . . . . . . . . . . . . . . . . . . . . . 5.5.2 Start einer Session . . . . . . . . . . . . . . . . . . . . . . . . 5.6 Benutzerrechte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.7 Zusammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.7.1 Gesamtstruktur . . . . . . . . . . . . . . . . . . . . . . . . . . 5.7.2 Beispielhafter Ablauf . . . . . . . . . . . . . . . . . . . . . . . 5.7.3 Schwierigkeiten beim Entwurf . . . . . . . . . . . . . . . . . . 5.7.4 Nebenläufigkeit . . . . . . . . . . . . . . . . . . . . . . . . . . 5.7.5 Übergang zur Implementierung . . . . . . . . . . . . . . . . . iv 34 34 34 34 35 35 37 37 38 38 38 39 40 41 43 43 44 45 45 46 47 49 50 51 51 51 53 54 55 57 57 60 60 61 61 63 64 65 65 6 Implementierung mit relationaler Datenbank 6.1 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2 Datendefinition . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2.1 Datentypen und Domänen . . . . . . . . . . . . . . . . 6.2.2 Primärschlüssel . . . . . . . . . . . . . . . . . . . . . . 6.2.3 Fremdschlüsselverbindungen und referentielle Integrität 6.2.4 Integritätsbedingungen . . . . . . . . . . . . . . . . . . 6.2.5 Trigger . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2.6 Benutzerdefinierte Routinen . . . . . . . . . . . . . . . 6.2.7 Sichten (Views) . . . . . . . . . . . . . . . . . . . . . . 6.2.8 Schwächen der relationalen Datendefinition . . . . . . . 6.3 Datenmanipulation . . . . . . . . . . . . . . . . . . . . . . . . 6.3.1 Datenmanipulationsoperationen . . . . . . . . . . . . . 6.3.2 (SQL-)Transaktionen . . . . . . . . . . . . . . . . . . . 6.3.3 Nebenläufigkeitsanomalien . . . . . . . . . . . . . . . . 6.3.4 Nebenläufigkeitskontrolle . . . . . . . . . . . . . . . . . 6.4 Datenabfragen (Select) . . . . . . . . . . . . . . . . . . . . . . 6.4.1 Select-Statement . . . . . . . . . . . . . . . . . . . . . 6.4.2 Subqueries . . . . . . . . . . . . . . . . . . . . . . . . . 6.4.3 OUTER JOIN . . . . . . . . . . . . . . . . . . . . . . 6.5 Redundanzvermeidung durch Normalisierung . . . . . . . . . . 6.5.1 Begrifflichkeiten . . . . . . . . . . . . . . . . . . . . . . 6.5.2 1. Normalform . . . . . . . . . . . . . . . . . . . . . . . 6.5.3 2. Normalform . . . . . . . . . . . . . . . . . . . . . . . 6.5.4 3. Normalform . . . . . . . . . . . . . . . . . . . . . . . 6.5.5 Boyce-Codd-Normalform (BCNF) . . . . . . . . . . . . 6.6 ODBC-Schnittstelle . . . . . . . . . . . . . . . . . . . . . . . . 6.7 Konkrete Implementierung . . . . . . . . . . . . . . . . . . . . 6.7.1 Verwendete Modellierungstechnik . . . . . . . . . . . . 6.7.2 Entwurf des Datenmodells . . . . . . . . . . . . . . . . 6.7.3 (SQL-)Transaktionen . . . . . . . . . . . . . . . . . . . 6.7.4 Sichten . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.7.5 Primärschlüssel und Identität . . . . . . . . . . . . . . 6.7.6 Referenzielle Integrität . . . . . . . . . . . . . . . . . . 6.8 Motivation zur Objektorientierung in Datenbanken . . . . . . 6.8.1 Vorteile einer relationalen Datenbank . . . . . . . . . . 6.8.2 Nachteile einer relationalen Datenbank . . . . . . . . . 6.8.3 Object-Oriented Database System Manifesto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 67 68 68 68 69 69 70 70 71 71 71 71 72 72 73 74 74 76 77 78 78 79 80 81 82 82 83 83 84 87 89 90 91 92 92 93 95 7 Implementierung mit objektrelationaler Datenbank 7.1 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2 Erweiterte Datendefinition . . . . . . . . . . . . . . . . . . . . . . . . 7.2.1 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 98 99 99 v . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.3 7.4 7.5 7.6 7.2.2 Distinct-Typen . . . . . . . . . . . . . . . . . . . . . . . 7.2.3 Unbenannte Typkonstruktoren . . . . . . . . . . . . . . . 7.2.4 Strukturierte Typen . . . . . . . . . . . . . . . . . . . . 7.2.5 Typisierte Tabellen . . . . . . . . . . . . . . . . . . . . . 7.2.6 Typisierte Sichten . . . . . . . . . . . . . . . . . . . . . . Erweiterte Datenabfragen und -manipulation . . . . . . . . . . . Bewertung nach Datenbankmanifesto . . . . . . . . . . . . . . . 7.4.1 Komplexe Datentypen . . . . . . . . . . . . . . . . . . . 7.4.2 Objektidentität . . . . . . . . . . . . . . . . . . . . . . . 7.4.3 Kapselung . . . . . . . . . . . . . . . . . . . . . . . . . . 7.4.4 Typen- und Klassenhierarchien . . . . . . . . . . . . . . 7.4.5 Vererbung . . . . . . . . . . . . . . . . . . . . . . . . . . 7.4.6 Override, Overload und spätes Binden . . . . . . . . . . 7.4.7 Sprach- und Berechnungsvollständigkeit . . . . . . . . . 7.4.8 Erweiterbarkeit von Typen . . . . . . . . . . . . . . . . . Klassenmodell in objektrelationales Datenmodell transformieren Zusammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Vergleich: relationale und objektrelationale Datenbank 8.1 Relationale Datenbank . . . . . . . . . . . . . . . . . . . 8.1.1 Modellierungsmöglichkeiten und Normalisierung . 8.1.2 Definition von Primärschlüsseln . . . . . . . . . . 8.1.3 Integritätsbedingungen . . . . . . . . . . . . . . . 8.1.4 Abfragemöglichkeiten und Datenmanipulation . . 8.1.5 Nebenläufigkeit und Performanz . . . . . . . . . . 8.2 Verbesserungen durch eine objektrelationale Datenbank? 8.3 Vergleich objektrelational zu relational zusammengefasst 9 Zusammenfassung und Ausblick 9.1 Objektorientierte Datenbank . . . . . . . . . . . 9.2 Persistenz Framework und Datenbankvergleich . 9.3 Entwicklungsprozess . . . . . . . . . . . . . . . 9.4 Zusammenfassung der wichtigsten Erkenntnisse 9.5 Offene Frage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 100 103 105 106 107 108 108 109 109 109 109 109 110 110 110 110 . . . . . . . . 112 . 112 . 112 . 113 . 114 . 114 . 115 . 115 . 116 . . . . . 116 . 116 . 118 . 118 . 119 . 120 Literaturverzeichnis 122 A Requirements Document 126 vi Abbildungsverzeichnis 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 Beispiel für eine Vergleichbarkeit von Fachgruppen . . . . . . . . . . . Gliederung und Vorgehensweise . . . . . . . . . . . . . . . . . . . . . Requirements Engineering Prozess [Som Saw 97, S. 113] . . . . . . . . Erste Befragung des Auftraggebers . . . . . . . . . . . . . . . . . . . Kommunikation zwischen den Stakeholdern . . . . . . . . . . . . . . . Activity Diagram des Ist-Zustandes für die Berichtserstellung . . . . . Zustände eines Projekts . . . . . . . . . . . . . . . . . . . . . . . . . Systemmodell: Klassendiagramm . . . . . . . . . . . . . . . . . . . . Statechart Diagramm für die Menüführung . . . . . . . . . . . . . . . Use Case Modell zur Beschreibung der drei Hauptfunktionalitäten . . Aufbau eines Requirements . . . . . . . . . . . . . . . . . . . . . . . Requirement Dokument nach [IEEE830-1998] . . . . . . . . . . . . . 3-Tier-Architektur für Web-Applikationen . . . . . . . . . . . . . . . Das .NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . Beispiel für die Verwendung von Properties . . . . . . . . . . . . . . . Beispielcode für die Verwendung eines Indexer . . . . . . . . . . . . . Beschreibung der Codebehind-Technologie . . . . . . . . . . . . . . . Zusammenhang von HTML und Server Controls . . . . . . . . . . . . Lebenszykus eines Page-Objekts . . . . . . . . . . . . . . . . . . . . . Struktur der Komponenten . . . . . . . . . . . . . . . . . . . . . . . . Übersicht der spefizischen Komponenten . . . . . . . . . . . . . . . . Struktur des Persistenz Frameworks am Beispiel Projekt . . . . . . . Rollen des Factory Patterns im Persistenz-Framework . . . . . . . . . Einfügen eines persistenten Objektes . . . . . . . . . . . . . . . . . . Die Klasse Controller mit zwei Beispielmanagern . . . . . . . . . . . . Klassendiagramm der persistenten Objekte . . . . . . . . . . . . . . . Seitenaufbau der Default-Webform . . . . . . . . . . . . . . . . . . . Die Webform Default und die Codebehind-Klasse PageFrontdoor . . . Eigenschaften einer Web-Applikation . . . . . . . . . . . . . . . . . . Beispielanwendung für ein Datagrid . . . . . . . . . . . . . . . . . . . Beispiel für ein User Control . . . . . . . . . . . . . . . . . . . . . . . Klasse DateControl . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sequenz Diagramm zum DateControl am Beispiel Mitarbeitereingabemaske . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Beispielklasse des PageNavigators zur Steuerung der Benutzeroberfläche Abhängig vom PageNavigator werden die jeweiligen Templates geladen Beispiel für Zustandsänderung mit PageNavigator . . . . . . . . . . . Sequenz Diagramm für das Starten einer Session . . . . . . . . . . . . Zusammenfassende Darstellung am Beispiel Mitarbeiterverwaltung . . Sequenz Diagramm bei einer Serveranfrage ohne Event . . . . . . . . Sequenz Diagramm bei einer Serveranfrage durch ein Event . . . . . . vii 3 3 5 11 18 19 20 28 29 29 32 33 34 35 36 36 38 39 42 44 45 46 47 48 49 51 52 53 54 54 55 56 56 58 58 59 60 62 63 63 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 Referenzielle Aktionen nach [Tür 03, S. 21] . . . . . . . . . . . . . . . 70 Die ACID-Eigenschaften, die eine Transaktion erfüllen sollte . . . . . 72 Anomalien bei nebenläufigen Transaktionen nach [FO 04b] . . . . . . 73 Einfache Darstellung des SQL-Select-Statements . . . . . . . . . . . . 75 Verbund von zwei SQL-Tabellen . . . . . . . . . . . . . . . . . . . . . 75 SQL-Select-Statement zu dem Beispielverbund von Abbildung 45 . . 75 Ad-hoc-Abfrage über alle Mitarbeiter in einem Projekt in einer ausgewählten Woche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 Definition einer Sicht auf Mitarbeiteraccounts . . . . . . . . . . . . . 76 Beispiel aus der Zeiterfassung für einen Subquery . . . . . . . . . . . 77 Beispiel für outer join . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 Verkürztes Ergebnis der Anfrage aus Abbildung 50 . . . . . . . . . . 78 Grafische Darstellung der 2NF . . . . . . . . . . . . . . . . . . . . . . 81 Grafische Darstellung der 3NF . . . . . . . . . . . . . . . . . . . . . . 81 Grafische Darstellung der BCNF . . . . . . . . . . . . . . . . . . . . . 82 Datenmodell nach der IDEF1X-Notation (siehe Kapitel 6.7.1) . . . . 85 Klasse Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 Beispielanwendung für die Klasse Database ohne Ausnahmebehandlung 89 Sichten aus der Zeiterfassung . . . . . . . . . . . . . . . . . . . . . . 89 Screenshot: Eingabemaske der Vertragsmitarbeiter . . . . . . . . . . . 90 zusammengesetzter Primärschlüssel . . . . . . . . . . . . . . . . . . . 91 Beispiel für referenzielle Intrität zwischen Projekt und Projekttyp . . 92 Vorteile einer relationalen Datenbank . . . . . . . . . . . . . . . . . . 93 Nachteile eines relationalen Datenmodels anhand eines Beispiels . . . 94 Beispiel für Tupeltypkonstruktor . . . . . . . . . . . . . . . . . . . . . 100 Beispiel für Arraytypkonstruktor . . . . . . . . . . . . . . . . . . . . 101 Beispiel für eine SQL-Anfrage auf einem Array . . . . . . . . . . . . . 101 Beispiel für einen Referenztypkonstruktor . . . . . . . . . . . . . . . . 102 Beispiel für die Vorteile von Zugriffen über Referenzen . . . . . . . . 102 Beispiel für 1:n-Relation . . . . . . . . . . . . . . . . . . . . . . . . . 103 Merkmale eines strukturierten Typs (basiert auf [Eis+ 99]) . . . . . . 103 Aufbau eines strukturierten Typs . . . . . . . . . . . . . . . . . . . . 104 Vereinfachter Definitionsaufbau einer typisierten Tabelle . . . . . . . 106 Beispiel für eine typisierte Sicht . . . . . . . . . . . . . . . . . . . . . 107 Zwei Möglichkeiten für Vererbung im ER-Modell . . . . . . . . . . . . 113 Überblick relationale zu objektrelationaler Datenbank . . . . . . . . . 116 Beispiel für eine Implementierung mit objektorientierter Datenbank . 117 Auswirkung einer Anforderungsänderung (vgl. mit Kapitel 9.3) . . . . 121 viii 1 Motivation und Einleitung 1.1 Motivation Obwohl die relationale Datenbank die mit Abstand am weitesten verbreitete Datenbanktechnik ist, hat diese doch viele Nachteile. In der Softwareentwicklung werden objektorientierte Konzepte eingesetzt um Wiederverwendbarkeit durch Vererbung, komplexe Datentypen, usw. zu verwenden und beim Modellieren der Datenbank wird auf flache und einfache Tabellenstrukturen zurückgegriffen. In dieser Arbeit werden die Möglichkeiten einer objektrelationale gegenüber einer relationalen Datenbank verglichen. Grundlage für die objektrelationale Datenbank ist der Standard SQL:19991 . Eine objektrelationale Datenbank ist eine Erweiterung einer relationalen Datenbank und bietet Konzepte an, mit denen Objektorientierung in einer Datenbank möglich ist. Zuvor aber musste ein sehr konkretes Problem gelöst werden. Von der Firma Francotyp Postalia wurde ich beauftragt im Rahmen einer Diplomarbeit ein webbasiertes Zeiterfassungssystem zu entwickeln. Das erste Problem, was sich dabei stellte, war: Was soll das Zeiterfassungssystem können, also die Analyse? In vielen Vorträgen zum Thema UML und anderen Modellierungstechniken wird sofort damit begonnen, das Problem zu modellieren, aber woher kommen die Beschreibungen für die zu lösenden Probleme? Vor allem, wenn es sich um ein Projekt in einer ”echten” Firma handelt, sind die Anforderungen oft nicht von vornherein so klar. Durch Requirements Engineering soll genau diese Frage beantwortet werden: ”Was genau soll entwickelt werden?” Für die Entwicklung der Applikation wurde das .NET Framework verwendet. Eine der Komponenten dieses Frameworks ist ASP.NET. ASP.NET ist eine Technik, mit der Web-Applikationen entworfen werden können, die ein etwas anderes Vorgehen besitzt, als es bei der Entwicklung von herkömmlichen Web-Applikationen der Fall ist. Ein weiterer Ansatz, um die Unterschiede zwischen objektorientierter Programmierung und relationaler Datenbank zu verringern, ist die Verwendung eines MappingTools, wie in [Scr+ 97] unter dem Begriff ”gateway-based object persistence” beschrieben ist. Bei einem Mapping-Tool wird eine automatische Umwandlung von Klassenstrukturen zu relationalen Datenstrukturen vorgenommen. Basierend auf diesem Konzept und der Struktur eines bereits existierenden Persistenz-Framework, wurde eine Framework entworfen, was einen direkten Vergleich der Datenbanktechniken ermöglichen soll. 1 SQL:1999 ist der offizielle Namen und ist gleichbedeutend mit SQL-99 oder SQL-3. 1 Diese Struktur ermöglicht darüber hinaus nicht nur eine logischen, sondern auch eine physikalische Trennung zwischen Entwurf und Implementierung. Das entwickelte Framework bildet dabei den Entwurf und die Komponente, die diese Framework verwendet, und enthält (fast) nur noch Implementierungsaspekte. Den Abschluss dieser Arbeit bildet ein Vergleich der relationalen und der objektrelationalen Datenbanktechnik, Schlussfolgerungen aus dem Entwicklungsprozess und ein Ausblick, in dem die Verwendung einer objektorientierten Datenbank betrachtet wird. 1.2 Die zu lösende Aufgabe Von der Firma Francotyp Postalia wurde eine Aufgabe gestellt, die, wie bereits erwähnt wurde, im Rahmen einer Diplomarbeit gelöst werden sollte. Francotyp Postalia stellt Frankier- und Kuvertiermaschinen her. Für die Entwicklung einer neuen Frankiermaschine2 sind u. a. folgende Schritte nötig, die von verschiedenen Teams (im Folgenden Fachgruppe genannt) bearbeitet werden: • Entwicklung und Weiterentwicklung der Hardware • Entwicklung der eingebetteten Software • Entwicklung der Mechanik • Entwicklung und Weiterentwicklung von Tools zum Konfigurieren der Maschine • Serverentwicklung zur Verwaltung der Kundendaten Die Fachgruppen erledigen dabei unterschiedliche Tätigkeiten, die in einer abstrakten Form für alle Arten von Fachgruppen gleich sind. Bei einer Hardwareentwicklung muss, genauso wie bei einer Softwareentwicklung, analysiert, entworfen, implementiert und getestet werden. In langer und mühevoller Arbeit hat die Abteilung Hardware- und Softwareentwicklung, von der ich beauftragt wurde, einen solchen Katalog mit abstrakten Aufgabenbeschreibungen (im Folgenden Aufgabenkatalog) erstellt. Diese Aufgabenkataloge sollen eine Vergleichbarkeit der unterschiedlichen Fachgruppen möglich machen. Abbildung 1 zeigt dies anhand eines Beispiels. Obwohl das Zusammenlöten von Schaltungen scheinbar nichts mit der Programmierung einer Applikation zu tun hat, kann es doch im Aufgabenkatalog Implementierung eine Vergleichbarkeit von Hardware- und Softwareentwicklung ermöglichen. 2 Frankiermaschinen sind Maschinen, die einen der Briefmarke entsprechenden Aufdruck auf einen Briefumschlag oder ein abziehbares Label drucken. 2 Aufgabenkatalog Fachgruppe Hardware Analyse 20 % Entwurf 30 % Implementierung 50 % Fachgruppe Software 30 % 60 % 10 % Abbildung 1: Beispiel für eine Vergleichbarkeit von Fachgruppen 1.3 Vorgehensweise Bei der Entwicklung der Applikation Zeiterfassung wurde, wie in Abbildung 2 dargestellt ist, vorgegangen. Abbildung 2: Gliederung und Vorgehensweise Der erste Schritt in einem Softwareentwicklungsprozess ist die Analyse. Requirements Engineering stellte Techniken, Methoden und Vorgehensweisen zur Verfügung, zum Erheben, Analysieren und Beschreiben von Anforderungen. Durch eine systematische Vorgehensweise sollen Fehler in der Analyse vermieden werden. Im Kapitel 2 werden diese Konzepte vorgestellt. Das Kapitel 2 dient als Grundlage für die eigentliche Analyse bzw. Anforderungsermittlung, die in Kapitel 3 beschrieben wird. Nach der Analyse folgt der Entwurf. Die zu erstellende Applikation sollte mit dem ASP .NET Page-Framework entwickelt werden. Im Kapitel 4 wird diese Framework vorgestellt und auf einige Konzepte, die im Weiteren benötigt werden, genauer eingehen. Prinzipiell sollte der Entwurf unabhängig von der Implementierung sein. Es hat sich aber herausgestellt, dass dies für die Entwicklung in einem Framework nicht so ohne weiteres möglich ist. Im Kapitel 5 wird, basierend auf den Konzepten 3 von Kapitel 4, der Entwurf für die Zeiterfassung mit ASP.NET beschrieben. Um eine Vergleichbarkeit von verschiedenen Datenbanktechniken zu ermöglichen, wurde ein Framework entwickelt. Die datenbankspezifischen Aspekte werden in eine separate Komponente auslagert, die das entwickelte Framework verwendet. Damit kann, abhängig von der verwendeten Datenbanktechnik, eine der spezifischen Komponenten verwendet und verglichen werden. Die konkrete Implementierung wurde mit einer relationalen Datenbank durchgeführt. Basierend auf dem entwickelten Framework von Kapitel 4, wird die eine verwendete Komponente mit einer Implementierung mit einer relationalen Datenbank vorgestellt (siehe Kapitel 6). Ausgehend von den Problemen, die sich dabei ergeben haben, wird diese Implementierung mit der einer objektrelationalen Datenbank verglichen (siehe Kapitel 7). 4 2 2.1 Requirements Engineering Einleitung Oft sind Fehler in der Softwareentwicklung auf eine schlechte Analyse zurückzuführen (vgl. u. a. [Rup 01]). Unklare, nicht oder nur oberflächlich formulierte Anforderungen können in einem Projektverlauf zu vielen Missverständnissen und späteren Änderungen führen. Diese Änderungen sind unter Umständen sehr zeitaufwendig oder gar nicht mehr möglich. Wie in [Rup 02, S. 1] beschrieben ist, stellen die Anforderungen das Fundament der Softwareentwicklung dar. Umso wichtiger ist es, dass diese Phase der Softwareentwicklung mit besonderer Sorgfalt durchgeführt wird. In diesem Kapitel werden die Grundlagen (Kapitel 2.2) und einige Techniken beschrieben, mit denen ein Requirements Document erstellt wird. Das Requirements Document ist das Ziel der Entwicklungsphase Requirements Engineering und beschreibt die Anforderungen an ein zu erstellendes Softwaresystem. Der Requirements Engineering Prozess besteht, wie in Abbildung 3 dargestellt, aus drei Phasen. Abbildung 3: Requirements Engineering Prozess [Som Saw 97, S. 113] Zunächst werden die Anforderungen ermittelt (Requirements Elicitation). In Kapitel 2.4 wird gezeigt, wie durch Befragung der System Stakeholder, Analyse des IstZustands und Untersuchung der vorhandenen Unterlagen dabei vorgegangen wird. System Stakeholder sind Personen, die das System direkt oder indirekt benutzen. Beispiele für System Stakeholder sind Kunden, Administratoren, Manager und Mitarbeiter. Nachdem die Anforderungen erhoben wurden, werden diese auf ”Schwächen” hin untersucht. In Kapitel 2.5 wird beschrieben, wie inkonsistente, unvollständige, fehlerhafte und unvollständige Anforderungen erkannt werden. Die Fragen und Probleme, 5 die sich bei den ”fehlerhaften” Anforderungen ergeben, müssen weiter hinterfragt werden (Requirements Negotiation), was zu neuen oder geänderten Anforderungen führen kann. Wie in Abbildung 3 dargestellt, ist der Requirements Engineering Prozess ein zyklischer, d. h., die geänderten oder neu hinzugekommenen Anforderungen müssen wiederum analysiert werden. Im Idealfall ist der Requirements Engineering Prozess beendet, wenn alle Unstimmigkeiten beseitigt sind. Parallel zu diesen drei Phasen müssen die Anforderungen aufgeschrieben werden. Bei der Beschreibung der Anforderungen ergeben sich u. a. folgende Fragen, die im Kapitel 2.3 beantwortet werden: • Wie werden die Anforderungen in dem Requirements Document strukturiert? • Wie werden die einzelnen Anforderungen beschrieben? • Wie können Systemmodelle unterstützend eingesetzt werden? 2.2 Definitionen Bevor auf die einzelnen Phasen des Requirements Engineering Prozesses eingegangen wird, werden in diesem Abschnitt einige Begrifflichkeiten und Grundlagen beschrieben. 2.2.1 Was sind Requirements? In [Som Saw 97, S. 5, eigene Übersetzung] wird die Frage folgendermaßen beantwortet: ”Requirements (=Anforderungen) sind die Spezifikation von dem, was implementiert werden soll. Sie beschreiben die Benutzermöglichkeiten, die generellen Systemrechte (Beispiel: Personalinformationen sind nur einsehbar, wenn sich der Benutzer authentifiziert hat), die generellen Bedingungen an das System (Beispiel: alle 10 Sekunden soll ein Sensorwert ausgelesen werden) und die Bedingungen an den Entwickler (Beispiel: Das System soll in C++ entwickelt werden)”. 2.2.2 Definition: Requirement Nach [IEEE610.12-1990] wird eine Requirement folgendermaßen definiert: 1. Eine Bedingung oder Fähigkeit von einem Benutzer, die benötigt wird, um ein Problem zu lösen oder eine Zielsetzung auszuführen. 2. Eine Bedingung oder Fähigkeit, die beschlossen wird oder die ein System oder eine Komponente besitzen muss, um einen Vertrag, Standard, Spezifikation oder andere formell aufgelegte Dokumente zu erfüllen. 3. Eine dokumentierte Repräsentation der Bedingungen von (1) und (2). 6 2.2.3 Bedingungen an ein Requirement Nach [IEEE830-1998] sollten Anforderungen mindestens folgende Bedingungen erfüllen: korrekt: Anforderungen müssen die (wahren) Kundenanforderungen widerspiegeln. unmissverständlich bzw. eindeutig : Anforderungen dürfen keinen Interpretationsspielraum zulassen. vollständig: Vor allem die Bedingungen sind zu überprüfen, Ausnahme- und Sonderfälle sind zu prüfen. konsistent: Jede Anforderung muss für sich allein konsistent sein. sortiert nach Bedeutung und Stabilität: Durch die Vergabe von Prioritäten können Anforderungen nach ihrer Wichtigkeit sortiert werden. testbar: Anhand einer Anforderung sollte sich mühlos ein Testfall ableiten können. änderbar: Änderungen an einer Anforderung dürfen keine Inkonsistenz zu anderen Anforderungen entstehen lassen. Ggf. müssen Abhängigkeiten der Anforderungen untereinander definiert werden, um diese änderbar zu machen. nachvollziehbar: Es sollte nachvollziehbar sein, warum die Anforderung so gestellt wurde, z. B. durch Referenzen auf zusätzliche Unterlagen oder anderen Dokumenten. 2.2.4 Was ist Requirements Engineering? Requirements Engineering beschreibt die Aktivitäten, die nötig sind um Anforderungen zu ermitteln, zu beschreiben und auf Korrektheit, Vollständigkeit, Konsistenz und Relevanz zu überprüfen. Der Begriff Engineering impliziert, dass es sich um eine systematische und wiederholbare Technik handelt (vgl. [Som Saw 97, S. 5]). Bei den Anforderungen unterscheidet man außerdem zwischen funktionalen und nicht-funktionalen Anforderungen. Nicht-funktionale Anforderungen sind z. B. Qualitätsanforderungen oder Randbedingungen und lassen sich oft nur sehr schwer oder gar nicht messen. Funktionale Requirements beschreiben die (messbaren bzw. testbaren) Eigenschaften des Systems. Dabei ist die Trennung nicht ganz eindeutig und viele nicht-funktionale Anforderungen lassen sich durch detailliertere Beschreibung in funktionale und damit auch messbare Anforderungen umwandeln (vgl. [Gli 04, Kap. 5.4]). Wie in Kapitel 3.2.1 noch zu sehen sein wird, können nicht-funktionale Anforderungen in funktionale umgewandelt werden. 7 2.3 2.3.1 Das Requirements Document Einleitung Das Requirements Document beschreibt die Anforderungen für die Kunden, die Benutzer und die Entwickler. Es sollte in einer einfachen, für jedermann verständlichen Sprache geschrieben sein. Das Requirements Document soll die verschiedensten Interessen und Sichtweisen der Benutzer- und Personengruppen widerspiegeln (siehe [Som Saw 97, S. 38 f.]. • Dem Kunden3 dient das Requirements Document zur Überprüfung, ob seine Anforderungen richtig verstanden wurden. • Dem Projektmanagement dient das Requirements Document als Grundlage für die Angebotserstellung und die Planung des Entwicklungsprozesses. • Dem Systementwickler dient das Requirements Document als Grundlage für den Entwurf und die Implementierung des Systems. • Die Tester sollen aus den Anforderungen Testfälle ableiten können, um zu überprüfen, dass die Anforderungen auch erfüllt sind. Sehr häufig werden in diesem Zusammenhang die Begriffe Pflichtenheft und Lastenheft verwendet. In einem Lastenheft werden die Anforderungen aus Sicht des Kunden aufgeschrieben. Die erweiterte Version des Lastenheftes ist das Pflichtenheft. Im Pflichtenheft werden die Anforderungen des Kunden verfeinert und konkrete Realisierungsansätze ermittelt. Kurz gesagt beschreibt das Lastenheft, was zu lösen ist und warum. Das Pflichtenheft erweitert das Lastenheft um das Wie und Womit. Das Pflichtenheft wird dem Auftraggeber vorgelegt und dient als Grundlage für einen Vertrag zwischen dem Systementwickler und Auftraggeber (vgl. [ViSEK]). In der Realität gibt es dabei oft Probleme, da das Pflichtenheft nicht immer konform zum Lastenheft ist. Beim Requirements Engineering gibt es ein Requirements Document, was das Pflichten- und das Lastenheft ersetzen soll. 2.3.2 Requirements beschreiben Anforderungen müssen so beschrieben werden, dass sie kurz, verständlich und eindeutig sind. Sie dürfen keinen Interpretationsspielraum zulassen und müssen die in Kapitel 2.2.3 genannten Bedingungen erfüllen. 3 Der Kunde wird im weiteren Verlauf als Auftraggeber bezeichnet und ist der beschriebene Abteilungsleiter. 8 Die Beschreibung solcher Anforderungen ist nicht ganz einfach, da kurze einfache Formulierungen und vollständig Beschreibungen mit allen Sonder- und Ausnahmefällen oft einen Widerspruch darstellen. Ein weiteres Problem stellen die sehr unterschiedlichen Lesergruppen (siehe Kapitel 2.3.1) dar. Die Anforderungen sollen so gestellt werden, dass ein Entwickler daraus eindeutig ableiten kann, was entwickelt werden soll, und das Projektmanagement beispielsweise muss die gleichen Anforderungen ebenfalls verstehen können, um daraus ein Angebot erstellen zu können. Dies ist vor allem bei einer rein natürlichsprachlichen Anforderungsbeschreibung oft sehr schwierig. Ein weiteres Problem mit der natürlichsprachlichen Anforderungsbeschreibung soll das folgende Beispiel verdeutlichen (vgl. auch [Som Saw 97, S. 141 ff.]): ”Wenn der Benutzer eingeloggt ist und den Button Administration bestätigt hat, kann er, wenn er das Benutzerrecht ’Administrator’ besitzt und sofern kein anderer...” Weitere Probleme, die sich nach Sawyer und Sommerville (vgl. [Som Saw 97, S. 147]) bei einer natürlichsprachlichen Beschreibung ergeben, sind, dass diese Terminologien meist in einer inkonsequenten und unsauberen Form verwendet werden. Die Verwendung einer Spezifikationssprache für Requirements hat den Nachteil, dass sie wahrscheinlich nicht von jedem sofort verstanden wird und erst erlernt werden muss (vgl. [IEEE830-1998, Kapitel 4.3.2.2]). Wie schon erwähnt wurde, sind die Systementwickler nur eine der Lesergruppen. 2.3.3 Systemmodellierung Systemmodelle beschreiben einen bestimmten Aspekt eines Systems. Sie ergänzen das Requirements Dokument, um die Anforderung verständlicher zu beschreiben, und sollten parallel zur Anforderungsermittlung erstellt werden (vgl. [Som Saw 97, S 299]). Systemmodelle helfen zum einen die Anforderungen besser zu verstehen und können es erleichtern, mit dem Auftraggeber zu kommunizieren. Zwei wichtige Typen von Systemmodellen sind verhaltensorientierte und strukturelle Modelle (vgl. [Som Saw 97, S. 307]). Die strukturellen Modelle beschreiben die Entitäten und die Abhängigkeiten dieser zueinander sowie die Struktur des Systems oder der Komponenten. Ein Beispiel für die verhaltensorientierten Modelle sind Statechart Diagramme oder Timeline Diagramme. Prinzipiell sollten die Systemmodelle die gleichen Anforderungen wie die eigentlichen Anforderungen erfüllen, da diese genauso von allen genannten Lesergruppen verstanden werden sollen. 9 2.3.4 Struktur des Requirements Documents Im Requirements Document sollen die gesammelten und analysierten Informationen (Requirements, Systemmodelle, Beschreibung der Stakeholder) in einer strukturierten Form dargestellt werden. Zu diesem Zweck wurde ein Standard entwickelt, der in [IEEE830-1998] beschrieben ist und als Grundlage für das Requirements Document dienen kann. Dieser Standard ist sehr allgemein gehalten, gibt aber trotz allem eine Reihe von Punkten vor, die grundsätzlich in jedem Requirements Documents enthalten sein sollten. Der Stuktur des Hauptteils ist dabei offen gehalten. Es werden lediglich Templates für mögliche Strukturen vorgeschlagen. Die Verwendung eines Standards hat den Vorteil, dass nicht jede Firma das ”Rad neu erfinden” muss und auf die Erfahrungen anderer zurückgegriffen werden kann. Neue Mitarbeiter, die ein Requirements Document lesen, was einem firmeneigenen Standard folgt, müssen sich erst einarbeiten, um mit diesem arbeiten zu können. Softwareunterstützte Tools, die auf diesem Standard basieren, sind in der Regel preiswerter als selbst entwickelte Tools, welche auf dem firmeneigenen Standard aufbauen. 2.4 2.4.1 Anforderungen erheben (Elicitation) Einleitung In diesem Abschnitt geht es darum, die Anforderungen zu ermitteln. Haupt- und Mittelpunkt bei der Anforderungserhebung sind die Stakeholder (vgl. [Rup 02, S. 140 f.]). Durch eine erste Befragung des Auftraggebers (siehe 2.4.2) werden die generellen Ziele und die ersten Stakeholder ermittelt. In Abschnitt 2.4.3 werden Techniken vorgestellt, mit denen diese befragt werden können. Parallel zu den Befragungen der Stakeholder können weitere Techniken verwendet werden, die in Abschnitt 2.4.4 vorgestellt werden. 2.4.2 Erste Schritte Als ersten Schritt in der Anforderungserhebung wird in [Som Saw 97, S. 66 ff.] eine Machbarkeitsstudie vorgeschlagen. Eine Machbarkeitsstudie im eigentlichen Sinne war diesem Fall aus zeitlichen Gründen nicht möglich. Basierend auf dem Fragenkatalog von [Som Saw 97, S. 66 ff.] können die in Abbildung 4 dargestellten Fragen zum ersten Interview des Auftraggebers dienen. Durch die letzte Frage werden die ersten Stakeholder ermittelt. 2.4.3 System Stakeholder identifizieren und befragen Ein sehr wichtiger Punkt in der Anforderungsermittlung ist die Ermittlung und Befragung der Stakeholder. Wenn nicht alle Stakeholder ermittelt werden, besteht die Gefahr, dass wichtige Anforderungen vergessen werden (vgl. [Som Saw 97, S. 72 ff.]), 10 1. Was ist das Ziel des Systems? 2. Was wäre die Konsequenz, wenn wir das System nicht entwickeln? 3. In welchen direkten und indirekten Wegen beeinflusst das System die Geschäftsprozesse? 4. Welche kritischen Prozesse muss das System berücksichtigen? 5. Welche kritischen Prozesse werden von dem System nicht unterstützt? 6. Wie beeinflusst das System die vorhandenen Systeme? 7. Was sind die Bedingungen an den Entwickler? 8. Welche Geschäftsbereiche sind in das System integriert und müssen betrachtet werden? Abbildung 4: Erste Befragung des Auftraggebers oder wie in [Rup 02, S. 148] beschrieben ist: ”Vergessene Stakeholder sind vergessene Anforderungen”. Ein nachträgliches Hinzufügen von Anforderungen ist dann nur noch mit sehr viel Aufwand möglich. Durch die Geschäftsbereiche, die in das System integriert werden sollen, lassen sich die ersten Benutzergruppen ermitteln (vgl. letzte Frage aus Abbildung 4). Im Folgenden werden einige Befragungstechniken vorgestellt, mit denen die Anforderungen von der Stakeholder ermittelt werden können. Ein grundsätzlicher Vorteil bei der Befragung der Stakeholder ist, dass sich diese durch die Befragung stärker an der Entwicklung beteiligt fühlen, was die Akzeptanz an das neue System erhöht. Fragebögen Fragebögen sind vor allem dann eine geeignete Technik, wenn in kurzer Zeit viele Informationen gesammelt werden sollen. Sie haben allerdings den Nachteil, dass die befragten Personen keine Fragen stellen können, und setzen voraus, dass bekannt ist, welche Informationen benötigt werden, was in dieser Arbeit oft nicht der Fall war. Einzelinterview In [Sah 00, S. 21] werden zwei Arten des Einzelinterviews beschrieben. Bei einem geschlossenen Interview werden zuvor Fragen vorbereitet, die dem entsprechenden Stakeholder gestellt werden. Rück- und Verständnisfragen sind zwar 11 möglich, aber diese Technik verlangt ein strenges Vorgehen nach den vorher definierten Fragen und erlaubt nicht, dass auf die Fragen weiter eingegangen werden kann. Wie in [Sah 00, S. 21] dargestellt ist, besteht bei dieser Technik das Problem, dass wichtige Aspekte nicht berücksichtigt werden, die durch ein ”freies Reden” aufkommen könnten. Einer der Vorteile dieser Methode ist, dass kein aufwendiges Protokollieren nötig ist und die gleiche Befragung bei einem anderen Repräsentanten der Stakeholdergruppe durchgeführt werden kann. Die zweite Möglichkeit ist das offene Interview. In diesem Fall wir eine zentrale Frage bzw. ein zentrales Ziel der Befragung definiert und der Befragende kann abhängig von den gegebenen Antworten weitere Fragen stellen. Bei dieser Technik besteht das Problem, dass auf unwichtige Themen abgeschweift werden kann und sowohl die Fragen als auch die Antworten müssen protokolliert werden. Außerdem ist ein geschlossenes Interview in gleicher Form nicht reproduzierbar. Gruppeninterview In einem Gruppeninterview wird eine repräsentative Menge an Stakeholdern ermittelt, mit denen gemeinsam die Anforderungen oder Probleme analysiert werden. Die Vorgehensweise ist dabei ähnlich der des offenen Interviews. Das Gruppeninterview hat zusätzlich den Vorteil, dass sich die Stakeholder gegenseitig Feedback geben können und durch die gemeinsame Analyse schneller eine Lösung erreicht werden kann. Eine Diskussion in einer Gruppe hat aber auch einige weitere Nachteile im Vergleich zum offenen Einzelinterview, wie z. B. die Einschüchterung von Befragten durch Anwesenheit eines Vorgesetzten oder Kollegen. Brainstorming Eine spezielle Form der Gruppenbefragung ist das Brainstorming. Brainstorming besteht in zwei Phasen: In der ersten Phase werden alle Ideen gesammelt und aufgeschrieben, ohne dass sie bewertet werden. Dabei können auch ungewöhnliche Ideen aufkommen oder sich beliebige Kombinationen ergeben. Erst in der zweiten Phase werden die Ideen bewertet und die unsinnigen Ideen verworfen oder korrigiert. 2.4.4 Unterstützende Analysetechniken Im Folgenden werden einige Techniken beschrieben, die sich nicht auf die Befragung der Stakeholder beziehen und unterstützend eingesetzt werden können. Diese Techniken allein sind oft wenig hilfreich, aber eine wertvolle Ergänzung zu den Befragungen. Analyse von Dokumenten und Vorgängersystemen Vor allem existierende Dokumente aller Art zu diesem Thema können eine hilfreiche Ergänzung darstellen. Gescheiterte Entwicklungen oder existierende Vorgängersysteme können bereits einige Probleme gelöst haben und sind ebenfalls eine hilfreiche 12 Unterstützung. Prototyping Eine weitere Technik ist das Prototyping. Beim Prototyping werden bereits einige Funktionalitäten in einer sehr frühen Phase implementiert, um das Benutzerverhalten zu demonstrieren. Bei dieser Technik gibt es zwei Vorgehensweisen: das explorative und das evolutionäre Prototyping. Beim explorativen Prototyping werden die Benutzermöglichkeiten des zu erstellenden Systems an einer einfachen Anwendung dargestellt, ohne dass konkrete Funktionalitäten existieren. Dieser Prototyp hat den Zweck, die Beschreibung der Anforderungen zu unterstützen, und wird nach dem Requirements Engineering nicht weiter verwendet. Ein explorativer Prototyp sollte mit einfachsten Mitteln erstellt werden können (z. B. Drag-and-Drop4 ). Obwohl ein explorativer Prototyp zusätzliche Zeit kostet, kann sich diese investierte Zeit doch lohnen, da eine ”funktionsfähige” Benutzeroberfläche oft mehr aussagt als eventuell umständliche Beschreibungen. Im Gegensatz dazu gibt es das evolutionäre Prototyping. Dieser Prototyp wird weiter verwendet und entwickelt, um dann schließlich daraus ein fertiges System zu erhalten. Durch die Verwendung eines evolutionären Prototypen hat der Auftraggeber die Möglichkeit, den Entwicklungsprozess mit zu verfolgen. Fehler und Probleme können so frühzeitig erkannt werden und die Stakeholder fühlen sich stärker an der Entwicklung beteiligt. Allerdings können dadurch auch immer weitere Anforderungen entstehen, die erst beim Prototyp erkannt werden. Da der evolutionäre Prototyp gleichzeitig ein Teil des endgültigen Systems darstellt, kann es aber sehr schwierig werden, diese Änderungen mit zu berücksichtigen. Viewpoint-orientierter Ansatz Ein weiterer Ansatz ist der Viewpoint-orientierte Ansatz. Die verschiedenen Sichten der Stakeholder und die verschiedenen Aspekte der Software können separat betrachtet werden. Durch die Betrachtung der Anforderungen unter einem bestimmten Gesichtspunkt (View) kann die Komplexität der Anforderungen vermindert werden und ist somit leichter verständlich. Viewpoints können neben der Anforderungserhebung auch zum Analysieren und in der Beschreibung der Anforderungen verwendet werden. Wie schon in 2.3.2 erwähnt wurde, stellt es eine Schwierigkeit dar, Anforderungen so zu formulieren, dass sie von allen Lesergruppen verstanden werden. Zwei mögliche Viewpoints, die betrachtet werden könnten, sind die Benutzeranforderungen, und zwar einmal mit und einmal ohne Systemanforderungen (vgl. [Som Saw 97, S. 7]). Weitere Möglichkeiten für die Ermittlung von Viewpoints sind die referenzierten Quellen oder die Benutzerrechte. 4 ”ziehen und loslassen”, d. h., die Benutzeroberfläche wird zusammengeklickt 13 2.5 Anforderungen analysieren und neu verhandeln Im Folgenden werden zwei Ansätze vorgestellt, mit denen Anforderungen auf Schwächen hin untersucht werden können. Schwächen in Anforderungen sind nichts Schlechtes. In [Som Saw 97, S. 125] werden sie als natürlich und unvermeidbar dargestellt. Der erste Ansatz ist die Analyse auf sprachlicher Ebene. Anhand der Formulierungen sollen Schwächen erkannt werden. Der zweite Ansatz basiert auf der inhaltlichen Analyse. Dabei wird überprüft, ob die Anforderungen die in Kapitel 2.2.3 genannten Bedingungen erfüllen und konform zueinander sind. Die gefundenen Schwächen in den Anforderungen müssen anschließend dem entsprechenden Stakeholder oder dem Auftraggeber vorgetragen werden. Durch Beschreibung des entstandenen Problems oder Konflikts muss gemeinsam eine Lösung gefunden werden (vgl. [Som Saw 97, S. 125 ff.]. Wie bereits erwähnt wurde, können an dieser Stelle neue Anforderungen entstehen, sich Anforderungen ändern oder neue Stakeholdergruppen herauskristallisieren. 2.5.1 Anforderungen sprachlich überarbeiten Die sprachliche Analyse von Anforderungen basiert auf der Idee, die Formulierungen der Anforderungen zu untersuchen und anhand dieser Schwächen und Fehler zu ermitteln. In [Rup 01] werden drei Arten der sprachlichen Analyse vorgestellt: Tilgung, Generalisierung und Verzerrrung. Bei der sprachlichen Tilgung werden Informationen weggelassen. Oft ist es sinnvoll, zu viele Details in der ersten Phase der Anforderungsermittlung zu vermeiden, um das Problem als Ganzes zu verstehen. Wurden die Anforderungen aber bereits erhoben und sollen analysiert werden, müssen diese Tilgungen wieder hinterfragt werden um die Anforderungen korrekt darzustellen. Eine Form der Informationstilgung sind unvollständig definierte Prozesswörter5 . Diese müssen ermittelt werden und weiter hinterfragt werden. Eine weitere Form der Informationstilgung sind unvollständige Komparative oder Superlative. Diese benötigen immer einen Bezugspunkt, der, wenn er spezifiziert ist, auch messbar sein sollte. Durch Generalisierung bzw. Verallgemeinerungen werden Anforderungen oft zu ungenau beschrieben. Sonder- und Ausnahmefälle werden nicht berücksichtigt, wodurch die Anforderungen unvollständig werden. Zur Überprüfung einer Generalisierung können Universalquantoren gesucht werden (siehe [ViSEK]), wie zum Beispiel ”alle”, ”jeder”, ”nie”, ”immer”. Diese Begriffe sind ein Anzeichen für eine Generalisierung und es muss hinterfragt werden, ob diese Anforderung wirklich für alle bzw. für keinen der möglichen Fälle eintritt. Unvollständig spezifizierte Bedin5 Prozesswörter sind Wörter, die einen Prozess beschreiben. 14 gungen können ebenfalls Anzeichen für Schwächen in den Anforderungen darstellen. Dabei ist zu hinterfragen, was passiert, wenn die gegebene Bedingung nicht eintritt. Substantive ohne Bezugspunkt müssen ebenfalls hinterfragt werden, ob diese nicht eine bestimmte Person oder einen Gegenstand darstellen. Beispiele für solche Substantive sind: ”die Daten”, ”die Funktion” oder ”das System” (vgl. [ViSEK]). Durch Verzerrung werden zeitlich zusammenhänge Informationen zusammengefasst. Ein Beispiel für eine Verzerrung ist Nominalisierung. Dabei wird ein Prozess zu einem Ereignis umformuliert. Beispiele sind ”das Drucken” oder ”das Melden”. Hinter diesen Anforderungen könnte sich ein Prozess verbergen. Ein weiteres Anzeichen für Schwächen in den Anforderungen sind Wörter wie ”machen”, ”können” oder ”haben”. Diese drücken Anforderungen oft nur unvollständig aus (siehe auch [Rup 02, S. 208 ff.]). 2.5.2 Checklisten zur Überprüfung Die Verwendung von Checklisten zur Überprüfung der Anforderungen hat den Vorteil, dass die Anforderungen systematisch und wiederholbar untersucht werden können. Jede Anforderung wird so lang gegen jeden Checklisteneintrag getestet, bis alle ”Fehler” beseitigt sind. In [Som Saw 97, S. 117-120] wird eine initiale Checkliste vorgegeben: voreiliger Entwurf: Beschreibt die Anforderung bereits Entwurfs- oder Implementierungsdetails? Kombinierte Anforderung: Beschreibt diese Anforderung wirklich eine einzelne Anforderung, oder könnte sie in mehrere unterteilt werden? Unwichtige Anforderung: Ist diese Anforderung wirklich nötig, oder beschreibt sie nur eine kosmetische Verschönerung? Konsistent zu den Unternehmenszielen: Ist diese Anforderung konform zu dem Unternehmenszielen? Anforderungsmehrdeutigkeit: Kann diese Anforderung von verschiedenen Personen unterschiedlich interpretiert werden? Was sind die möglichen Deutungen dieser Anforderung? Anforderungsrealismus: Ist die Anforderung mit den gegebenen Mitteln und Werkzeugen realisierbar? Testbarkeit: Ist die Erfüllung dieser Anforderung testbar? Kann ein Tester anhand dieser Anforderung einen Testfall ableiten, der zeigt, dass das System diese Anforderung erfüllt? 15 Wenn die oben dargestellten Checklistenpunkte mit den Bedingungen an die Requirements aus Kapitel 2.2.3 verglichen werden, sieht man, dass diese Checkliste prinzipiell überprüft, ob die genannten Bedingungen an die Requirements erfüllt sind. Die in Kapitel 2.5.1 dargestellte sprachliche Analyse kann ebenfalls in Form einer Checkliste verwendet werden. 16 3 Analyse mit Requirements Engineering 3.1 3.1.1 Anforderungen erheben Erste Schritte Durch eine erste Befragung des Auftraggebers6 , wie in Kapitel 2.4.2 beschrieben, wurden die ersten Anforderungen ermittelt. Dabei ergaben sich u. a. die folgenden Informationen. Die detailliertere und überarbeitete Beschreibung befindet sich in [ReqDoc, Kapitel 1.1 und 2]. Ziele des Systems: • Es soll ein webbasiertes Zeiterfassungssystem erstellt werden, wo die Mitarbeiter ihre geleistete Arbeitszeit den Projekten zuschreiben können. Die geleistete Arbeitszeit wird in prozentualer Form auf die vorhandenen Projekte verteilt. • Die Projekte wiederum bestehen aus einer Menge von Fachgruppen. Die Mitarbeiter sollen ihre den Projekten zugewiesene Arbeitszeit auf diese Fachgruppen verteilen. • Außerdem existieren Aufgabenkataloge, die unabhängig von Projekten und Fachgruppen sind. Jede zugewiesene Arbeitszeit in den Fachgruppen muss von den Mitarbeitern auf die Aufgabenkataloge verteilt werden. • Bei ”kleineren” Projekten existieren keine Fachgruppen. Die in diesen Projekten zugewiesene Arbeitszeit wird dann direkt auf die Aufgabenkataloge verteilt. • Es sollen zahlreiche Berichte (Reports) erzeugt werden können, die verschiedenste Daten in aufbereiteter Form darstellen. • Gleiche Berichte mit gleichen Parametern sollen jederzeit die gleichen Daten anzeigen, d. h., ein nachträgliches Ändern von Daten darf keine Änderung in den Berichten verursachen. Folgendes Beispiel soll diese Anforderung erklären: Wird eine Kostenstelle eines Mitarbeiters geändert, so würde ein Bericht mit allen Stunden pro Kostenstelle nach der Änderung eine andere Ausgabe erzeugen. Konsequenz ohne das System: • Ohne dieses System wäre ein Aufbau von Kennzahlen für die Personalentwicklung nicht möglich (siehe auch [ReqDoc, S. 1]), d. h., die oben genannten Berichte müssten mühselig von Hand erstellt werden. 6 dem Abteilungsleiter der Abteilung Hardware- und Softwareentwicklung 17 Kritische Prozesse: • Das System darf personengebundene Leistungskontrolle nicht ermöglichen, da der Betriebsrat dieses System sonst nicht zulassen würde. Grenzen des Systems: • Eine Anbindung an das existierende SAP-System ist aus politischen und datenschutztechnischen Gründen nicht möglich. Bedingungen an den Entwickler: • Die Zeiterfassung soll eine webbasierte Applikation sein, d. h., die Kommunikation erfolgt über einen Webbrowser. • Für die Zeiterfassung soll ASP.NET und die Programmiersprache C# verwendet werden. Geschäftsprozesse oder andere Systeme beeinflusst die Zeiterfassung nicht (siehe Frage 3 und 6 aus Kapitel 2.4.2). Wie an diesen Antworten zu sehen ist, stellten sich dabei weitere Fragen, die nicht auf Anhieb beantwortet werden konnten: • Woher kommen die Projekte, wenn es keinen Zugriff auf die Projektdaten des SAP-Systems gibt? • Wenn die Mitarbeiter nur prozentual ihre Arbeitszeit den Projekten zuordnen, woher kommen dann die absoluten Arbeitszeiten, um daraus Reports zu erstellen? Aus dieser Befragung ergaben sich die in Abbildung 5 dargestellten Geschäftsbereiche bzw. Stakeholder (vgl. mit Frage 8 und 6 in Abbildung 4 auf Seite 11). Abbildung 5: Kommunikation zwischen den Stakeholdern 18 3.1.2 Analyse des Ist-Zustandes Basierend auf dem Ist-Zustand wurden die ersten Stakeholder ermittelt. Das Hauptziel der Anwendung ist es, Berichte mit Arbeitsstunden über Projekte, Fachgruppen und Aufgabenkataloge zu erhalten. Im Vorgängersystem wurden die Berichte, wie in Abbildung 6 dargestellt, erstellt. Abbildung 6: Activity Diagram des Ist-Zustandes für die Berichtserstellung Die Arbeitszeiten der Mitarbeiter werden über ein externes System erfasst, was nicht ersetzt werden kann. Diese Zeiten stehen dann in einem SAP-System dem Controller zur Verfügung. Über ein Excell-basiertes System müssen die Mitarbeiter ihre Arbeitszeiten nach Ablauf einer jeden Woche auf vorhandene aktive Projekte verteilen. Der Controller wandelt diese relativen Arbeitszeiten in den Projekten zusammen mit den absoluten Arbeitszeiten aus dem SAP-System in absolute Arbeitszeiten in den Projekten um. Über die Zuordnung der Mitarbeiter zu bestimmten Kostenstellen kann er daraus einen Stundenreport für Projekte nach Kostenstellen und nach Mitarbeitern erstellen und diese dem Abteilungsleiter zur Verfügung stellen. Die Projektverwaltung erfolgt wie in Abbildung 7 dargestellt. Die Projekte werden vom Projektmanager7 in einer Exceltabelle verwaltet. Wenn ein neues Projekt beschlossen8 wird, wird der Projektmanager benachrichtigt. Das neue Projekt wird dann in der Exceltabelle angelegt. Die Projektnummer wird dabei manuell ermittelt. Anschließend wird ein Schreiben aufgesetzt, indem u. a. der Controller benachrichtigt wird, dieses Projekt im SAP-System anzulegen. Das Beenden eines Projekts 7 Projektmanager ist in diesem Fall die Sekretärin des Bereichsleiters, der wiederum der Vorgesetzte des Abteilungsleiters ist. 8 in einem Projektteammeeting, was für diese Anwendung aber irrelevant ist 19 Abbildung 7: Zustände eines Projekts erfolgt in einer ähnlichen Form. Wie an dieser Beschreibung zu sehen ist, ergeben sich bei dieser Vorgehensweise viele Probleme. Einige Beispiele hierfür sind die folgenden: • Die Projekte existieren redundant in drei verschiedenen Systemen: in der Exceltabelle des Projektmanagers, im SAP-System, und der Auftraggeber besitzt ebenfalls ein eigenes System. • In dem Excel-basierten System des Controllers kann ein Projekt nur hinzugefügt werden. Abgeschlossene Projekte zu löschen oder wenigstens aus der Liste der Projekte zu entfernen ist nicht möglich. • Der Controller muss bis zu einem festgesetzten Datum jeden Monats einen Bericht mit Arbeitsstunden über Kostenstellen und Projekte erstellen. Wurden Arbeitszeiten von Mitarbeitern nicht zugewiesen, weil sie beispielsweise am Ende der Woche in den Urlaub gegangen sind, ohne ihre Zeitverteilung vorzunehmen, so muss der Controller die Zeitverteilung für diese Mitarbeiter vornehmen, da alle Arbeitsstunden auf Projekte verteilt werden müssen. 3.1.3 Befragung der Stakeholder mit verschiedenen Techniken Für die Befragung der Stakeholder wurden jeweils die in Kapitel 2.4.3 dargestellten unterschiedlichen Techniken angewendet. Gruppeninterview Die Befragung der Mitarbeiter erfolgte in Form eines (geschlossenen) Gruppeninterviews (vgl. Kapitel 2.4.3). Vier repräsentative Mitarbeiter und der Auftragge20 ber sollten klären, wie die Zeitverteilung vorgenommen wird. Dabei sollten folgende Punkte geklärt werden: • Da Unstimmigkeiten über die Verwendung von prozentualer oder absoluter Zuordnung existierten, sollten die Stakeholder diese Frage beantworten. • Sollen Fachgruppen global verwaltet und den Projekten zugeordnet werden oder werden sie für jedes Projekt neu angelegt? • Der Nutzen für die Mitarbeiter sollte geklärt werden, d. h. ob es für sie sinnvoll wäre, wenn sie Berichte über ihre zugeordneten Zeiten erhalten würden. Der letzte Punkt wurde im Wesentlichen nur deswegen gewählt, um die Akzeptanz der Mitarbeiter zu steigern und ihnen einen Vorteil darzubieten, der das neue System für sie besitzt. Ein interessantes Phänomen war, dass sich die Meinungen ziemlich schnell zu einer gemeinsamen Gruppenmeinung entwickelten. Interessant war außerdem, dass die Mitarbeiter Prozente eingeben wollten, obwohl sie ihre Arbeitszeiten als Stunden sehen wollten, so wie zuvor vom Auftraggeber schon gefordert wurde. Nach den Angaben der Stakeholder besteht eine Fachgruppe im Wesentlichen aus einem festen Kern von Mitarbeitern. Um aber den Administrationsaufwand für die Verwaltung der Fachgruppe zu vermeiden, sollen diese für jedes Projekt neu angelegt werden. Brainstorming Die möglichen Berichte, die durch die Zeiterfassung erstellt werden können, wurden in einem Brainstorming-Interview durchgeführt. Der entscheidende Vorteil des Brainstormings liegt darin, dass ziemlich schnell viele Ideen entstehen. Allerdings hat diese Technik den Nachteil, dass das gegebene Vorgehen auch streng eingehalten werden muss, was in diesem Fall nur halbwegs funktioniert hat. Ein weiterer nachteiliger Punkt ist, dass es schwierig ist, die Ideen zu bewerten. Grundsätzlich waren viele gute Ideen dabei, die aber in der gegebenen Zeit nicht realisierbar waren. Einzelinterview Die Befragung der Stakeholder Projektmanagement und Controller wurde als Einzelinterview vorgenommen. Ein strenges Vorgehen in Form eines geschlossenen Interviews (vgl. Kapitel 2.4.3) wurde nicht vorgenommen, um die Möglichkeiten nicht von vornherein einzuschränken. Ein Problem stellte auch die Tatsache dar, dass die Fragen nicht genau genug gestellt werden konnten, da nicht genau klar war, was entwickelt werden sollte. Vor der Befragung wurde eine Liste mit Fragen vorbereitet, die als Richtlinie für das Interview diente. Diese Technik hat sich als sehr vorteilhaft herausgestellt, da durch die vorgegebenen Fragen die Ziele des Interviews definiert waren und die Möglichkeiten trotzdem 21 nicht eingeschränkt wurden. Ein weiterer Vorteil war der, dass keine ”geschickte” Moderatorfunktion des Befragenden nötig war und keine ”störenden” gruppendynamischen Prozesse berücksichtigt werden mussten. Weitere Befragungen Für die Befragungen nach entstandenen Widersprüchen und Schwächen der Anforderungen wurden direkte Befragungen der entsprechenden Stakeholder durchgeführt. 3.1.4 Beschreibung der Stakeholder Im Folgenden werden die einzelnen Stakeholder beschrieben, die in Kapitel 3.1.2 ermittelt und in Kapitel 3.1.3 befragt wurden. Mitarbeiter: Bisher wurden nur Mitarbeiter erwähnt. Diese werden weiter unterteilt in interne und externe Mitarbeiter. Die internen Mitarbeiter arbeiten an den Projekten. An Ende jeder Woche müssen sie ihre Arbeitszeiten in prozentueller Form den vorhandenen Projekten, Fachgruppen und Aufgabenkatalogen zuordnen. Die absoluten Arbeitszeiten der internen Mitarbeiter kommen von einem externen System, auf das aus datenschutztechnischen Gründen nicht zugegriffen werden kann. Die einzige Möglichkeit, diese Daten zu erhalten, besteht darin, diese aus den Exceltabellen des Controllers zu extrahieren. Da diese Lösung aber sehr instabil ist, muss auf jeden Fall auch eine manuelle Stundeneingabe existieren. Die externen Mitarbeiter arbeiten, genau wie der interne Mitarbeiter, in Fachgruppen organisiert, an verschiedenen Projekten. Im Gegensatz zu den internen Mitarbeitern erscheinen externe Mitarbeiter nicht in den Berichten des Vorgängersystems. Die externen Mitarbeiter schreiben in unregelmäßigen Zeitabständen Rechnungen mit ihren geleisteten Arbeitszeiten und reichen diese beim Abteilungsleiter ein. In Kapitel 6.7.2 werden die internen und externen Mitarbeiter auch als Vertragsmitarbeiter bezeichnet, da es möglich sein soll, dass Mitarbeiter, die ihre Arbeitszeiten nicht den Projekten, Fachgruppen und Aufgabenkatalogen zuordnen müssen, ebenfalls Fachsprecher oder Projektleiter sein können. Vertragsmitarbeiter sind sozusagen eine erweiterte Form der Mitarbeiter. Auf dieses Thema wird in den Kapiteln 6.7.2 und 6.8.2 noch eingegangen. 22 Projektmanager: Der Projektmanager verwaltet die Projekte. Er legt die Projekte mit den entsprechenden Projektleitern an und kann diese beenden. Außerdem kann er den Projekten Fachgruppen hinzufügen oder entfernen. Controller: Der Controller überwacht die Kosten der Projekte. Am Ende eines jeden Monats benötigt er eine Projekt-Kostenstelle-Tabelle mit den geleisteten Arbeitsstunden, die er so effizient wie möglich in das SAP-System eingeben möchte und dem Abteilungsleiter zur Verfügung stellt. Der Controller ist die einzige Schnittstelle, um die absoluten Arbeitszeiten der internen Mitarbeiter zu erhalten. Abteilungsleiter: Der Abteilungsleiter verwaltet die Projekte und die darin enthaltenden Fachgruppen und Mitarbeiter seiner Abteilung. Sein Hauptinteresse an der Zeiterfassung ist die Ausgabe der Berichte. Administrator: Diese Rolle existierte vorher nicht und ist nötig um verschiedene Daten, wie beispielsweise Kostenstellen, zu verwalten. Wie bereits erwähnt wurde, existiert keine Möglichkeit, auf die Daten des SAP-Systems zuzugreifen. Die benötigten Informationen müssen redundant zu dem SAP-System verwaltet werden. 3.1.5 Unterstützende Analysetechniken Zwei unterstützende Techniken bei der Anforderungserhebung sind die Analyse von vorhandenen Dokumenten und die Analyse eines Vorgängersystems. Der Viewpointorientierte Ansatz ist vor allem dann vorteilhaft, wenn das Requirements Engineering durch einen CASE-Tool9 unterstützt wird. Da in diesem Fall aber kein CASE-Tool verwendet wurde, wurde auf diesen Ansatz verzichtet. Wie bereits beschrieben wurde, kann der Viewpoint-orientierte Ansatz auch für das Beschreiben von Anforderungen verwendet werden, was in diesem Fall getan wurde (siehe Kapitel 3.3.3). Dokumente und Vorgängersystem: Eine Access Datenbank, die für diese Zwecke entworfen worden war und verwendet wird, lieferte weitere Informationen, die durch die Befragungen nicht aufgekom9 Ein CASE (Code Aided Software Engineering)-Tools ist eine Software, welche den Softwareentwicklungsprozess unterstützt (siehe auch [Som 00] Kapitel 3). 23 men sind. Ein Beispiel dafür ist die weitere Unterteilung der internen Mitarbeiter in Studenten, Aushilfen und ”normale” interne Mitarbeiter. Die vorhandene Exceltabelle des Stakeholders Projektmanager zeigte außerdem, dass Projekte weiter in Projektgruppen organisiert sind. Prototyping: Zunächst wurde ein explorativer Prototyp (vgl. Kapitel 2.4.4) verwendet, der die Funktionalität darstellen sollte. Dies waren einfache PHP-Scripte, die mithilfe einer ”Template-Klasse”10 HTML-Templates zu vollständigen HTML-Seiten zusammensetzen. Der entscheidende Vorteil an dieser Technik ist die Trennung von Funktionalität und Layout über einen sehr einfachen Mechanismus. Änderungen in den HTMLTemplates haben (fast) keine Auswirkungen auf Funktionalität (in diesem Fall nur die Benutzersteuerung) und umgekehrt, wodurch sich ziemlich schnell und einfach Oberflächen gestalten lassen. Die Anforderung, dass die Zeiterfassung in ASP.NET und C# entwickelt werden soll, kam erst etwas später dazu, wodurch sich ein Problem darstellte. ASP .NET bietet einige grundlegend neue Techniken, wie in Kapitel 4 noch beschrieben wird. Da mir diese Technik nicht vertraut war und nicht vorhergesehen werden konnte, was mit ASP .NET möglich ist und was nicht, wurde die Art des Prototyping in einen evolutionären geändert. Wie in Kapitel 2.4.4 beschrieben wurde, stellte sich dabei ein Problem ein. Der Auftraggeber hatte die Möglichkeit, den Entwicklungsprozess zu verfolgen und Änderungen an der definierten Benutzerführung wurden verlangt. 3.2 Analyse der Anforderungen Gemäß Kapitel 2.5 werden im Folgenden einige Beispiel für ”Schwächen” in den Anforderungen darstellt und die Konsequenzen daraus beschrieben. Vor allem der natürlichsprachliche Ansatz (siehe 2.5.1) stellte sich als sehr effizient heraus, da durch eindeutige Regeln Schwächen in den Anforderungen gefunden werden können. Allerdings bot dieser Ansatz keine Möglichkeit, Inkonsistenzen der Anforderungen untereinander zu analysieren. Der Checklisten-Ansatz aus Kapitel 2.5.2 war etwas schwieriger durchzuführen, da diese Fragen ein großes Maß an Interpretationsfreiraum zuließen, d. h., der gleiche Test von einer anderen Person hätte u. U. zu einem anderen Ergebnis geführt. Im Folgenden werden einige Beispiele dargestellt, die zeigen, welche Schwächen durch die Analyse der Anforderungen gefunden wurden. 10 Mehr Informationen zu der Klasse Template befinden sich unter http://phplib.sourceforge.net/ 24 3.2.1 Anforderungen sprachlich überarbeiten Tilgung: Das folgende Beispiel zeigt eine Tilgung in Form eines unvollständig spezifizierten Prozesswortes, welche weiter hinterfragt werden musste: Wurde beim Anlegen eines Projekts keine Projektnummer angegeben, so wird automatisch eine Projektnummer ermittelt, die dem Benutzer voreingestellt in der Eingabemaske angezeigt wird. Das Prozesswort ermittelt stellt dabei ein Schwäche dar. Die Frage ist hierbei, wie wird diese Projektnummer ermittelt. Beim Hinterfragen des Stakeholders Projektmanager ergab sich, dass die Projektnummer abhängig von dem Projekttyp in einem Projektnummerraum liegt. Eine Konsequenz daraus ist, dass der Projekttyp um mindestens ein weiteres Attribut erweitert wird. Außerdem musste geklärt werden, ob sich Projektnummern immer in dem Projektnummerraum befinden müssen oder diese nur eine Empfehlung darstellen, wenn keine Projektnummer eingegeben wurde. Ein weiteres Beispiel für eine Tilgung ist ein unvollständiger Komparativ. Wie bereits in Kapitel 3.1.5 angesprochen wurde, existierten Unstimmigkeiten über das Aussehen und den Ablauf der Benutzeroberfläche, da folgende Anforderungen nicht genau genug betrachtet wurden: Die Zeiterfassung soll eine einfach bedienbare und übersichtliche Benutzeroberfläche besitzen. Die Frage, die sich hierbei u. a. stellt, lautet, wozu die Benutzeroberfläche einfach bedienbar sein soll. Dies ist auch gleichzeitig ein Beispiel für eine nicht-funktionale Anforderung (vgl. Kapitel 2.2.4), die durch genauere Beschreibung zu einen funktionalen umgeformt werden musste. Generalisierung: Ein Beispiel für eine Generalisierung, die zu einer Schwäche führt ist die Projektzeiterfassung der Mitarbeiter. Dabei stellte sich die Frage, was passiert, wenn die Zuordnungen zu Projekten, Fachgruppen und Aufgabenkatalogen nicht vollständig durchgeführt wird, weil beispielsweise der Browser geschlossen oder ein anderer Menüpunkt ausgewählt wird. 25 Ohne Betrachtung dieses Problems wären die eingegebenen Daten einfach verworfen worden, was im Fall eines Ausfalls, weil beispielsweise der Browser abstürzt, sehr ärgerlich geworden wäre. Die Zeitverteilung kann u. U. etwas Zeit in Anspruch nehmen und ein frustrierter Mitarbeiter, der seine Zuordnungen ein zweites Mal vornehmen muss, weil alle Daten verworfen wurden, wird sicherlich keine allzu gründlichen Angaben mehr vornehmen. Nominalisierung: Ein Beispiel für Nominalisierung ist folgende Anforderung: Durch die Eingabe einer Exceltabelle vom Controller werden die absoluten Arbeitszeiten der Mitarbeiter in das System eingegeben. Zur Überprüfung, ob es sich bei einem Substantiv um eine Nominalisierung handelt, kann, wie [Rup 02, S. 208 ff.] beschrieben ist, folgendermaßen vorgegangen werden: • ”Passt das Substantiv sinnvoll in die Phrase ’ein(e) andauernde(r) ...’ (im Sinne von kontinuierlich)”, oder • ”Beschreibt ein Substantiv etwas, das man nicht anfassen kann?” Trifft mindestens eine der beiden Fragen auf ein Substantiv zu, so handelt es sich um eine Nominalisierung. In diesem Fall treffen für das Wort ”Eingabe” sogar beide Fälle zu, d. h., dieser Prozess sollte weiter hinterfragt werden. Bei genauerer Untersuchung dieses Punkts stellte sich heraus, dass dieses Problem im Rahmen dieser Arbeit nicht zufrieden stellend gelöst werden kann. Dies ist auch einer der Gründe dafür, dass in jedem Fall eine manuelle Arbeitszeiteingabe für die internen Mitarbeiter existiert. 3.2.2 Checklisten zur Überprüfung Widersprüchliche Anforderungen: 1. Bei der Befragung des Stakeholders Projektmanagement ergab sich die Information, dass bei der Planung eines Projektes festgelegt wird, wann ein Projekt gestartet wird. Anschließend wird es in eine Exceltabelle eingetragen, der Controller wird informiert und redundant dazu wird dieses Projekt in das SAP-System eingegeben. 26 2. Eine Anforderung vom Stakeholder Abteilungsleiter war, dass Projekte auch rückwirkend eingegeben werden sollten, da das Eintragen der Projekte eventuell vergessen werden konnte, und die Projektinformationen korrekt sein sollten. 3. Des Weiteren sollen Berichte, die sich auf Daten der Vergangenheit beziehen, nicht verändert werden, wenn sich irgendwelche Daten geändert haben. Die 1. Anforderung schließt aus, dass das Eintragen eines Projekts vergessen werden kann, da die Zeiterfassung die vorhandene Exceltabelle des Stakeholders Projektmanager ersetzen soll. Des Weiteren stellt die 1. Anforderung einen Widerspruch zur dritten dar, da die besagten Berichte beispielsweise auch eine Auflistung aller aktuellen Projekte eines Monats enthalten, die bei einem rückwirkenden Eintragen verfälscht werden würden. Die Konsequenz daraus ist, dass Projekte nur mit einem Projektstart angelegt werden dürfen, der nicht in der Vergangenheit liegt. Unnötige Anforderungen sind beispielsweise Anforderungen, die beschreiben, in welchem Fall welcher Button wie gefärbt wird, wobei dieser Punkt ebenfalls abhängig von den Möglichkeiten der verwendeten Implementierungstechnik ist. In ASP. NET ist es beispielsweise kein Aufwand, Buttons in unterschiedlichen Farben darzustellen oder Tabellenspalten für bestimmte Benutzergruppen auszublenden. In anderen Implementierungstechniken für Web-Applikationen ist dies nicht so ohne weiteres der Fall. Dabei zeigt sich auch, dass Anforderungen niemals völlig unabhängig vom Entwurf und von der Implementierung sind. Folgende Aspekte können ebenfalls als Checkliste verwendet werden: • Die Untersuchung der sprachlichen Schwächen aus Kapitel 3.2.1 • Die Struktur des Requirements Documents aus Kapitel 3.3 Da es den Umfang der Arbeit sprengen würde, wurde dieses Thema nicht weiter vertieft. 3.3 3.3.1 Requirements Document Systemmodelle Gemäß Kapitel 2.3.3 werden im Folgenden die verwendeten Systemmodeltechniken beschrieben. Als statisches Modell wurde ein Klassendiagramm (siehe Abbilung 8) gewählt und das in Kapitel 6.7.2 noch vorgestellte, Datenbankmodell. Wie bereits in der Einleitung (Kapitel 1.3) erwähnt wurde, soll die entwickelte Struktur einen Vergleich 27 Abbildung 8: Systemmodell: Klassendiagramm der Datenbanktechniken ermöglichen. Aus diesem Grund kann das Klassendiagramm nicht eins-zu-eins verwendet werden, dient aber zur Beschreibung der Entitäten und ihrer Beziehungen. Als dynamisches Modell wurden Statechart Diagramme verwendet. Diese beschreiben das Benutzerverhalten und die Möglichkeiten der Benutzeroberfläche. Die Zustände bilden dabei jeweils einen Zustand der Benutzeroberfläche ab und die Transitionen beschreiben die Benutzeraktionen. Statechart Diagramme können zudem geschachtelt werde, wodurch die jeweiligen Zustände Schritt für Schritt verfeinert werden können. Durch die Schachtelung lassen sich Funktionsblöcke auf verschiedenen Detailliertheitsgraden darstellen. Der Zustand AuthentificatedUser, wie in Abbildung 9 dargestellt, kann nur erreicht werden, wenn sich der Benutzer zuvor erfolgreich authentifiziert hat (siehe Kapitel 5.6). Einschränkungen, welche die Benutzerrechte betreffen, werden nicht in den Statechart Diagrammen, sondern direkt in den Requirements beschrieben (siehe Kapitel 3.3.2). Befindet sich der Benutzer in einem bestimmten Unterzustand wie beispielsweise Project, so hat er immer die Möglichkeit, durch Auswahl eines anderen Menüpunktes den Zustand Project zu verlassen (beispielsweise durch Betätigen des Buttons Mitarbeiterverwaltung - ButtonEmployeeClick ). Die Statechart Diagramme wurden dabei bewusst einfach gehalten, beispielsweise wurden keine parallelen Kompositionen verwendet, um die Benutzermöglichkeit einfach erkennbar zu lassen und 28 Abbildung 9: Statechart Diagramm für die Menüführung die Testfallgenerierung nicht zu erschweren. Durch den dargestellten Junction Point (siehe schwarzen Punkt in Abbildung 9) können mehrere Transitionen zu einer zusammengefasst werden (siehe auch [Lin 01]). Abbildung 10: Use Case Modell zur Beschreibung der drei Hauptfunktionalitäten Das in Abbildung 10 dargestellte Use Case Diagramm soll aus einer sehr abstrakten Sicht zeigen, welches die generellen Funktionsblöcke sind. Die Akteure spiegeln dabei nicht die Stakeholder wider, sondern sollen die drei generellen Benutzerrollen beschreiben. Die Administratorrolle mit den Use Case ”System verwalten” beschreibt die Funktionalitäten, die nötig sind, da keine Anbindung an das vorhandene SAPSystem möglich ist. Dieser Use Case enhält auch die Eingabe der absoluten Arbeitszeiten und die Projektverwaltung. Die Mitarbeiter ordnen ihre Arbeitszeiten den Projekten, Fachgruppen und Aufgabenkatalogen zu. Die durch die Mitarbeiter und den Administrator gesammelten Informationen können dann von einer Controllerrolle in Form von Berichten (Reports) ausgegeben werden (siehe auch [ReqDoc, 2.2 Produkt-Funktionen]). 29 3.3.2 Struktur eines Requirements Wie in Kapitel 2.3.2 beschrieben ist, hat sowohl die rein natürlichsprachliche als auch die rein formale Beschreibung ihre Nachteile. Um die Anforderungen leicht verständlich, aber trotzdem vollständig zu beschreiben, wurden bestimmte Informationen der Anforderungen aus den Formulierungen extrahiert (siehe Abbildung 11 auf Seite 32). Die Anforderungsbeschreibung ist in diesem Fall frei von umständlichen Formulierungen, welche beispielsweise die Möglichkeiten der Benutzerführung (durch die Statechart Referenz) oder die Benutzerrechte betreffen. Die einzelnen Punkte werden unterschieden in zwingend erforderliche und optionale. Diese Punkte können ebenfalls als Checkliste verwendet werden (siehe Kapitel 3.2.2), um zu überprüfen, ob die Anforderungen vollständig sind. 3.3.3 Struktur des Requirements Documents nach [IEEE830-1998] Gemäß Kapitel 2.3 wurde das Requirements Document nach dem [IEEE830-1998] Standard verwendet. Dieser besteht, wie in Abbildung 12 darstellt, aus drei Teilen: Das erste Kapitel Einleitung gibt einen groben Überblick über das Produkt und das Requirements Document. Im Abschnitt Zielsetzung wird beschrieben, warum dieses Produkt benötigt wird (siehe Kapitel 3.1.1) und für welche Lesergruppen dieses Dokument geeignet ist. Definitionen, Akronyme und Abkürzungen helfen dabei, eine gemeinsame ”Sprachbasis” zu definieren. Unterschiedliche Begriffe für gleiche Dinge sollen damit vermieden werden. Der weitere Aufbau des Requirements Documents und die Struktur der einzelnen Anforderungen (siehe Kapitel 3.3.2) werden im letzten Abschnitt beschrieben. Das Kapitel Benutzercharakteristika beschreibt die Benutzergruppen, die im Kapitel Zielsetzung der Einleitung kurz vorgestellt wurden detaillierter. Eine genauere Beschreibung der Stakeholder soll erklären, warum die Anforderungen genau so beschrieben wurden. Generelle Einschränkungen, Annahmen und Abhängigkeiten zu definieren ist vor allem dann interessant, wenn die Anforderungen des 3. Kapitels auf diese verweisen. Soll das System geändert werden, weil sich z. B. eine Abhängigkeit geändert hat, so wäre sofort erkennbar, welche Anforderungen davon betroffen sind. Anforderungen, die vielleicht sinnvoll und nützlich sind, aber aus irgendwelchen Gründen nicht realisiert werden können, können im letzten Abschnitt des 2. Kapitels aufgeschrieben werden, um nicht vergessen zu werden. Vor allem das dritte Kapitel ist sehr dynamisch gehalten (siehe Kapitel 2.3). In diesem Fall wurde die in Abbildung 12 dargestellte Form gewählt: Der Punkt Schnittstellenbeschreibung ist noch offen und soll die Anbindung an das SAP-System oder die Exceltabelle des Controllers beschreiben. Das in Kapitel 3.3.1 dargestellte Klassendiagramm und das Datenmodell befinden sich im Abschnitt 30 ”Statische Systemmodelle”. Die eigentlichen Anforderungen werden durch zwei Sichten dargestellt (vgl. 2.4.4 und 3.1.5). Wie bereits in Kapitel 2.3.2 erwähnt wurde, ist es schwierig, Anforderungen so zu beschreiben, dass sowohl ein Entwickler als auch beispielsweise ein Projektmanager diese versteht und eindeutig interpretieren kann. Aus diesem Grund wurden genau diese beiden Sichten dargestellt. Im Abschnitt ”Benutzeranforderungen” werden nur die Benutzerfunktionalitäten ohne alle Sonder- und Ausnahmefälle beschrieben. Diese Sicht soll einen detaillierten Überblick über alle vorhandenen Funktionalitäten geben, ohne dass zu sehr ins Detail gegangen wird. Für den Entwickler, der aus diesen Anforderungen eindeutig ableiten soll, was entwickelt werden soll, wird diese Sicht nicht ausreichen. Aus diesem Grund werden im Abschnitt ”Benutzeranforderungen mit Systemanforderungen” die einzelnen Anforderungen im Detail beschrieben. 3.4 Abschließende Worte zum Requirements Engineering Wie schon im Kapitel 2.1 beschrieben wurde, wird beim Requirements Engineering ein iteratives Vorgehen vorgeschlagen. Dabei ist es sehr wichtig, diese Reihenfolge auch diszipliniert durchzuführen. Anforderungen, die geändert, aber nicht im Requirements Document aufgenommen wurden, und anschließend implementiert wurden, verfehlen den Grundgedanken des Requirements Engineerings. Dabei kann es sehr schnell geschehen, dass Anforderungen, Entwurf und Implementierung nicht mehr konform zueinander sind. Da in diesem Fall kein CASE-Tools (siehe Kapitel 3.1.5) verfügbar war, war es in dieser Arbeit sehr mühselig, die Anforderungen aktuell zu halten. Die Anforderungen wurden in einer Exceltabelle mit der in Kapitel 3.3.2 beschriebenen Struktur verwaltet. Über die Filterfunktion konnten nur sehr eingeschränkte Sichten (Viewpoints) auf die Anforderungen vorgenommen werden. Für die Ausgabe in dem Requirements Document wurde eine Serienbrieffunktion verwendet, die diese Anforderungen nach Latex konvertiert hat, da diese Arbeit und das Requirements Document mit Latex erstellt wurden. Folgeänderungen durch Referenzen der Anforderungen untereinander, eine Versionsverwaltung und eine etwas bessere Möglichkeit, verschiedene Sichten auf die Anforderungen zu erhalten, hätten die Arbeit wahrscheinlich sehr viel weniger mühselig gemacht. Wie an den Beispielen zu sehen ist, war das Problem bei der Analyse gar nicht so sehr die Abbildung des Problems auf geeignete Modelle, sondern vielmehr die Frage, was abgebildet werden soll. Eine klare Beschreibung, die angibt, wie detailliert Requirements beschrieben werden sollen, habe ich nicht gefunden. In [Som Saw 97, eigene Übersetzung, S. 6] heißt es nur: ”Der Detailliertheitsgrad der Anforderungen hängt im wesentlichen von der Praxis in ihrem Unternehmen ab.” 31 ID: Jede Anforderung besitzt eine eindeutige Identität. Durch die verwendete Punkt-Notation werden diese hierarchisch geordnet, d. h., Project.Insert.Valid beschreibt den detaillierteren Fall, wenn das Anlegen eines Projekts (Project.Insert) aus beschriebenen Gründen nicht möglich ist. Priorität: Jede Anforderung besitzt eine der drei folgenden Prioritäten: • A (zwingend erforderlich), • B (wäre gut, aber muss nicht sein) oder • C (”nice to have”) Benutzerrecht (optional): Bedingungen sind meist mit Transitionen verbunden und beschreiben all diejenigen Bedingungen, die sich nicht auf Möglichkeiten der Benutzeroberfläche oder die Benutzerrechte beziehen. Anforderung: In diesem Punkt werden die eigentlichen Anforderungen (Requirement) beschrieben. Statechart-Referenz: Jeder Funktionsblock besitzt genau ein Statechart Diagramm. Jede Anforderung muss sich auf einen Zustand oder eine Transition beziehen, die hier beschrieben wird. Stakeholder: Jede Anforderung kommt von einem Stakeholder, der als Referenz für die Anforderung gilt. Dieser kann sich von den Benutzerrechten unterscheiden, beispielsweise wenn Forderungen vom Auftraggeber für Mitarbeiterfunktionalitäten beschrieben werden. Referenz (optional): Alle zusätzlichen Referenzen (siehe Kapitel x) werden hier beschrieben. Aus zeitlichen Gründen wurde diese Spalte nicht vollständig ausgefüllt. Dieser Punkt stellt auch eine Erweiterung des Punktes Stakeholder dar. Beispiel (optional): Vor allem bei Berechnungen oder beschriebenen Einschränkungen können Beispiele unterstützend verwendet werden. Anmerkung (optional): In diesem Punkt werden detaillierte Beschreibungen für eine Anforderung, die keine neue Anforderung darstellt, oder Begründungen für bestimmte Anforderungen beschrieben. Abbildung 11: Aufbau eines Requirements 32 1. Einleitung (a) Zielsetzung (b) Produkt- und Anwendungsbereich (c) Definitionen, Akronyme und Abkürzungen (d) Referenzen (e) Überblick zum restlichen Dokument 2. Generelle Beschreibung (a) Produkt-Perspektiven (b) Produktfunktionen (c) Benutzercharakteristika (d) Generelle Einschränkungen (e) Annahmen und Abhängigkeiten (f) Anforderungen für Weiterentwicklungen 3. Spezifische Anforderungen (a) Schnittstellen im Detail (b) Statische Systemmodelle (c) Benutzeranforderungen (d) Benutzeranforderungen mit Systemanforderungen 4. Anhänge 5. Index Abbildung 12: Requirement Dokument nach [IEEE830-1998] 33 4 Konzepte von ASP.NET 4.1 4.1.1 Grundlagen 3-Tier-Architektur Im Allgemeinen werden Web-Applikationen als 3-Tier-Architektur konzipiert, wie in Abbildung 13 dargestellt ist. Abbildung 13: 3-Tier-Architektur für Web-Applikationen In einer 3-Tier-Architektur sind Client11 , Applikation und Datenbank voneinander getrennte Einheiten. Der Client kommuniziert nur mit dem Applikationsserver (oft auch Businesslogik genannt), welcher wiederum mit einer Datenbank kommuniziert, d. h., der Client und die Datenbank kommunizieren niemals direkt miteinander. Durch Senden einer parametrisierten Webseiten-Anfrage an den Server fordert der Client vom Server eine Webseite an. Diese ist abhängig von der jeweiligen Anfrage. Für jede Benutzeraktion (beispielsweise das Betätigen eines Buttons) wird eine solche Anfrage an den Server gesendet (siehe auch [Sch 02, S. 9 ff.]). 4.1.2 .NET - Framework Eine verhältnismäßig neue Entwicklungsform für Web-Applikationen ist ASP.NET. ASP.NET ist ein Bestandteil des .NET Frameworks, wie in Abbildung 14 dargestellt. In [MSDN .NET Framework FAQ 01, eigene Übersetzung] wird das .NET Framework definiert als, ”eine integrierte Windowskomponente, zum Ausführen und Entwickeln von Applikationen [..] der nächsten Generation. Das .NET Framework ist sprachenunabhängig und stellt eine umfangreiche Klassenbibliothek zur Verfügung [(Base Class Library)].” Auf dem (Windows-)Betriebssystem ist eine Common Language Runtime aufgesetzt, die, ähnlich der JAVA Virtual Maschine, ein Programm nicht direkt ausführt, 11 Der Client der Web-Applikation ist immer der Web-Browser. 34 Abbildung 14: Das .NET Framework sondern es erst bei der ersten Verwendung in Maschinencode übersetzt. Die Programmiersprache, die in der Zeiterfassung verwendet wurde, ist C# (siehe Kapitel 4.1.4), obwohl die Festlegung einer Programmiersprache im .NET Framework nicht unbedingt nötig ist, da über die Common Language Specification die verschiedenen Klassen in verschiedenen Programmiersprachen entwickelt und beliebig miteinander kombiniert werden können. Für die Web-Applikation ist vor allem ASP.NET wichtig. Die Konzepte von ASP.NET werden in Kapitel 4.1.5 genauer beschrieben. 4.1.3 Businessobjekte In .NET gibt es zwei Möglichkeiten, Gruppen von Klassen zu Komponenten oder Businessobjekten zusammenzufassen (vgl. dazu auch [Mös 03]). Assemblies: Assemblies sind wiederverwendbare Programmpakete, die in einer physikalischen Datei abgelegt sind und von anderen Applikationen verwendet werden können. Sie sind in der Windowswelt sozusagen eine Weiterentwicklung der Dynamic Linked Librarys (DLL). Im Vergleich zu JAVA sind sie eng verwandt mit den JAR-Files. Namespaces: Namespaces sind ähnlich zu den Packages in JAVA. Im Gegensatz zu JAVA kann eine Datei aber mehrere Namespaces besitzen oder sich ein Namespace über mehrere Dateien erstrecken. 4.1.4 Die Programmiersprache C# Parallel zum .NET-Framework wurde von Microsoft eine neue Programmiersprache mit dem Namen C# (gesprochen: ”See Sharp”) entwickelt. C# besitzt sehr viel Ähnlichkeit mit JAVA und C++, aber auch einige neue Konzepte, die im Folgenden 35 erklärt und im Entwurf in Kapitel 5 verwendet werden. Properties Im [NetLexikon] wird ein Property (Eigenschaft) als eine Sicht auf ein Attribut bezeichnet. Properties ersetzen die ”Getter”- und ”Setter”-Methoden und werden wie Attribute einer Klasse verwendet, wie in Abbildung 15 an einem Beispiel gezeigt wird. Die Konsistenzprüfung in dem Property Proration gewährleistet, dass das Attribut immer kleiner als 100 ist. (1) private string m Proration; (2) public string Proration { (3) get{ return this.m Proration; } (4) set { (5) if( value < 100 ) throw new Exception( ”Fehlermeldung” ); (6) else this.m Proration = value; (7) } ... Proration = 142; // wirf eine Exception Abbildung 15: Beispiel für die Verwendung von Properties Indexer Ähnlich zu dem Konzept der Properties sind die Indexer. Diese erlauben es, auf ein Objekt wie auf ein Array zuzugreifen. Indexer werden durch das Schlüsselwort this definiert. Abbildung 16 zeigt eine Klasse Manager, die einen Indexer enthält. (1) (2) (3) (4) (5) (6) ... (7) (8) (9) public class Manager { PersistentObject this [int id ] { get { /* Gibt das PersistentObject id zurück */ } set { /* Setzt das PersistentObject id */ } } } Manager m = new Manager(); m[0] = new PersistentObject(); Persistentobject o = m[0]; Abbildung 16: Beispielcode für die Verwendung eines Indexer Eventhandler Ein Event ist eine Nachricht, die von einem Objekt gesendet wird, um das Auftreten einer Aktion zu signalisieren. Sie wird von einem Sender ausgelöst und von einem Empfänger empfangen. Der Empfänger muss sich dafür beim Sender anmelden, was über ein Delegate passiert. In . NET wird dafür ein eigener Typ mit dem 36 Namen event zur Verfügung gestellt, bei dem ein Empfänger sich durch Übergeben einer Methode (Delegation) anmelden kann. Wenn das Event eintritt bzw. gefeuert wird, werden die an dem Event angemeldeten Methoden aufgerufen (siehe auch [Mös 03, Kap. 10]). Sichtbarkeiten In C# gibt es neben public, protected und private noch eine weitere Sichtbarkeit, die durch das Schlüsselwort internal gekennzeichnet ist. Diese drückt aus, dass ein Mitglied einer Klasse nur in derselben Assembly sichtbar ist. Im Klassendiagramm wird diese Sichtbarkeit durch ein ∼ dargestellt. 4.1.5 ASP.NET Page-Framework Microsoft definiert das ASP. NET Page Framework ”als ein Programmierframework, das auf einem Webserver läuft und dynamisch Webseiten erzeugt und verwaltet. Diese Webseiten werden Webforms genannt und können im Visual Studio entwickelt und implementiert werden. ... Das ASP .NET Page Framework schafft eine Abstraktion der traditionellen Client-Server Kommunikation, die es ermöglicht, eine Web-Applikation mit den traditionellen objektorientierten und eventbasierten Programmiertechniken zu entwickeln” ([MSDN ASP.NET, eigene Übersetzung]). Eine Webform besteht aus zwei Teilen, die im Folgenden erklärt werden: visuelle Elemente, die das Aussehen der grafischen Benutzeroberfläche (siehe Kapitel 4.3) beschreiben, und die dazugehörige Programmlogik (siehe Kapitel 4.2). 4.2 Codebehind-Technologie Verbunden wird eine Webform mit ihrer Codebehind-Klasse durch eine so genannte Page-Direktive. Die Codebehind-Klasse, wie in Abbildung 17 dargestellt, ist eine Klasse, die von der Page abgeleitet werden muss. Die Klasse Page stellt Schnittstellen zur Verfügung, um das gewünschte Verhalten der Webform zu implementieren. Der Einstiegspunkt in eine Codebehind-Klasse ist die Methode OnInit. In C# müssen Methoden, die überschrieben werden können, explizit mit dem Schlüsselwort virtual, und wenn sie überschrieben werden, explizit mit dem Schlüsselwort override gekennzeichnet werden. In dem Beispiel von Abbildung 17 werden den Events Load und PreRender jeweils Methoden zugeordnet, die beim Eintreten der entsprechenden Events ausgeführt werden. In Kapitel 4.5 werden der Lebenszyklus und die möglichen Events eines Page-Objekts noch genauer beschrieben. 37 Abbildung 17: Beschreibung der Codebehind-Technologie 4.3 Webforms 4.3.1 Einleitung Eine Webform ist eine Webseite (HTML-Seite) mit einem HTML-Formular, die neben HTML-Elementen und einem HTML-Formular so genannte Server Controls enthält. Server Controls sind grafische Objekte mit Methoden, Properties und Events. Der in dem HTML-Attribut id angegebene Name definiert den Namen des Properties in der entsprechenden Codebehind-Klasse, d. h., auf der Clientseite werden HTML-Elemente angezeigt und in der Codebehind-Klasse erscheinen diese als ”echte Objekte”. Durch diesen Mechanismus wird die in Kapitel 4.1.5 beschriebene Abstraktion realisiert. Die Server Controls werden unterschieden in HTML Server Controls und Web Server Controls. 4.3.2 HTML Server Controls HTML Server Controls repräsentieren HTML-Elemente. Die Attribute der HTMLElemente bilden die Attribute der HTML Server Controls in der Codebehind-Klasse. Wird beispielsweise in der Codebehind-Klasse ein Attribut eines HTML Server Controls geändert, so erscheint beim Client das HTML-Element mit dem geänderten Attribut. 38 Abbildung 18: Zusammenhang von HTML und Server Controls Abbildung 18 soll diese Funktionsweise und den Zusammenhang von HTMLElementen und Properties erklären. Der Client schickt an den Server eine HTTPAnfrage, in der er eine Webseite anfordert. Das ASP .NET Page Framework wandelt die HTML-Elemente in HTML Server Controls Objekte um. Die Codebehind-Klasse besitzt dann für jedes HTML Server Control ein Property, welches den gleichen Namen besitzt wie das Attribut id des HTML-Elements. Die Properties können dabei beliebig geändert werden. Nachdem die Anfrage abgearbeitet wurde, wandelt das ASP .NET Page Framework die Server Controls (mit den geänderten Attributen) in HTML um und schickt das erzeugte HTMLDokument an den Client zurück. Des Weiteren kann ein Server Control Events besitzen. Ein Beispiel ist das HTMLButton Server Control. Dieser besitzt ein Event ServerClick, was ausgeführt wird, wenn der entsprechende Button auf der Clientseite betätigt wurde. Ein weiteres Konzept kann durch den Zustatz runat=”server” im HTML Server Control realisiert werden. Dieser Zusatz bedeutet, dass auf dem Server eine Instanz des entsprechenden Objekts gehalten wird, welche den Zustand des entsprechenden Objekts enthält. In einem ViewState12 wird zu jedem Objekt, was als runat=”server” definiert wurde, eine Referenz abgelegt, die dieses Objekt auf dem Server identifiziert. Damit besteht die Möglichkeit, dass dem Server nur mitgeteilt wird, was an einem Objekt geändert wurde, ohne das komplette Objekt bzw. alle Attribute zu übertragen. 4.3.3 Web Server Controls Die zweite Form von Server Controls sind die Web Server Controls. Während die HTML Server Controls die HTML-Elemente repräsentieren, ist die Vorgehensweise bei den Web Server Controls genau entgegengesetzt. Die Web Server Controls beschreiben komplexe grafische Objekte und die Umwandlung in HTML kann sich 12 Ein ViewState ist eine versteckte Variable, die in einer Webform enthalten ist und zusätzliche Informationen für den Server enthält. 39 über mehrere HTML-Elemente erstrecken. Ein spezielles Web Server Control ist der PlaceHolder, der als Container innerhalb einer Webform verwendet wird. Dieser besitzt eine Methode, um ihn in weitere Server Controls zu laden. Dadurch können dynamisch Inhalte in einer Webform gesetzt werden. Web Server Controls, die mindestens einen PlaceHolder besitzen, werden im Folgenden auch als Templates bezeichnet. Neben den vordefinierten Server Controls besteht auch die Möglichkeit, eigene Server Controls zu entwickeln. Diese werden User Controls genannt. In Kapitel 5.4.5 wird ein Beispiel für die Entwicklung eines User Controls beschrieben. 4.4 Zustandsmanagement In einer Web-Applikation kommuniziert der Client über das zustandslose HTTPProtokoll mit dem Server. Gleiche Serveranfragen von verschiedenen Clients werden nicht unterschieden. Nach der Verarbeitung der Anfrage werden alle Verbindungsdaten verworfen. Bei einer Web-Applikation ist es aber nötig, dass Zustandsinformationen verwaltet werden. ASP.NET bietet dafür verschiedenste Möglichkeiten, die im Folgenden beschrieben werden. Versteckte Formularfelder: Die einfachste Möglichkeit, Zustandsinformationen zu halten, ist es, diese mit jeder Anfrage an den Server in versteckten Formularfeldern mitzuschicken. Die Methode RegisterHiddenField in der Klasse Page bietet die Möglichkeit, versteckte Formularfelder zu definieren, die beim Erzeugen der HTML-Seite mit angelegt werden. Die mitgeschickten Zustandsinformationen sind allerdings im HTML-Code in Klartext sichtbar, was vor allem bei sensiblen Daten sehr nachteilig ist. ViewState: Jede Webform enthält ein verstecktes HTML-Element mit dem Namen VIEWSTATE. In der Page-Klasse wird dieser Viewstate durch ein Property repräsentiert. Auf dieses Property kann in der Codebehind-Klasse zugegriffen werden. Der Vorteil dieser Variante, im Vergleich zu den versteckten Formularfeldern, ist, dass die Daten nicht mehr als Klartext sichtbar sind. Allerdings müssen die Zustandsdaten bei dieser Variante immer noch bei jeder Serveranfrage mitgesendet werden. Session: Eine Session ist der Zeitraum vom ersten Aufruf einer Webseite bis zum Schließen des Webbrowsers. Allerdings kann eine Session auch vorher vom Server beendet 40 werden (beispielsweise wenn ein Timeout abgelaufen ist) oder über das Schließen des Webbrowser hinaus gültig sein, wenn die Sessiondaten im Cookie gespeichert werden. Hierfür bittet die Klasse Page das Property Session an. In diesem Property können Daten, die abhängig von einer Session sind, verwaltet werden, d. h., die Zustandsinformationen werden nicht bei jeder Anfrage mit übermittelt. Application: Informationen können auch über die gesamte Lebenszeit einer Applikation verwaltet werden. Eine Applikation startet, wenn die erste Anfrage an den Server gesendet wird, und endet, wenn die Konfigurationsdaten geändert oder der Serverprozess beendet, wird. Hierfür bietet die Page-Klasse ein Property mit dem Namen Application an. 4.5 Lebenszyklus eines Page-Objekts Um zu verstehen, welche Schnittstellen das ASP.NET Page Framework anbietet, wird in diesem Kapitel der Lebenszyklus eines Page Objekts beschrieben, d. h. was passiert zwischen einer Serveranfrage und dem anschließenden Senden der HTMLSeite (vgl. Kapitel 4.1.1). Wie bereits erwähnt wurde, ist das zentrale Konzept von ASP.NET die Klasse Page. Bei einer Serveranfrage bzw. Anfrage an einer Webform wird eine Instanz der dazugehörigen Codebehind-Klasse erzeugt. Den verschiedenen Events können durch Überschreiben der Methode Init (vgl. Kapitel 4.2) eigene Methoden übergeben werden, die im Folgenden kurz beschrieben werden (vgl. [Esp 04]). In Abbildung 19 ist der Lebenszyklus eines Page-Objekts dargestellt. Nachdem die OnInit-Methode durch das Event Init aufgerufen wurde, werden die übergebenen Variablen ausgewertet. Dies sind zum einen der Viewstate und zum anderen die durch die http-Anfrage übergebenen Variablen. Der Viewstate enthält Referenzen auf die Server Controls, die durch runat=”server” gekennzeichnet wurden. Die Server Controls dieser Referenzen werden geladen. Anschließend werden die durch den Post-Mechanismus übertragenen Formulardaten ausgewertet. Nach Abschluss dieser Phase besitzen die Objekte auf dem Server den gleichen Zustand wie auf dem Client. Anschließend wird das Event Load aufgerufen. Dieses Event ist dafür gedacht, benutzerdesfiniertes Initialisieren vorzunehmen. Das Laden der User Controls in die Templates ist ein Beispiel dafür. Des Weiteren können Attribute initialisiert werden. Diesem Event wird üblicherweise eine Methode Page Load übergeben. 41 Abbildung 19: Lebenszykus eines Page-Objekts Die Benutzeraktionen (Betätigen eines Buttons oder das Ändern einer Auswahl in einer Dropdownliste, sofern dies definiert wurde) werden in der nächsten Phase ausgewertet. Den Events der Server Controls können zuvor Methoden übergeben worden sein, die in dieser Phase ausgewertet werden. Wurde eine Seite angefragt, weil ein Benutzerevent ausgeführt wurde, so spricht man auch von Postback. In der Page-Klasse steht hierfür ein Property zur Verfügung, mit dem geprüft werden kann, ob eine Seite durch einen Postback aufgerufen wurde. In diesem Fall müssen dann eventuelle Initialisierungen nicht mehr vorgenommen werden. Bevor die HTML-Seite zusammengebaut wird, wird das Event PreRender geworfen. Dieses Event wird nach den Benutzeraktionen ausgeführt und kann beispielsweise abhängig von diesen bestimmten Ausgaben erzeugen. Die übliche Methode für dieses Event ist eine Methode mit dem Namen PreRender. Im letzten Schritt wird der ViewState zusammengesetzt, d. h., die in dem Property ViewState enthaltenen Daten werden als String kodiert, die HTML-Seite wird zusammengesetzt und die zuvor angeforderten Ressourcen werden freigegeben. 42 5 5.1 Architektur und Entwurf der Webapplikation Einleitung Im objektorientierten Entwurf wird für das aus der Analyse spezifizierte System ein abstraktes Implementierungskonzept erstellt. Der Entwurf sollte die Analyse erweitern und unabhängig von der Implementierung sein (siehe auch [Bit Koc 00, S. 47]). In diesem Fall war dies allerdings in der Form nicht möglich. Die Struktur der Zeiterfassung soll neben den Benutzermöglichkeiten einen Vergleich von den in der Einleitung vorgestellten Datenbanktechniken ermöglichen. Dieser Aspekt war bei der Analyse nicht relevant, muss aber im Entwurf berücksichtigt werden. Aus diesem Grund kann auch das in Kapitel 3.3.1 dargestellte Klassendiagramm im Entwurf nicht erweitert werden. Zu diesem Zweck wurde eine Framework entwickelt, was diesen Vergleich ermöglichen soll. Die Idee für diese Struktur stammt von einem Persistenz Framework, das in der Firma Francotyp Postalia entwickelt wurde. Die Architektur der Zeiterfassung wird in Kapitel 5.2 beschrieben. In Kapitel 5.3 wird detaillierter auf die Struktur des entwickelten Frameworks eingegangen. Ein weiterer Punkt für das geänderte Vorgehen ist der, dass die Zeiterfassung das ASP .NET Framework verwenden soll. Hierbei können nur die vordefinierten Schnittstellen verwendet werden, was beim Entwurf ebenfalls berücksichtigt werden muss. Dieser Aspekt muss vor allem bei dem Entwurf des Web-Interfaces betrachtet werden. Das Web-Interface bildet die Schnittstelle zwischen Benutzer und Businesslogik (siehe Kapitel 5.4). Das .NET Framework bietet zwar ein Konzept für das Zustandsmanagement (vgl. Kapitel 4.4) an, aber stellt keine Technik zur Verfügung, um die Navigation durch die Webseiten zu steuern. Der Entwurf für die angewandte Technik des Zustandsmanagements und die Navigation werden in Kapitel 5.5 beschrieben. Ein weiteres Problem, was gelöst werden muss, ist die Authentifizierung der Benutzer und die Definition der Zugriffsmöglichkeiten. In Kapitel 3.2 wurde beschrieben, welche Benutzerrollen existieren und welche Möglichkeiten diese haben. Hierfür wird der integrierte Windows Authentifizierungsmechanismus des .NET Frameworks verwendet. Dieser wird in Kapitel 5.6 dargestellt. Abgeschlossen wird das Kapitel Entwurf mit einem Überblick über das gesamte System (siehe Kapitel 5.7). Dort werden die vorgestellten Entwürfe zusammengeführt. Außerdem werden in diesem Kapitel einige weitere Probleme, wie beispielsweise die Nebenläufigkeit, kurz angesprochen. 43 5.2 Architektur Die Zeiterfassung besteht, wie in Abbildung 20 dargestellt, aus fünf Komponenten. Jede Komponente ist gleichzeitig ein eigenes Assembly und besitzt einen eigenen Namespace (vgl. Kapitel 4.1.3). Abbildung 20: Struktur der Komponenten Die Komponente ProjectManagement bildet die Schnittstelle zwischen Benutzer und Businesslogik. Nach dem Model View Controller Design Pattern nimmt diese Komponente die Rollen Controller und View ein und realisiert das Web-Interface. Im Kapitel 5.4 wird die Struktur detaillierter beschrieben. Die Businesslogik besteht aus den folgenden zwei Komponenten: 1. Die Komponente ProjectManagement.Core ist ein Framework, welches persistente Objekttypen und ihre Managerklassen als abstrakte Klassen definiert (siehe Abbildung 20). Managerklassen sind Klassen, die persistente Objekte eines bestimmten Typs verwalten. Für jede Entität existiert ein Typ eines persistenten Objekts und ein dazugehöriger Manager. Diese beiden stehen miteinander in Beziehung. Der detaillierte Aufbau dieses Frameworks wird in Kapitel 5.3 beschrieben. 2. Die konkrete Implementierung mit der jeweiligen Datenbanktechnik wird in der spezifischen Komponente (siehe Abbildung 21) realisiert. Für jede Managerklasse und jedes persistente Objekt muss eine spezifische (abgeleitete) Klasse definiert werden, welche die definierten abstrakten Methoden implementiert. 44 Komponente: ProjectManagement. Datenbanktechnik Realisierung Core.Relational relational s. Kapitel 6 Core.ObjectRelational objektrelational Theorie in Kapitel 7 Core.ObjectOriented objektorientiert Idee Abbildung 21: Übersicht der spefizischen Komponenten 5.3 5.3.1 Persistenz-Framework Einleitung Das entwickelte Framework wird als Persistenz Framework bezeichnet, da es persistente Objekte verwaltet. In dem ”echten” Persistenz-Framework (siehe Kapitel 5.1), was die Motivation für diese Struktur war, werden die entsprechenden Datenbankoperationen automatisiert, d. h., über Reflexion werden die Attribute der Objekte ausgelesen und über Umwandlungsroutinen in Datenbankoperationen umgewandelt. Da das ”echte” Persistenz-Framework ziemlich komplex in seiner Struktur und Anwendung ist, wurde, wie bereits erwähnt, nur die Idee übernommen. Ziel der Zeiterfassung ist die Verwaltung von persistenten Objekten verschiedenster Typen, wie beispielsweise Projekte, Mitarbeiter oder Fachgruppen. Die benötigten Operationen lassen sich dabei in zwei Arten unterscheiden: 1. Operationen, die direkt an einem persistenten Objekte ausgeführt werden, um beispielsweise den Zustand eines Objekts zu ändern (siehe PersistentObject in Abbildung 22), und 2. Operationen, die eine bestimmte Menge von Objekten eines bestimmten Typs zurückliefern oder auf einer Menge von Objekten eines bestimmten Typs ausführen werden. Ein Beispiel ist eine Anfrage nach allen Projekten, die keine Fachgruppen besitzen. Diese Operationen werden in den bereits erwähnten Managerklassen realisiert (siehe PersistentManager in Abbildung 22). Die Klassen ProjectManagerImpl, ControllerImpl und ProjectImpl in Abbildung 22 zeigen ein Beispiel für Klassen, die in einer der drei spezifischen Komponenten, wie beispielsweise ProjectManagement.Core.Relational, realisiert werden. Anhand des Beispiels Project und ProjectManager wird im Folgenden die abstrakte Managerklasse (PersistentManager, siehe Kapitel 5.3.3) mit ihren spezifischen Managerklassen beschrieben. Mit spezifischen Managerklassen sind in diesem Fall Klassen gemeint, die in der Komponente ProjectManagement.Core enthalten und von PersistentManager abgeleitet sind, wie in Abbildung 22 die Klasse ProjectManager. Diese Klassen sind abstrakt und müssen in den konkreten Managern implementiert werden. Konkrete Manager sind Klassen, die von den spezifischen Managerklassen abgeleitet sind und in der konkreten Komponente (siehe Abbildung 45 Abbildung 22: Struktur des Persistenz Frameworks am Beispiel Projekt 21) die jeweiligen Funktionalitäten implementieren. Die Formulierung spezifisch und konkret wird auch für persistente Objekte (PersistentObject, siehe Kapitel 5.3.3) und die Schnittstelle (Controller, siehe Kapitel 5.3.4) zur Komponente ProjectManagement verwendet. Abgeschlossen wird das Kapitel in 5.3.5 mit einem Überblick der vorhandenen persistenten Objekte der Zeiterfassung. 5.3.2 Persistenz Manager Erzeugt werden persistente Objekte durch ein Factory Pattern, welches in der in Abbildung 22 dargestellten Struktur enthalten ist. In Abbildung 23 sind die Rollen des Factory Patterns und die zugehörigen Klassen des entwickelten Frameworks dargestellt. Die Methode CreateObject im PersistentManager hat die Rolle der Methode FactoryMethode im Factory Pattern. In der konkreten Implementierung der Managerklasse erzeugt diese Methode eine Instanz des konkreten PersistentObjects. Das Erzeugen eines solchen Objekts darf nur über diese Methode erfolgen. Dadurch ”kennt” jeder Manager den Typ seines persistenten Objekts (siehe Abhängigkeit persistentObject in Abbildung 22). 46 Klassen im Factory Pattern Klassen im Persistenz-Framework Creator PersistentManager ConcreteCreator spezifische Implementierung der Managerklasse Product PersistentObject ConcreteProduct spezifische Implementierung des PersistentObjects Abbildung 23: Rollen des Factory Patterns im Persistenz-Framework Der Indexer (vgl. Kapitel 4.1.4) im PersistentManager ermöglicht es, einen spezifischen PersistentManager wie ein Array zu verwenden. Jedes konkrete persistente Objekt besitzt eine Identität in Form einer Zahl. Im Indexer kann anhand dieser Zahl ein konkretes Objekt ermittelt werden. Existiert kein Objekt zu der übergebenen Zahl, so wird ein Null Pointer zurückgeliefert. Der Indexer ist abstrakt und muss in der konkreten Komponente bzw. im konkreten Manager realisiert werden. Der Indexer erlaubt nur lesende Zugriffe, da das Einfügen, Ändern und Löschen von persistenten Objekten an den persistenten Objekten selber durchgeführt wird. Wenn ein Objekt mit der Identität 42 existiert, dann würde der Aufruf Controller.ProjectManager[42] dieses Objekt zurückliefern. Die Methoden Insert, Update und Delete werden im PersistentManager definiert und müssen in der konkreten Implementierung der Managerklasse realisiert werden. Der Zugriff auf diese Methode erfolgt aber über die persistenten Objekte. In Kapitel 5.3.3 wird der Ablauf genauer beschrieben. Durch die Methode LoadArrayList wird eine Array mit allen Objekten des jeweiligen Typs zurückgeliefert. In den spezifischen Managerklassen können weitere abstrakte Methoden definiert werden, die beispielsweise die Ergebnismenge einschränken oder andere Funktionalitäten auf der Menge der persistenten Objekte definieren. Die Methode GetNewProjectNumber (siehe Abbildung 22) ist ein Beispiel für eine weitere Methode. Abhängig vom Projekttyp wird durch diese eine neue vorgeschlagene Projektnummer ermittelt (vgl. Kapitel 3.2.1 das Beispiel Tilgung). 5.3.3 Persistente Objekte Wie bereits in Kapitel 5.3.2 erwähnt wurde, ist das Einfügen, Ändern und Löschen eine Eigenschaft des persistenten Objekts. Diese Methoden leiten die Anfragen an ihren jeweiligen Manager (siehe Insert, Update und Delete in Abbildung 22 auf Seite 46 in der Klasse PersistentObject). In Abbildung 24 ist der Ablauf für das Einfügen eines persistenten Objekts dar47 Abbildung 24: Einfügen eines persistenten Objektes gestellt. Die Methode CreateObject erzeugt lediglich eine neue Instanz des jeweiligen Objekts mit einer Verbindung zu seinem Manager. Persistent im eigentlichen Sinne, d. h. dass diese Daten beispielsweise auch in der Datenbank abgelegt werden, ist dieses Objekt in diesem Zustand noch nicht. Erst durch Aufrufen der Methode Insert werden diese Objekte in der entsprechenden Datenbank hinzugefügt. Diese Methode liefert ein Boolean zurück. Im Falle eines Fehlers wird false zurückgeliefert. Durch das Property CurrentError wird in diesem Fall die Fehlermeldung ermittelt. Wie bereits erwähnt wurde, besitzt jedes persistente Objekt eine Identität in Form einer Zahl. In Kapitel 6.2.2 wird noch auf die Schwierigkeiten bei diesem Vorgehen eingegangen. Darüber hinaus besitzt jedes persistente Objekt einen Namen (siehe Property Name in Abbildung 22). Die Realisierung dieses Namens kann in den jeweiligen konkreten persistenten Objekten unterschiedlich aussehen. Bei einem Mitarbeiter ist dieser beispielsweise eine Kombination aus Vor- und Nachname, während dieser für ein Projekt der Name des Projektes ist. Die Informationen, die in einem spezifischen persistenten Objekt gespeichert werden, lassen sich in zwei Arten unterscheiden: Zum einen sind dies einfach Daten, die in Form von Properties definiert werden. Beispiele hierfür im Projekt sind der Projektstart (statedDate) oder die Bemerkung zum Projektabschluss (finishComment). Die zweite Art von Informationen sind Abhängigkeiten zu anderen persistenten Objekten, wie beispielsweise ein Projektleiter (projectLeader ) in einem Projekt, der ein Mitarbeiter (Employee) ist. Ein Überblick aller persistenten Objekte und ihrer Abhängigkeiten zueinander wird in Kapitel 5.3.5 dargestellt. In den spezifischen persistenten Objekten können weitere Methoden definiert werden. Wie in Abbildung 22 auf Seite 46 zu sehen ist, besitzt die Klasse Project 48 eine Methode Close, welche ein Projekt mit einem Datum und einer Bemerkung zum Abschluss beendet. Ab dem definierten Datum ist das Projekt in der Projektliste nicht mehr sichtbar und kann nur noch über die Berichte angezeigt werden. Die Funktionalitäten für die prozentuale Zeitverteilung der Mitarbeiter auf die Projekte wurden als Methoden des Projektes definiert. Ähnlich zu dem Einfügen, Ändern und Löschen eines Objekts werden diese Methoden auf dem jeweiligen Objekt aufgerufen und in dem entsprechenden Manager implementiert. 5.3.4 Die Klasse Controller Bisher wurden nur die Managerklassen und ihre persistenten Objekte beschrieben. In diesem Abschnitt geht es darum, diese zusammenzuführen und eine Möglichkeit zur Initialisierung des Frameworks zu geben. Die dafür verantwortliche Klassen sind die Klassen Controller und ControllerImpl (siehe Abbildung 22 auf Seite 46). Abbildung 25: Die Klasse Controller mit zwei Beispielmanagern Die Klasse Controller besitzt zu jeder abstrakten Managerklasse einen Property (siehe Abbildung 25). Die Komponente ProjectManagement (siehe Abbildung 22) kann über den Controller auf diese Properties der jeweiligen Manager zugreifen. Der Konstruktor der Klasse Controller ruft eine abstrakte Methode Init auf. Um das Framework zu initialisieren muss von der Klasse Controller eine abgeleitete Klasse definiert werden (ControllerImpl ), welche die Methode Init implementiert. In dieser Methode werden Instanzen der konkreten Managerklassen erzeugt und an die 49 Properties bzw. an die dahinter liegenden Attribute gebunden. Durch eine Instanz dieser abgeleiteten Klasse stehen dem Anwender - in diesem Fall der Komponente ProjectManagement - alle Manager zur Verfügung. 5.3.5 Zusammenfassung und Übersicht über alle persistenten Objekte Abhängig von der jeweiligen Datenbanktechnik wird eine Komponente erstellt, die das entwickelte Framework verwendet. Dieses Framework definiert für jede Entität ein Paar aus (persistenten) Managern und persistenten Objekten. In diesen Klassen werden abstrakte Methoden definiert, die jeweils in die konkreten Klassen implementiert werden. Die Klasse Controller besitzt für jeden Manager einen Property, auf den die Komponente ProjectManagement (also das Web-Interface) zugreifen kann. Initialisiert wird das Framework durch eine konkrete Controllerklasse, welche konkrete Instanzen der Managerklassen an die Properties binden. Einfügen, Ändern und Löschen von persistenten Objekten geschieht über Methoden an den Objekten selber, während Operationen, die sich auf Mengen von persistenten Objekten beziehen, in den Managern aufgerufen werden. Die beiden in Abbildung 25 dargestellten Managerklassen haben noch eine weitere Bedeutung. Die Arbeitszeiten der Mitarbeiter und die prozentualen Verteilungen dieser auf Projekte, Fachgruppen und Aufgabenkataloge sind abhängig von der Kalenderwoche. Beim Starten einer Session (siehe Kapitel 4.4 auf Seite 40) müssen die Kalenderwocheneinträge in der jeweiligen Datenbank aktualisiert (UpdateWeeks) werden. Dieses Thema wird in Kapitel 5.5.2 noch beschrieben. Die Klasse Employee besitzt außerdem eine Methode SelectEmployeeByAccount, die abhängig von einem übergebenen Account einen Mitarbeiter zurückliefert. Die Problematik mit der Authentifizierung der Mitarbeiter wird in Kapitel 5.6 auf Seite 60 noch beschrieben. In Abbildung 26 ist die Struktur der persistenten Objekte mit ihren Abhängigkeiten dargestellt. Wie an dieser Abbildung zu sehen ist, können erst die konkreten persistenten Objekte auf die jeweils abhängigen persistenten Objekte zugreifen, d. h., diese müssen in jeder konkreten Komponente implementiert werden. Ein weiteres Problem stellt die fehlende Vererbung dar. Dadurch, dass jedes persistente Objekt direkt oder indirekt von PersistentObject abgeleitet werden muss, besteht keine Möglichkeit, Vererbung in den persistenten Objekten in der konkreten Komponente zu verwenden. 50 Abbildung 26: Klassendiagramm der persistenten Objekte 5.4 5.4.1 Entwurf des Web-Interfaces Einleitung Im Folgenden wird das Web-Interface beschrieben. In der Komponentenstruktur aus Abbildung 20 in Kapitel 5.2 ist dies die Komponente ProjectManagement. Die Zeiterfassung besteht aus einer einzigen Webform und einer dazugehörigen CodeBehind Klasse, die in Kapitel 5.4.2 beschrieben wird. Eine Web-Applikation besitzt einige Besonderheiten im Vergleich zu einer nicht Web-Applikation, die beim Design berücksichtigt werden müssen. Diese werden in Kapitel 5.4.3 aufgezeigt. Wie bereits in Kapitel 5.2 beschrieben wurde, werden in der Zeiterfassung persistente Objekte verwaltet. Diese müssen erzeugt, geändert, gelöscht und angezeigt werden. Dafür wird meist ein Datagrid verwendet. In Kapitel 5.4.4 wird an einem Beispiel die Verwendung eines Datagrids beschrieben. Ein Beispiel für die Entwicklung eines User Controls, was in der Zeiterfassung benötigt wird, wird in Kapitel 5.4.5 beschrieben. 5.4.2 Struktur der GUI Die Benutzeroberfläche besteht, wie in Abbildung 27 dargestellt ist, aus drei PlaceHoldern: 51 Abbildung 27: Seitenaufbau der Default-Webform PhHead In den PlaceHolder PhHead wird eine konstante UserControl eingefügt, die ein Firmenlogo und ein Logo der Applikation enthält. PhNavigation In den PlaceHolder PhNavigation wird das UserControl Navigator/Main hineingeladen, das abhängig von den Benutzerrechten des aktuellen Benutzers alle ihm verfügbaren Menüpunkte anzeigt. Auf die Benutzerrechte wird in Kapitel 5.6 genauer eingegangen. PhContent Der interessante Teil ist der PlaceHolder PhContent, der abhängig vom Benutzerzustand eine entsprechende UserControl enthält. Diese kann weitere PlaceHolder enthalten, die wiederum UserControls besitzen. Eine sprachliche Beschreibung, in welchem Zustand sich der Benutzer in der Zeiterfassung zum aktuellen Zeitpunkt befindet, wird in LHead dargestellt. Die Steuerung der Benutzeroberflächen wird in Kapitel 5.5.1 beschrieben. Fehlermeldungen und Benutzerhinweise werden in dem Label LInfo dargestellt. Abbildung 28 zeigt die entsprechende Klassenstruktur zu der grafischen Benutzeroberfläche aus Abbildung 27. Die Webform Default wird dabei in zwei Klassen modelliert, welche die Stereotypen (siehe auch [UML]) ClientPage und ServerPage besitzen. Diese beiden Klassen zeigen den serverseitigen (ServerPage) und den clientseitigen (ClientPage) Aspekt dieser Webform (vgl. [Con 99]). Der serverseitige Aspekt besitzt beispielsweise einen direkten Zugriff auf die Businesslogik und damit auch die Datenbank, während die clientseitige Webform diese nur über die serverseitige Webform erreichen kann. Beim Ausführen von Funktionalitäten muss außerdem unterschieden werden, ob diese auf dem Client (beispielsweise durch Javascript) oder auf dem Server ausgeführt wird. 52 Abbildung 28: Die Webform Default und die Codebehind-Klasse PageFrontdoor Das HTML-Formular in der Webform wird durch eine Aggregationsbeziehung modelliert, d. h., die Webform aus clientseitiger Sicht enthält ein Formular, was wiederum Attribute (die HTML- bzw. Webform-Elemente) besitzt. Die Verbindung zwischen der serverseitigen und der clientseitigen Webform wird durch eine Assoziation mit dem Stereotypen Build modelliert. Diese modelliert das Erzeugen einer clientseitigen Webform bzw. Webseite. 5.4.3 Problem bei Web-Applikationen Eine Eigenschaft, die eine Web-Applikation im Vergleich zu anderen Applikationen besitzt, ist die, dass der Client ein Web-Browser ist. Während in einer Nicht-WebApplikation die Möglichkeiten des Benutzers ziemlich genau eingegrenzt werden, müssen bei einer Web-Applikation die Möglichkeiten des Browsers mit berücksichtigt werden. In Abbildung 29 sind einige Beispiele hierfür darstellt. Aus diesem Grund wurde eine Lösung mit nur einer Frame entwickelt und die Applikation besitzt lediglich einen Einstiegspunkt. Den ”Zurück”-Button vollständig abzufangen ist nicht möglich. In vielen Fällen führt dieser aber in ASP.NET zu einem Fehler, auf den entsprechend reagiert werden kann (siehe Kapitel 5.5.1). Die Benutzermöglichkeiten werden auf Buttons und Javascript-Events beschränkt, damit besteht (fast) keine Möglichkeit, mehrere unkontrollierte Instanzen des Browsers zu erzeugen. Für jede neue Instanz wird eine eigene Session erzeugt, damit sind zwei Instanzen auch zwei unabhängige Benutzer in der Web-Applikation. 53 • Die Webseiten können direkt aufgerufen werden, damit sind beliebige Einstiegspunkte in die Applikation möglich. • Durch den ”Zurück”-Button besteht immer die Möglichkeit, auf vorherige Seiten zuzugreifen. Bei einer Nicht-Web-Applikation ist dies nur möglich, wenn diese Funktionalität explizit implementiert wurde. Wenn der Browser diese Seite dann auch noch aus dem Cache holt, besteht ein weiteres Problem. Eine Seite, die vielleicht durch einen Lock gesperrt und wieder freigegeben wurde, ist für den Client sichtbar, ohne dass der Lock erneut gesetzt wurde. • Durch Erzeugen einer neuen Browser-Instanz können mehrere Instanzen der Applikation parallel laufen. Der Server kann nicht unterscheiden, wann eine weitere Instanz gebildet und von welcher eine Anfrage gestellt wurde. • Bei der Verwendung von Frames werden mehrere unabhängige Instanzen des Browsers erzeugt, was zu weiteren Problemen führen kann. Die Zustände der Frames müssen u. U. zueinander bestimmte Bedingungen erfüllen, die nur schwer einzuhalten sind. Ein weiteres Problem ist, dass nur ein einziges Frame abstürzen kann und somit die Applikation unvorhersehbare Zustände erreichen kann. Abbildung 29: Eigenschaften einer Web-Applikation 5.4.4 Verwendung eines Datagrids Ein Beispiel für ein ServerControl ist das Datagrid. Mit dem Datagrid können, wie in Abbildung 30 dargestellt ist, Datenmengen in Tabellenform angezeigt werden. Aus der Sicht des Servers ist ein Datagrid ein Objekt. Dieses besitzt verschiedene Properties, Methoden und Events. Die Spalten können dabei mithilfe von Flags einund ausgeblendet werden. Abbildung 30: Beispielanwendung für ein Datagrid 54 Die Spalten können in einem Datagrid mit verschiedenen Spaltentypen definiert werden, die im Folgenden, an dem Beispiel von Abbildung 30, beschrieben werden. Wie bereits in Kapitel 5.3.3 beschrieben wurde, besitzt jedes persistente Objekt eine Identität, die in der ersten Spalte des Datagrids gesetzt und für die Ansicht ausgeblendet wird. Über diese Spalte können die Objekte bzw. Zeilen identifiziert werden. Die einzelnen Zeilen des Datagrids besitzen zwar eine eigene Nummerierung, da diese aber automatisch vergeben wird und nicht geändert werden kann, musste auf eine versteckte Spalte zurückgegriffen werden. Diese Spalten (BoundColumn) werden auch für die Darstellung der übrigen Daten (in diesem Fall nur Status) verwendet. Eine weitere Spaltenart ist die Buttonspalte (ButtonColumn). Das Datagrid bietet für solche Spalten ein Event an. Über Delegation kann diesem Event eine Methode übergeben werden. Beim Werfen dieses Events (also beim Betätigen des Buttons) kann durch die mitgegebene Methode entsprechend reagiert werden. In diesem Fall wird eine neue Benutzeroberfläche für die Arbeitszeitverteilung auf Projekte des ausgewählten Mitarbeiters angezeigt. Die Eingabefelder (Arbeitszeit) stellten im Datagrid eine Schwierigkeit dar. Das Datagrid stellt dafür keine eigene Spaltenart zur Verfügung. In diesem Fall wurde eine Template-Spalte (TemplateColumns) definiert, in der das entsprechende Eingabefeld einfügt wurde. Damit ist es Bestandteil einer Zeile (Item) und kann über die Methode FindControl des Items ermittelt werden. Aus der Sicht des Clients ist ein Datagrid eine HTML-Tabelle, welche Daten, Eingabefelder und Buttons enthält. Die Zusammengehörigkeit dieser Daten existiert im HTML nicht. Wird beispielsweise ein Button betätigt, so wird eine Anfrage an den Server gesendet und die HTML-Elemente werden wieder zu einem DatagridObjekt ”zusammengesetzt”. 5.4.5 Entwurf eines User Controls ASP.NET stellt zwar ein Kalender Server Control zur Verfügung, mit dem ein Datum ausgewählt bzw. angezeigt werden kann, bietet aber keine Möglichkeit, ein Datumsfeld in einfacher und weniger Platz raubenden Form darzustellen, wie in Abbildung 31 zu sehen ist. Abbildung 31: Beispiel für ein User Control Abbildung 32 zeigt die dazugehörige Klasse, die von der Klasse UserControl abgeleitet werden muss und die OnInit-Methode überschreibt. In der OnInit-Methode 55 wird dem Load - bzw. PreRender -Event über Delegation eine entsprechende Methode übergeben. Abbildung 32: Klasse DateControl Das voreingestellte bzw. angezeigte Datum wird dabei in Attributen gespeichert und kann über die entsprechenden Properties gelesen werden. Das Ändern des voreingestellten Datums geschieht durch die überladene Methode SetDefaultDate. Ein Problem stellt hierbei der angezeigte Jahreszahlenraum dar. Ein Geburtsdatum besitzt beispielsweise einen anderen Jahreszahlenraum wie das Jahr eines Projektstarts. Die Methode SetYearLimit setzt diesen Jahreszahlenraum. Abbildung 33: Sequenz Diagramm zum DateControl am Beispiel Mitarbeitereingabemaske In Abbildung 33 ist eine beispielhafte Anwendung für ein UserControl dargestellt. Für jeden angelegten Mitarbeiter wird ein Datum der Aktivierung festgelegt. 56 Da ein Objekt vom Typ DateControl auch als Kopie auf dem Server gehalten wird, muss das voreingestellte Datum nicht bei jeder Ausgabe neu geladen werden, d. h., eine wiederholte Anfrage (IsPostBack ) desselben UserControls muss das Datum des Mitarbeiters nicht erneut ermitteln. Wird die Methode SetYearLimit nicht aufgerufen, so wird ein voreingestellter Jahreszahlenbereich von [aktuelles Jahr -5; aktuelles Jahr +5] definiert, bzw. wenn ein voreingestelltes Datum mit einem Jahr gesetzt wird, wird der Jahreszahlenbereich entsprechend erweitert. 5.5 5.5.1 Zustandsmanagement PageNavigator Wie in Kapitel 4.4 beschrieben wurde, stellt das ASP.NET Page Framework verschiedenste Mechanismen zur Verfügung, um Zustandsinformationen zu verwalten. Jeder Benutzer, der die Web-Applikation startet, d. h. die Web-Applikation im WebBrowser aufruft, erhält vom ASP.NET Page Framework eine eindeutige Session zugewiesen. Damit hat die Web-Applikation die Möglichkeit, die Anfragen der verschiedenen Benutzer zu unterscheiden. Wie in Abbildung 28 auf Seite 53 zu sehen war, stellt die Klasse Page eine Property mit dem Namen Session zur Verfügung. Zu jeder Session wird ein Session Objekt erzeugt, an das über einen Indexer verschiedene Werte gebunden werden können. Die verschiedenen Zustände der Benutzer in der Web-Applikation müssen in irgendeiner Form unterschieden werden. Wie bereits erwähnt wurde, stellt ASP.NET dafür keine Technik zur Verfügung. Die Klasse PageNavigator, wie in Abbildung 34 dargestellt ist, ist für die Steuerung der Benutzerzustände zuständig. Eine Instanz der Klasse PageNavigator, oder einer spezifischen Form davon, wird an das Session Objekt gebunden bzw. wird diesem zugewiesen. Abhängig davon, in welchem Funktionsblock sich der Benutzer aktuell befindet, wird jeweilig eine der in Abbildung 34 dargestellten spezifischen PageNavigator Objekte erzeugt. Jeder Funktionsblock verwaltet in irgendeiner Form persistente Objekte, die eine Identität besitzen. Das Property ID in der Klasse PageNavigator hat dabei folgende Bedeutung: ID = -1 Es wurde kein persistentes Objekt ausgewählt, d. h., die Liste oder Tabelle der persistenten Objekte wird angezeigt. ID = 0 Der Benutzer befindet sich in einem Zustand, in dem er eine Eingabemaske sieht, um ein neues Objekt dieses Typs anzulegen. 57 Abbildung 34: Beispielklasse des PageNavigators zur Steuerung der Benutzeroberfläche ID > 0 Der Benutzer hat ein bestimmtes Objekt mit der Identität ID ausgewählt, um etwas damit zu tun. Im einfachsten Fall möchte er es bearbeiten und sieht eine Eingabemaske mit den änderbaren Daten. Abbildung 35: Abhängig vom PageNavigator werden die jeweiligen Templates geladen Wie in Abbildung 35 an dem Beispiel Administration zu sehen ist, wird abhängig von dem Property ID eines der beiden Templates in das Haupt Template (PhAdminContent) der Administration geladen. Der Zustand ID > 0 ist in diesem Fall nicht möglich, da diese Entitäten nicht geändert werden dürfen. Eine weitere Gemeinsamkeit aller Funktionsblöcke ist die, dass jeder Funktionsblock ein Haupt Template besitzt. Der Name dieses Templates wird durch das Property Content ausgelesen und im Konstruktor des jeweiligen PageNavigators gesetzt. 58 Abhängig von den jeweiligen Funktionsblöcken und Zuständen darin werden weitere Properties definiert, welche den Aufbau der Oberfläche beschreiben. Ein Beispiel dafür ist das Property AdminKind in AdminNavigator. AdminNavigator beschreibt den Aufbau der Administrationsoberfläche. Dort können Kostenstellen, Projekttypen, Projektgruppen und Aufgabenkataloge verwaltet werden. Das Property AdminKind beschreibt, in welchem dieser vier Zustände sich der Benutzer aktuell befindet, oder ist NULL, wenn die Begrüßungsseite der Administration angezeigt wird. Abbildung 36: Beispiel für Zustandsänderung mit PageNavigator Das Beispiel aus Abbildung 36 soll diesen Mechanismus erklären (vgl. dazu auch Abbildung 34): Der Benutzer betätigt den Navigationsbutton ”Administration” (Event ButtonAdminClick in Abbildung 36) und gelangt in den Zustand ShowAdminMenu. In diesem Zustand steht dem Benutzer ein Untermenü mit den oben genannten Administrationspunkten zur Verfügung (vgl. in Abbildung 34 mit Enumeration AdminKind ). Betätigt der Benutzer den Untermenüpunkt Kostenstelle (Event ButtonCostCenterClick in Abbildung 36), so wird AdminKind auf COSTCENTER gesetzt. In diesem Zustand sieht der Benutzer einen Button mit der Aufschrift ”Eine neue Kostenstelle anlegen”, welcher beim Betätigen das Event ButtonNewCostCenterClick wirft und ID auf 0 setzt. Da mit jeder Serveranfrage auch die Session Informationen mitgeschickt werden, ”kennt” die Web-Applikation ebenfalls das PageNavigator -Objekt und kann, abhängig vom Zustand des PageNavigator -Objekts, die entsprechenden UserControls ”zusammensetzen”. 59 5.5.2 Start einer Session Eine weitere Besonderheit bei einer Web-Applikation ist die Tatsache, dass diese Applikation nur läuft, wenn entsprechende Anfragen an den Server gesendet werden. Eine Web-Applikation ist demnach keine Applikation, die als dauerhafter Prozess läuft und somit z. B. nach definierten Zeiträumen bestimmte Aktualisierung vornehmen kann. Abbildung 37: Sequenz Diagramm für das Starten einer Session Ein Problem stellen dabei die Kalenderwochen in der Datenbank dar. Die Verteilung der Arbeitszeit auf die Projekte wird wochenweise durchgeführt. Für jede abgelaufenen Woche muss in der Datenbank eine neue Woche angelegt werden. Es besteht zwar die Möglichkeit, diese erst zu aktualisieren, wenn sie entsprechend benötigt wird, da dies aber an verschiedensten Stelle nötig ist, wurde die Aktualisierung, wie in Abbildung 37 zu sehen ist, beim Starten einer Session durchgeführt (in der Klasse Global wird das Event Session Start geworfen). Die Authentifizierung des Benutzers bzw. Mitarbeiters (SelectEmployeeByAccount) wird im folgenden Kapitel beschrieben. 5.6 Benutzerrechte In diesem Kapitel geht es darum, die Mitarbeiter bzw. die Benutzer in der Zeiterfassung zu authentifizieren. Authentifizierung ist die Überprüfung der Identität eines Benutzers. Die integrierte Windows-Authentifizierung (vgl. [GotDotNet]) von ASP.NET bietet die Möglichkeit, auf die Daten der NT-Konten der Benutzer zuzugreifen. Da sich jeder Mitarbeiter in der Firma FP an seinem Arbeitsplatzrechner authentifizieren muss, bot sich diese Technik an. Der Browser kommuniziert dabei mit dem Server in einer verschlüsselten Form, wobei das Passwort selber nicht übertragen wird (siehe [Loh 03, Kap. 13]). 60 Wird die Zeiterfassung gestartet, so werden die Authentifizierungsdaten an den Server gesendet und sofern dieser Benutzer berechtigt ist, bekommt er den Zugang zum System. Zunächst wurde in der Analyse von einer eigenständigen Authentifizierung ausgegangen, d. h., zu jedem Mitarbeiter wird ein Passwort angelegt. Dafür muss eine entsprechende Authentifizierungsmaske entwickelt werden. Dabei mussten verschiedene Probleme berücksichtigt werden: Wer darf das Passwort sehen? Wird das Passwort verschlüsselt und wenn ja mit welchem Verfahren? Was passiert, wenn ein Benutzer sein Passwort vergessen hat? usw. Die bis dahin beschriebenen Anforderungen mussten geändert werden. Wie sich bei weiteren Befragungen herausgestellt hat, besitzt der Benutzer nicht nur ein NTKonto, sondern beliebig viele, d. h., für jeden Benutzer wird eine Menge von Konten bzw. Accounts angelegt (vgl. mit Abbildung 8 auf Seite 28 und siehe auch EmployeeAccount in 55 auf Seite 85). Diese Lösung funktioniert nur unter einigen Voraussetzungen. Da der Benutzer über das NT-Konto authentifiziert wird, muss ein entsprechendes auch in der Domäne existieren. Ein Problem bei diesem Mechanismus ist die Abhängigkeit zu einem Windowsserver. Außerdem muss der Browser ein Internet Explorer sein. Da diese Bedingungen in der Zeiterfassung aber erfüllt waren, stellt dieser Mechanismus eine gute Lösung dar. Im Namespace System.Security.Principal stellt ASP.NET eine Klasse WindowsIdentity zur Verfügung, die einen Windowsbenutzer repräsentiert. Über diese Klasse wird der Benutzername des NT-Kontos (Account) des Benutzers ermittelt. Beim Event Session Start in der Klasse Global wird zu dem Account ein entsprechender Benutzer ermittelt (siehe SelectEmployeeByAccount in 5.3.5). Die Benutzerechte in der Zeiterfassung sind dabei verschieden von denen in der Domäne und werden an das Session Objekt gebunden. Damit stehen die Benutzerrechte überall in der Zeiterfassung zur Verfügung und können entsprechend verwendet werden, um z. B. bestimmte Spalten im Datagrid auszublenden oder in der Navigation nur bestimmte Buttons anzuzeigen. 5.7 5.7.1 Zusammenfassung Gesamtstruktur Die zuvor vorgestellten Konzepte werden im Folgenden anhand des Beispiels Mitarbeiterverwaltung von Abbildung 38 zusammengefasst. 61 Abbildung 38: Zusammenfassende Darstellung am Beispiel Mitarbeiterverwaltung Der Einstiegspunkt in die Zeiterfassung ist die Webform Default mit ihrer dazugehörigen CodeBehind Klasse PageFrontdoor. Die Verbindung zwischen der Klasse PageFrontdoor und dem Template Main stellt das Laden des Templates in den PlaceHolder PhContent dar (vgl. Kapitel 5.4.2). Gemäß Kapitel 5.4 beschreibt der Namespace WebControl.Employee in Abbildung 38 in der Komponente ProjectManagement.Core einen beispielhaften Aufbau für die zwei Templates Main und EmployeeList. Die Templates werden von einer spezifischen Klasse von UserControlBasic abgeleitet. In diesem Fall ist dies EmployeeUserControl. In diesen Klassen werden weitere Methoden definiert, die in mehreren Templates des Funktionsblocks benötigt werden. Die Klasse UserControlBasic, wel62 che einen Funktionsblock repräsentiert, wird von UserControl abgeleitet und stellt einige Properties zur Verfügung. Das Setzen des Properties Info setzt beispielsweise einen Benutzerhinweis auf der Webform Default (siehe LInfo in Kapitel 5.4.2). Die Klasse UserControlBasic besitzt außerdem ein Property, welches den aktuellen Benutzer mit seinen Benutzerrechten repräsentiert (siehe Kapitel 5.6). Die Schnittstelle zur Businesslogik bildet das Property Controller. Das Property PageNavigator bzw. in diesem Fall das spezifische Property EmployeeNavigator repräsentiert das PageNavigator Objekt, was an die Session gebunden wird. Dieses beschreibt die Zusammensetzung der Oberfläche, d. h. wie die Templates miteinander in Abhängigkeit stehen (siehe Kapitel 5.5). Die Klasse EmployeeManager ist eine beispielhafte Managerklasse, wie in 5.2 und 5.3 beschrieben wurde. 5.7.2 Beispielhafter Ablauf Abbildung 39: Sequenz Diagramm bei einer Serveranfrage ohne Event Abbildung 40: Sequenz Diagramm bei einer Serveranfrage durch ein Event 63 In Abbildung 39 und 40 sind zwei beispielhafte Abläufe einmal mit und einmal ohne Event dargestellt. Beim Aufrufen eines Oberflächenzustandes durch ein Event (beispielsweise durch Betätigen eines Buttson) wird, wie in Abbildung 40 dargestellt, für jedes Template das Event Load geworfen bzw. die Methode Page Load aufgerufen. An das Event ”Betätigen des Buttons neuen Mitarbeiter anlegen” wird eine Methode mit dem Namen BtShowInsertMask Click gebunden, die in diesem Fall aufgerufen wird. Diese ändert den Zustand des PageNavigator Objekts (vgl. Abbildung 36 auf Seite 59) und ruft die Reload-Methode auf, die in UserControlBasic definiert wurde. Diese führt zu einer neue Anfrage am Server (mit dem geänderten PageNavigator ). Die neue Anfrage an den Server (siehe Abbildung 40) wirft dann ebenfalls das Event Load, was in den jeweiligen Templates die Methoden Page Load aufruft. Das anschließende Event PreRender (mit der Methode Page PreRender ) setzt die Inhalte der einzelnen Templates. An dem Beispiel von Abbildung 38 ist dies die Darstellung aller Mitarbeiter, die durch LoadArrayList aus der Businesslogik geholt werden. 5.7.3 Schwierigkeiten beim Entwurf Die fehlende Vererbung im Persistenz Framework erzwang bereits beim Entwurf flache Strukturen, d. h. Strukturen ohne Vererbung. Beispielsweise ist Wiederverwendbarkeit in den konkreten Managerklassen nicht möglich, da diese von ihren spezifischen abstrakten Managerklassen abgeleitet werden müssen (siehe Kapitel 5.3.1). Das nächste Problem stellen die verschiedenen Anfragemöglichkeiten dar. Für jede Anfrage, beispielsweise Projekte mit Fachgruppen, die bereits geschlossen sind, oder Projekte ohne Fachgruppen eines bestimmten Monats, muss eine abstrakte Methode in der Komponente ProjectManagement.Core definiert und in den konkreten Managern implementiert werden. Problematisch an dieser Struktur waren auch die Änderungen. Eine Änderung führt zu einer Änderung in den entsprechenden spezifischen und konkreten persistenten Objekten und entsprechend auch in den dazugehörigen Managern. Der Vorteil an dieser Variante ist nicht nur die logische, sondern auch die physikalische Trennung zwischen Implementierung und Entwurf. Wie bereits in Kapitel 5.1 beschrieben wurde, soll der Entwurf die Analyse erweitern bzw. verfeinern, was durch Definition der abstrakten Methoden in den Klassen des Persistenz-Frameworks durchgeführt wird. Vererbung kann dabei nur auf Spezifikationsebene durchgeführt werden, wie in Abbildung 26 in Kapitel 5.3.5 an der Klasse SimpleObject zu sehen ist. Kostenstellen (CostCenter ), Projekttypen (ProjectType), Projektgruppen (ProjectGroup) und Aufgabenkataloge (Activity) haben die gleichen Properties: ID, Name und Beschreibung. Wie bereits erwähnt wurde, ist diese Struktur in den konkreten 64 Komponenten nicht mehr möglich. Die Trennung nach dem Model-View-Controller Pattern ist ebenfalls gegeben. Das Persistenz-Framework besitzt dabei die Rolle des Modells, die Webform und die Templates bilden die View und die Codebehind Klassen mit ihrem PageNavigator (siehe Kapitel 5.5.1) nehmen die Rolle des Controllers ein. Die Entwicklung in einem Framework ist nicht ganz einfach, da nur an den vordefinierten Schnittstellen angesetzt werden kann. Beispielsweise habe ich erst sehr spät herausbekommen, dass es ein PreRender Event gibt, wobei man sich vorstellen kann, wie eine Implementierung ohne dieses Event ausgesehen hat, da nach dem Werfen der Benutzer Events keine Methode mehr zur Verfügung stand. Ein weiteres Problem für einen Web-Programmierer ist die Vorstellung, dass HTML-Elemente Objekte mit Events und Methoden sind. Die etwas andere Form der Webseitengestaltung hat aber auch einige Nachteile. Über das Visual Studio lassen sich zwar die Oberflächen einfach zusammenklicken, aber wenn man besondere Wünsche hat (siehe Kapitel 5.4.4), wird man gezwungen Manipulationen in den automatisch erzeugten Webforms bzw. Templates vorzunehmen, die nicht gerade einfach zu lesen sind. Die Entwicklung und Verwendung des PageNavigators (siehe Kapitel 5.5.1) war prinzipiell eine gute Idee, wobei sich die Controller-Funktion des Model-View- Controller Patterns für jede Oberfläche auf drei Klassen verteilt hat: die CodeBehind Klasse, die spezifische UserControlBasic Klasse und den spezifischen PageNavigator. 5.7.4 Nebenläufigkeit Ein Problem bei der Entwicklung einer Web-Applikation ist die Nebenläufigkeit. Wie noch im Kapitel 6.3.3 gezeigt wird, stellten nebenläufig arbeitende Aktionen ein Problem dar. In Kapitel 6.3.3 wird die Nebenläufigkeitsproblematik zwischen Businesslogik und Datenbank beschrieben. Ein anderes Problem ist die Nebenläufigkeit zwischen Client und Businesslogik. Eine Web-Applikation besitzt im Vergleich zu einer Nicht-Web-Applikation (siehe Kapitel 5.4.3) einige Besonderheiten. Beispielsweise kann der Zustand der grafischen Benutzeroberfläche eines Benutzers nie wirklich eindeutig bestimmt werden. Aus diesem Grund muss jedem Benutzer Event bzw. Serveranfrage sichergestellt werden, dass die Operationen, die ausgeführt werden sollen, im aktuellen Zustand noch zulässig sind. 5.7.5 Übergang zur Implementierung Die in den spezifischen Managerklassen und den persistenten Objekten definierten abstrakten Methoden müssen für die spezifische Komponente mit Funktionalität 65 gefüllt werden, d. h., von jeder dieser Klassen muss eine abgeleitete Klasse entwickelt werden, welche die abstrakten Methoden implementiert. Instanzen dieser Klasse müssen an eine von Controller abgeleitete Klasse gebunden werden. 66 6 Implementierung mit relationaler Datenbank 6.1 Einleitung Die relationale Datenbank basiert auf dem Relationenmodell, welches von E. F. Codd 1970 [Cod 70] vorgestellt wurde. Das grundlegende Konzept der relationalen Datenbank ist die Tabelle13 . Eine Tabelle besitzt eine definierte Anzahl von Attributen (Spalten) und eine beliebige Menge von Tupeln. Die Tupel repräsentieren die Datensätze. Über so genannte Schlüsselverbindungen, wie in Kapitel 6.2 noch gezeigt wird, werden Beziehungen zwischen den Tabellen realisiert. Die Kommunikation zwischen der Anwendung14 und der Datenbank erfolgt über die standardisierte Stuctured Query Language (SQL). Eine relationale Datenbank ist immer ein von der Anwendung unabhängiges System. Die Probleme, die durch diese Trennung entstehen, werden im weiteren Verlauf noch beschrieben. In Form eines Strings (Query) werden Anweisungen oder Abfragen formuliert, die an die Datenbank gesendet und dort entsprechend ausgeführt werden. SQL kann in drei Teilsprachen unterteilt werden: Die Datendefinitionssprache (DDL) enthält Befehle zum Anlegen, Ändern und Löschen von Strukturen bzw. Tabellen. Die einzelnen Möglichkeiten und Probleme werden in Kapitel 6.2 beschrieben. In der Datenmanipulationssprache (DML) werden Befehle zum Erzeugen, Ändern und Löschen von Daten definiert. Die Funktionsweise der Datenmanipulation und die Problematik, insbesondere bei nebenläufigen Manipulationen, werden in Kapitel 6.3 beschrieben. Die dritte Teilsprache von SQL ist die Abfragesprache (QL), mit der die einzelnen Daten abgefragt werden. Diese wird in Kapitel 6.4 vorgestellt. Redundanzvermeidung durch Normalisierung ist einer der entscheidenden Vorteile einer relationalen Datenbank. Durch mathematische Regeln, die auf der Arbeit von [Cod 70] basieren, können Redundanzen vermieden bzw. gemindert werden. Dieses Thema wird in Kapitel 6.5 behandelt. In Kapitel 6.6 wird anhand des Beispiels der ODBC-Schnittstelle beschrieben, wie aus der Sicht der Anwendung mit der Datenbank kommuniziert wird. Basierend auf den Grundlagen von Kapitel 6.2-6.6 wird in Kapitel 6.7 das kon13 In der Relationstheorie spricht man von Relationen und in der Datenbank von Tabellen. Prinzipiell sind Tabellen Relationen, die in einer (relationalen) Datenbank verwendet werden. 14 Die Anwendung ist in diesem Fall die Applikation ”Zeiterfassung”. 67 krete Datenmodell der Applikation Zeiterfassung vorgestellt. In Kapitel 5.3 wurde bereits das entwickelte Framework vorgestellt, was eine Trennung von Entwurf und Implementierung ermöglicht. Die Beispiele im Folgenden beziehen sich auf dabei vorgestellten Managerklassen aus Kapitel 5.3. Bei der Entwicklung einer relationalen Datenbank ergeben sich etliche Schwierigkeiten und Schwächen, wie in den folgenden Kapiteln noch gezeigt wird. In Kapitel 6.8 werden diese zusammengefasst und mit einer Motivation zur Objektorientierung in Datenbanken abgeschlossen. Die Beschreibungen basieren auf dem SQL-99 Standard, allerdings ohne die objektrelationalen Erweiterungen. Da SQL-99 abwärts kompatibel zu SQL-92 ist, sind darin auch alle Möglichkeiten von SQL-92 enthalten. Dabei werden nur die Punkte behandelt, die für die Realisierung und den Vergleich relevant sind. Weitere Konzepte, wie beispielsweise Schemata, mit denen logisch zusammengehörige Tabellen weiter strukturiert werden können, werden nicht behandelt. 6.2 6.2.1 Datendefinition Datentypen und Domänen Für jedes Attribut wird ein Wertebereich definiert. Dieser Wertebereich wird als Domäne bezeichnet. Neben vordefinierten Domänen besteht die Möglichkeit, eigene Domänen zu definieren. Diese basieren auf vordefinierten Domänen und können diese einschränken. Ein Beispiel für eine Domäne ist eine Prozentdefinition, die durch den Query ”CREATE DOMAIN Percent INTEGER CHECK(BETWEEN 0 AND 100)” definiert werden kann. Benutzerdefinierte Domänen sind nicht streng typisiert, da sie keine Typen im eigentlichen Sinne sind, d. h., ein Vergleich von Percent und einem Attribut vom Typ Integer mit dem Wert 101 wäre zulässig (vgl. [Tür 03, S. 26]). Domänen sind atomar, d. h., Strukturen in Attributen sind nicht möglich. Die Konsequenzen daraus, die sich für die Datenmodellierung ergeben, werden im weiteren Verlauf noch beschrieben. 6.2.2 Primärschlüssel Zur Identifizierung eines Tupels wird in einer Tabelle ein Primärschlüssel definiert. Dieser kann entweder aus einem einzelnen oder aus einer Gruppe von Attributen (zusammengesetzter Schlüssel) bestehen. Der Primärschlüssel darf nicht NULL sein und muss für jedes Tupel eindeutig vorliegen. 68 Die Betrachtung eines Primärschlüssels als Identität, wie es in vielen Fällen getan wird, hat einen entscheidenden Nachteil. Wenn der Wert des Primärschlüssels geändert wird, so bedeutet das, dass sich die Identität eines Tupels ändert, was aber falsch ist. Ein konkretes Beispiel ist das Projekt, wie in Kapitel 6.7 auf Seite 83 noch gezeigt wird. Ein Projekt wird durch eine Projektnummer (ProjectID) identifiziert, welche gleichzeitig der Primärschlüssel ist. Eine Änderung der Projektnummer, beispielsweise weil eine Projektnummer falsch eingegeben wurde, bedeutet aber keine Änderung der Identität des Projekts (vgl. auch [Saa 03, S. 47 f.]). Aus diesem Grund wurden - bis auf das Projekt - für alle Entitäten unveränderliche Schlüssel definiert. Der Datentyp ”serial” in der Abbildung 55 auf Seite 85 erzeugt automatisch eine fortlaufende eindeutige Zahl. Die Anwendung, also die Zeiterfassung, braucht sich in diesem Fall nicht mehr um die Eindeutigkeit zu kümmern. 6.2.3 Fremdschlüsselverbindungen und referentielle Integrität Um zwei Tabellen miteinander in Beziehung zu setzen werden Fremdschlüssel definiert. Ein Fremdschlüssel kann, genau wie ein Primärschlüssel, für ein einzelnes Attribut oder eine Gruppe von Attributen definiert werden. Zu jedem Fremdschlüssel in einer Tabelle gibt es einen dazugehörenden Primärschlüssel in einer anderen Tabelle. Dabei müssen Fremdschlüsselverbindungen die referentielle Integrität gewährleisten. Referentielle Integrität bedeutet, dass zu jedem Fremdschlüsselwert in einer Tabelle ein entsprechender Primärschlüssel existiert, der den gleichen Wert besitzt, oder der Fremdschlüssel ist NULL, d. h., ein Fremdschlüssel muss immer auf einen existierenden Primärschlüssel verweisen (vgl. [Vor 99], S. 89). 6.2.4 Integritätsbedingungen Durch Änderungen an den Daten können Schlüsselbedingungen verletzt werden und die referentielle Integrität ist dann nicht mehr gegeben. Wie in [Tür 03, S. 20] beschrieben, tritt dies ein, wenn einer der folgenden Punkte erfüllt ist: • Einfügen einer Zeile in die referenzierende Tabelle. • Ändern des Fremdschlüsselwertes einer Zeile in der referenzierenden Tabelle. • Löschen einer Zeile aus der referenzierten Tabelle (oder Löschen einer referenzierten Tabelle). • Ändern des korrespondierenden Schlüsselwertes einer Zeile in der referenzierten Tabelle. 69 Zu Sicherung der referenziellen Integrität muss einer Fremdschlüsselverbindung eine Eigenschaft (siehe Abbildung 41) mitgegeben werden, die beschreibt, wie eine Verletzung der referenziellen Integrität behandelt wird. NO ACTION: Wenn eine Fremdschlüsselbedingung beim Ändern oder Löschen einer Zeile verletzt wird, wird diese Anfrage mit einem Fehler zurückgewiesen. Allerdings kann die Integritätsverletzung mit einem Trigger behoben werden, wodurch kein Fehler auftritt. CASCADE (C): Die Änderung oder Löschung der Zeile wird kaskadiert. Wird eine Zeile gelöscht bzw. geändert, so werden alle Zeilen, die auf diese Zeile referenziert haben, mit gelöscht oder geändert. SET NULL (SN) und SET DEFAULT (SD): Wird ein Primärschlüssel einer Zeile geändert oder eine Zeile gelöscht, so werden die Fremdschlüssel, die auf diese Zeile referenzierten, auf NULL bzw. den eingestellten Defaultwert gesetzt. RESTRIKT (R): Restrikt weist eine Anfrage, genau wie No Action, zurück, wenn eine Integritätsverletzung vorliegt. Ein Beheben der Integritätsverletzung mit einem Trigger ist allerdings nicht möglich. Abbildung 41: Referenzielle Aktionen nach [Tür 03, S. 21] 6.2.5 Trigger Fremdschlüsselverbindungen können nur die Integrität zwischen zwei Tabellen, d. h. die referentielle Integrität gewährleisten. Für komplexere Integritätsprüfungen werden Trigger definiert. Ein Trigger führt, ähnlich zu einem Event, beim Eintreten eines Ereignisses eine Folge von Anweisungen aus. Die möglichen Ereignisse nach dem SQL-99 Standard, wie in [Tür 03, S. 37] beschrieben, sind das Einfügen, Ändern oder Löschen von Tupel. 6.2.6 Benutzerdefinierte Routinen Durch die Definition von benutzerdefinierten Routinen (stored procedures) besteht die Möglichkeit, einfache Funktionalitäten in einer relationalen Datenbank auszuführen. Diese können, durch die Verwendung von atomar definierten Funktionsblöcken, Definition von Variablen, bedingten Schleifen oder bedingten Anweisungen, zusätzliche Integrationsprüfungen oder analog zu den Sichten komplexe Abfragen realisieren. Dabei ähnelt eine benutzerdefinierte Routine sehr einem Pascalprogramm, in welchem zusätzlich SQL-Statements enthalten sind. 70 So wie in [Tür 03, S. 32] beschrieben wird, sind nicht alle SQL-Statements zulässig. Beispiele für nicht zulässige SQL-Statements sind Transaktionsanweisungen, Anweisungen zur Steuerung der Datenbankverbindung und Transaktionsanweisungen. Bei den benutzerdefinierten Routinen wird zwischen Prozeduren und Funktionen unterschieden. Funktionen haben im Gegensatz zu Prozeduren einen Rückgabewert und können auch in Queries verwendet werden, um z. B. Bedingungen zu definieren. Funktionen können außerdem überladen (overloading) werden (vgl. dazu auch [Tür 03, S. 28-37]). Die Funktionen und Prozeduren in Klassen zu organisieren und damit Vererbung und dynamisches Binden zu ermöglichen, besteht nicht. 6.2.7 Sichten (Views) Eine Sicht, auch als virtuelle Tabelle bezeichnet, repräsentiert eine SQL-Anfrage und kann wie eine Tabelle verwendet werden. Änderungen in den Tupeln einer Sicht sind zwar nach dem SQL-99 Standard unter sehr eingeschränkten Bedingungen möglich (vgl. [Tür 03, S. 253 ff.]), da aber die mir zur Verfügung stehende Informix Datenbank Änderungen auf Sichten nicht unterstützt und die verwendeten Sichten die Bedingungen überwiegend nicht erfüllt haben, wird im Folgenden davon ausgegangen, dass Änderungen an Sichten nicht möglich sind. 6.2.8 Schwächen der relationalen Datendefinition Während in der Anwendung komplexe (objektorientierte) Datentypen verwendet werden können, müssen diese in der relationalen Datenbank durch die fehlende Vererbung auf flache Strukturen abgebildet werden. Die Domänen (vgl. 6.2.1) können zwar Wertebereiche definieren, sind aber keine echten Typen im eigentlichen Sinne. Dadurch, dass sie nicht typsicher sind, können beliebige Daten unterschiedlicher Domänen miteinander verglichen und in Beziehung gesetzt werden. In Kapitel 6.7.2 wird die Problematik bei der Modellierung des Modells von Abbildung 8 auf Seite 28 in einer Struktur ohne Vererbung noch genauer beschrieben. 6.3 6.3.1 Datenmanipulation Datenmanipulationsoperationen Einfügen, Ändern und Löschen von Tupeln werden über die Insert-, Update- und Delete-Statements durchgeführt. Diese Operationen sind auf einzelne Tabellen beschränkt, d. h., Operationen, die sich auf mehrere Tabellen verteilen, müssen in einzelnen SQL-Statements angegeben werden. Die referentielle Integrität und eventuell durch Trigger zusätzlich definierte Integritätsbedingungen dürfen dabei nicht 71 verletzt werden. Damit ist gesichert, dass keine unzulässigen Zustände in der Datenbank vorkommen können. 6.3.2 (SQL-)Transaktionen Eine Transaktion ist eine atomare Ausführungseinheit, die eine Folge von logisch zusammengehörigen Operationen umfasst und dem ACID-Prinzip, wie in Abbildung 42 dargestellt, entsprechen muss (vgl. [Saa 03, S. 275]). Atomicity (Atomarität): Eine Transaktion stellt eine atomare Einheit dar, d. h., eine Transaktion wird entweder vollständig oder gar nicht ausgeführt. Consistency (Konsistenz): Nach Abschluss einer Transaktion muss sich die Datenbank in einem konsistenten Zustand befinden. Isolation: Parallel ablaufende Transaktionen dürfen sich gegenseitig nicht behindert, d. h., eine Transaktion muss immer so ablaufen, als wäre sie die einzige auf der Datenbank. Änderungen an Daten in einer Transaktion dürfen in einer anderen Transaktion nicht auftreten. Durability (Dauerhaftigkeit): Beim Beenden einer Transaktion müssen alle Änderungen, welche durch die Transaktion verursacht wurden, dauerhaft (persistent) erhalten bleiben. Abbildung 42: Die ACID-Eigenschaften, die eine Transaktion erfüllen sollte In einer relationalen Datenbank werden dafür entsprechende Operationen zur Verfügung gestellt, die eine Transaktion starten und erfolgreich (Commit) oder durch Rückgängigmachen aller Operationen der Transaktion (Rollback ) beenden. Erst wenn ein Commit durchgeführt wurde, sind alle Daten dauerhaft in der Datenbank gespeichert. Tritt während einer Transaktion ein Fehler auf, beispielsweise weil eine Integritätsbedingung nicht erfüllt ist oder eine Query eine fehlerhafte Syntax besitzt, so verhält sich die Datenbank wie bei einem Rollback und erzeugt den Zustand, der vor der Transaktion existierte. Dies funktioniert wunderbar unter der Voraussetzung, dass keine weitere parallele Transaktion läuft. Durch das Bilden von Transaktionen, in denen die Queries an die Datenbank gesendet werden, sind die ACID-Eigenschaften Atomicity und Durability erfüllt. 6.3.3 Nebenläufigkeitsanomalien Problematisch wird die Erfüllung der ACID-Eigenschaften Consistency und Isolation. Diese beziehen sich auf die Nebenläufigkeitsproblematik. Nebenläufige Leseund Schreiboperationen können, wie in Abbildung 43 dargestellt, zu inkonsistenten 72 Zuständen führen (vgl. [Vor 99, S. 143 f.]). Dirty Read: Diese Problem tritt auf, wenn eine Transaktion Daten liest, die zuvor von einer zweiten geändert wurden, und diese zweite Transaktion ein Rollback ausführt. Das Rollback der zweiten Transaktion verwirft die Änderungen in der Datenbank, aber die erste Transaktion verwendet noch die ”falschen” Daten. Lost Update: Zwei Transaktionen lesen jeweils das gleiche Objekt und ändern dies unabhängig. Die Änderungen der ersten Transaktionen werden dabei überschrieben. Non-repeatable Read: Wenn eine Transaktion zweimal dasselbe Objekt liest und es währenddessen geändert wurde, würde die zweite Leseoperation einen anderen Wert zurückliefern. Dies ist vor allem dann problematisch, wenn eine wiederholte Anfrage abhängig von einem Ergebnis einer vorherigen Anfrage ist. Phantom Read: Das Problem Phantom Read tritt bei folgendem Ablauf ein: Eine Transaktion holt sich Daten, die abhängig von einer Menge sind, die anschließend von einer zweiten Transaktion geändert wird. Die erste Transaktion verarbeitet diese Daten, welche die geforderten Bedingungen nicht mehr erfüllt. Abbildung 43: Anomalien bei nebenläufigen Transaktionen nach [FO 04b] In [FO 04b] wird noch eine weitere Anomalie mit dem Namen Reading of Inconsistent States beschrieben, die sich auf Verletzung von Bedingungen zwischen Daten bezieht, da diese aber in der übrigen Literatur nicht zu finden war, wird sie hier nicht weiter beschrieben. Das folgende Beispiel soll das Problem Phantom Read verdeutlichen: Transaktion 1 ermittelt alle Projekte, die keine Fachgruppen15 besitzen. Eine zweite Transaktion fügt anschließend einem dieser Projekte eine erste Fachgruppe hinzu. Die erste Transaktion enthält dabei in ihrer Projektmenge ein Projekt, welches Fachgruppen besitzt, obwohl diese Transaktion davon ausgeht, dass sie die Liste aller Projekte ohne Fachgruppen enthält. 6.3.4 Nebenläufigkeitskontrolle Um die Kapitel 6.3.3 dargestellten Probleme zu beseitigen gibt es grundsätzlich zwei Ansätze, die in diesem Kapitel beschrieben werden. Nebenläufigkeitskontrolle kann 15 In der realisierten Datenbank existiert zu jedem Projekt immer eine Default-Fachgruppe (vgl. 6.7). Das Problem bleibt aber das gleiche. 73 auf verschiedenen Ebenen durchgeführt werden. Im Folgenden wird nur von Dateneinheiten gesprochen, wobei es abhängig von der verwendeten Granularität ist, ob eine Dateneinheit ein Wert, ein Tupel, eine Tabelle oder eine Datenbank ist. Der erste Ansatz ist die pessimistische Nebenläufigkeitskontrolle. Diese basiert auf einem Lock-Mechanismus. Eine bestimmte Dateneinheit kann von einer Transaktion entweder durch einen exklusive, write lock oder ein shared, read lock gesperrt werden (vgl. [Vor 99, S. 150]. Dabei kann eine Dateneinheit entweder von beliebig vielen Transaktionen mit einem shared, read lock belegt oder einer einzigen Transaktion mit einem exklusive, write lock gesperrt werden. Zugriffe auf gelockte Dateneinheiten werden von der Datenbank sofort zugewiesen, bzw. abhängig von der Datenbank können auch Wartezeiten eingestellt werden. Wird der Lock während dieser Wartezeit freigegeben, so kann die Transaktion, welche die gelockte Dateneinheit benötigt, ausgeführt werden (vgl. dazu auch [FO 04b]). Der zweite Ansatz ist die optimistische Nebenläufigkeitskonrolle (vgl. [FO 04b]). Die Prüfung, ob eine Lese- oder Schreiboperation unzulässig ist, wird beim Ausführen der jeweiligen Operation überprüft. Realisiert werden kann dieser Algorithmus durch das Einführen von Zeitstempeln oder Versionierung der Dateneinheiten (vgl. [FO 04b] und [Vor 99, S. 156 f.]). Einen direkten Mechanismus gibt es beim relationalen Datenbankkonzept nicht. Es besteht zwar die Möglichkeit, in einem Attribut eine Version oder einen Zeitstempel zu speichern und diesen Wert bei jeder Änderung zu aktualisieren. Das Problem, was sich dabei stellt, ist, dass dieses spezielle Attribut ein Attribut wie jedes andere auch ist und beliebig geändert werden kann. Viel schlimmer ist die Abfrage, ob ein Wert noch aktuell ist. Die Versionsinformation muss beim Lesen eines Datensatzes mit ausgelesen und beim Ändern entsprechend überprüft werden, ob dieser Wert noch aktuell ist. Zumindest das Testen auf Aktualität und das Ändern sollten dann in einer sperrenden Transaktion durchgeführt werden. 6.4 6.4.1 Datenabfragen (Select) Select-Statement Durch das Select-Statement werden, wie in Abbildung 44 dargestellt, Tupelmengen aus Tabellen abgefragt. Die From-Klausel enthält die Tabellen, aus denen die Daten abgefragt werden sollen. In der Select-Klausel werden die Attribute angegeben, die zurückgeliefert werden sollen. Die Where-Klausel gibt Bedingungen an, die auf die Ergebnismenge zutreffen müssen. Abbildung 45 zeigt ein Beispiel mit zwei Tabellen. Um einen Verbund dieser beiden Tabellen zu erzeugen, werden die Schlüsselbedingungen in der 74 SELECT <Attribute> FROM <Tabellen> [WHERE <Bedingungen>] [ORDER BY <Sortierreihenfolge>] Abbildung 44: Einfache Darstellung des SQL-Select-Statements Where-Klausel definiert, wie in Abbildung 46 dargestellt. Abbildung 45: Verbund von zwei SQL-Tabellen SELECT Employee.ID AS ID, AccountID, Firstname, Lastname, Account FROM Employee, EmployeeAccount WHERE Employee.ID=EmployeeAccount.ID Abbildung 46: SQL-Select-Statement zu dem Beispielverbund von Abbildung 45 Des Weiteren können in der Select-Klausel berechnete Werte enthalten sein. Ein Beispiel aus der Zeiterfassung ist die Select-Anfrage für Projekte. Dort wird u. a. ein Attribut erzeugt, was die Summe aller Fachgruppen des jeweiligen Projekts enthält. Abbildung 47 stellt eine ”einfache” Ad-hoc-Anfrage über alle Mitarbeiter, die in einer ausgewählten Kalenderwoche an einem ausgewählten Projekt gearbeitet haben, dar. Wie an diesem Beispiel zu sehen ist, können Anfragen nach einfachen Informationen ziemlich kompliziert werden und die Bedeutung einer Anfrage ist nicht sofort erkennbar. Die definierten Fremdschlüsselverbindungen müssen dabei als Bedingungen mit angegeben werden. Solche Anfragen können bei sehr großen Datenmengen durch die Verbund-Operation sehr rechenintensiv werden. 75 SELECT ... FROM Employee e, EmployeeContract ec, EmployeeWeek ew, Week w, ProjectEmployee pe, Project p WHERE e.EmployeeID = ec.EmployeeID AND ec.ContractID = ew.ContractID AND ew.EmployeeWeekID = w.WeekID AND w.CalendarWeek = <ausgegewählte Kalenderwoche> AND w.Year = <ausgewähltes Jahr> AND ew.EmployeeWeekID = pe.EmployeeWeekID AND pe.ProjectID = p.ProjectID AND p.ProjectID = <ausgewähltes Projekt> Abbildung 47: Ad-hoc-Abfrage über alle Mitarbeiter in einem Projekt in einer ausgewählten Woche Wie in Kapitel 6.2.7 schon beschrieben wurde, können Select-Anfragen als Sichten abgespeichert werden. Abbildung 48 zeigt eine Sicht, die wiederum eine Sicht (CurrentEmployeeView ) mit der Tabelle EmployeeAccount verbindet. Die Menge aller Mitarbeiter mit ihren Accounts, die zum aktuellen Zeitpunkt aktiv sind, wird dann über ein einfaches SELECT * FROM EmployeeAccountView abgefragt. CREATE VIEW EmployeeAccountView AS SELECT ... FROM CurrentEmployeeView, EmployeeAccount WHERE CurrentEmployeeView.ID=EmployeeAccount.ID Abbildung 48: Definition einer Sicht auf Mitarbeiteraccounts Da Sichten nur für Anfragen verwendet werden konnten (siehe Kapitel 6.3.1), mussten das Ändern, Löschen und Einfügen von Datensätzen in einer Sicht, auf den in der Sicht enthaltenden Tabellen durchgeführt werden. Ein Beispiel aus der Zeiterfassung ist das in Abbildung 45 dargestellte Beispiel. Ein neu angelegter Mitarbeiter führt zu einem neuen Eintrag in der Tabelle Employee und für jeden Account zu einem Eintrag in der Tabelle EmployeeAccount. In Kapitel 6.7.4 wird auf die Problematiken, die bei der Verwendung von Sichten entstehen, noch genauer eingegangen. 6.4.2 Subqueries Ein Subquery ist ein Query, der in einem anderen Query eingebettet ist (vgl. [Inf 99, S. 7-60 bis 7-68]). Subqueries können in Insert-, Delete-, Update- und Select-Statements 76 verwendet werden. Ein Beispiel für eine Subquery ist die Anfrage alle Mitarbeiter, die keinen Vertrag besitzen, wie in Abbildung 49 dargestellt. (1) (2) (3) (4) SELECT * FROM Employee e WHERE ( SELECT COUNT(*) FROM EmployeeContract c WHERE c.EmployeeID=e.EmployeeID) = ’0’ Abbildung 49: Beispiel aus der Zeiterfassung für einen Subquery 6.4.3 OUTER JOIN Die bisherigen Verbunde waren so genannte inner join-Verbunde. Ein weiteres Konzept von SQL sind die outer join-Verbunde. Ein outer join-Verbund enthält die Menge aller inner join-Verbunde. Zusätzlich zu dieser Menge enthält sie die Menge aller Tupel, die die Bedingungen der Where-Klausel zwar nicht erfüllen, aber aus einer Tabelle stammen, die in der From-Klausel als outer join definiert wurde. In Abbildung 50 ist eine Beispielanwendung aus der Zeiterfassung dargestellt, welche die Liste aller Aufgabenkataloge (Activity) zurückliefert (vgl. dazu auch 55 auf Seite 85). Existiert zu dem übergebenden Vertrag (contractID) in der übergebenden Woche (weekID) der übergebenden Fachgruppe (teamID) eine Arbeitszeitzuordnung bzw. ein Eintrag in der Tabelle ActivityEmployee (siehe Abbildung 55 auf Seite 85), so wird diese Arbeitszeitzuordnung (Proration) mit ausgegeben. (1) (2) (3) (4) (5) (6) (7) (8) (9) SELECT * FROM Activity OUTER ( ActivityEmployee ActivityEmployee, EmployeeWeek ) WHERE Activity.ActivityID=ActivityEmployee.ActivityID AND ActivityEmployee.EmployeeWeekID=EmployeeWeek.EmployeeWeekID AND ( (TeamID is null) OR (TeamID=’“+ teamID + “) ) AND ( (ContractID is null) OR (ContractID=’“+ contractID + “) ) AND ( (WeekID is null) OR (WeekID=’“+ weekID + “) ) AND Activity.ActivityID>’0’ Abbildung 50: Beispiel für outer join Wie in Abbildung 51 zu sehen ist, existierte für die drei oben angegebenen Parameter für die Fachgruppe ”Software” kein Eintrag. In einem inner join-Verbund 77 wäre die Zeile ”Software” nicht in der Ergebnismenge enthalten gewesen. Activity.Name Software Hardware Testen ActivityEmployee.Proration NULL 77 23 Abbildung 51: Verkürztes Ergebnis der Anfrage aus Abbildung 50 6.5 Redundanzvermeidung durch Normalisierung Ziel der Normalisierung ist es, ein redundanzfreies Datenmodell zu erhalten, indem keine unerwünschten Seiteneffekte auftreten. Diese Seiteneffekte werden Anomalien genannt. Dabei werden die folgenden drei Arten von Anomalien unterschieden: Update-Anomalie: Änderungen an redundanten Daten müssen an allen vorhandenen Stellen durchgeführt werden. Insert-Anomalie: Ein Datensatz kann erst eingefügt werden, wenn alle darin enthaltenen Informationen vorhanden sind. Delete-Anomalie: Wird ein Datensatz gelöscht, so gehen alle Information in diesem verloren. Durch die von Codd (vgl. Literatur [Cod 70]) vorgestellten Normalformen sollen diese Anomalien vermieden werden. Das Prinzip der Normalisierung ist es, redundante Daten dadurch zu vermeiden, dass Tabellen aufgeteilt und ggf. über zusätzliche Schlüssel in Verbindung gesetzt werden. Um die ursprünglichen Relationen wieder zu erhalten werden diese aufgeteilten Tabellen über ihre Schlüssel verbunden. Die Zerlegung der Tabellen muss dabei verlustfrei sein, d. h., es dürfen keine Daten verloren gehen (vgl. auch [Geb 04, S. 167 f.]). 6.5.1 Begrifflichkeiten Funktionale Abhängigkeit: Ein Wertebereich B ist funktional abhängig von einem Wertebereich A, geschrieben A -> B, wenn zu jedem Zeitpunkt gilt: Zu jedem Wert von A ist genau ein Wert in B zugeordnet. Das bedeutet, dass der Wertebereich A den Wertebereich B eindeutig identifiziert. Voll funktionale Abhängigkeit: Ein Wertebereich B mit B=(B1 , B2 , ..., Bm ) ist voll funktional abhängig von A mit 78 A=(A1 , A2 , ..., An ), wenn B funktional abhängig von A, aber nicht funktional abhängig von einer echten Teilmenge von A ist. Transitive Abhängigkeiten: Der Wertebereich C ist funktional abhängig von B und B ist funktional abhängig von A (A –> B –> C), dann ist C transitiv abhängig von A. 6.5.2 1. Normalform Eine Relation liegt in der ersten Normalform vor, wenn jedes Attribut atomar ist, d. h. eine nicht weiter zerlegbare Dateneinheit darstellt und keine Wiederholungsgruppe enthält. Um eine nicht-normalisierte Relation in eine Relation der ersten Normalform zu überführen, müssen die nicht atomaren Attribute in atomare aufgeteilt werden. Die Attribute der Wiederholungsgruppen werden in einer neuen Tabelle angelegt und entsprechend aus der alten Tabelle entfernt. Anschließend müssen diese beiden Tabellen über eine Schlüsselverbindung verbunden werden, um die ursprüngliche Relation wieder darstellen zu können. Für jeden Wechsel einer Kostenstelle muss ein neuer Datensatz in der Tabelle Employee erzeugt werden. Dieser enthält ein Datum, ab wann der Mitarbeiter dieser Kostenstelle zugeordnet ist. Die Kostenstelleninformationen dürfen nicht einfach überschrieben werden, da Reports, die sich auf einen Zeitraum vor dem Wechsel beziehen, diesen Mitarbeiter mit der vorherigen Kostenstelle darstellen müssen. Ein Beispiel für solch einen Report wäre eine Stundenübersicht, nach Kostenstellen geordnet, für einen ausgewählten Monat. Das folgende Beispiel soll die Redundanz an dieser Tabelle zeigen: Alte Tabelle Employee: EmployeeID 1 1 2 Name Vertragsstart Kostenstelle Claus Schmidt 01.01.2004 287 Claus Schmidt 10.04.2004 110 Max Müller 26.06.1998 287 Wie an dieser Tabelle zu sehen ist, ist Name nicht atomar und Kostenstelle stellt eine Wiederholungsgruppe dar. Die Konsequenz ist, dass keine Mitarbeiter ohne Vertrag eingefügt werden können, Änderungen beispielsweise am Namen müssten an mehreren Stellen durchgeführt werden, und sollten alle Datensätze bzw. Tupel gelöscht werden, die der Kostenstelle 287 gewesen sind, so wäre die Kostenstelle 287 anschließend nicht mehr existent. Um diese Relation in die erste Normalform zu überführen, muss der Name in seine Bestandteile (Vor- und Nachname) zerlegt werden und die Attribute Vertragsstart 79 und Kostenstelle werden in eine neue Tabelle mit dem Namen EmployeeContract ausgelagert. Zusätzlich ist der neue Schlüssel ContractID nötig, um die ursprüngliche Relation wieder darstellen zu können. Neue Tabelle Employee: EmployeeID 1 2 Vorname Claus Max Nachname Schmidt Müller Neue zusätzliche Tabelle EmployeeContract: EmployeeID 1 1 2 ContractID Vertragsstart Kostenstelle 1 01.01.2004 287 2 10.04.2004 110 1 26.06.1998 287 Durch den dargestellten Normalisierungsprozess ergab sich, dass ein Mitarbeiter eine beliebige Menge an Verträgen besitzt, wobei es in dem jetzigen System nicht möglich ist, dass ein Mitarbeiter mehr als einen Vertrag gleichzeitig besitzt, was aber im Datenmodell ohne größere Probleme möglich wäre. Wie an diesem Beispiel zu sehen ist, hilft Normalisierung nicht nur Redundanzen zu vermeiden bzw. zu mindern, sondern hilft auch die Daten und ihre Abhängigkeiten besser zu verstehen. Diese Information, dass Mitarbeiter Verträge besitzen und eigentlich nur die Verträge ”arbeiten”, d. h. Arbeitszeiten besitzen und diese Zeiten auf Projekte verteilen, wurde im Requirement Engineering ”übersehen” und ist erst beim Normalisieren entstanden. 6.5.3 2. Normalform Eine Relation liegt in der zweiten Normalform vor, wenn sie in der ersten Normalform vorliegt und jedes Nichtschlüsselattribut16 voll funktional abhängig vom Primärschlüssel ist (vgl. [CIS]). Das bedeutet, dass es keine Nichtschlüsselattribute geben darf, die nur von einem Teil des Primärschlüssels abhängig sind (vgl. gestrichelte Linie in Abbildung 52). Alte Tabelle Week: 16 Attribute, die nicht zum Primärschlüssel gehören 80 Abbildung 52: Grafische Darstellung der 2NF WeekID ContractID Year CalendarWeek WorkingHour 1 1 2004 10 38 1 2 2004 13 45 Neue Tabelle Week: WeekID Year CalendarWeek 1 2004 10 1 2004 13 Neue zusätzliche Tabelle EmployeeWeek: WeekID ContractID WorkingHour 1 1 38 1 2 45 6.5.4 3. Normalform Eine Relation liegt in der dritten Normalform vor, wenn sie sich in der 2. Normalform befindet und jedes Nichtschlüsselattribut nicht transitiv abhängig vom Primärschlüssel ist (vgl. [CIS]). Es würfen keine Nichtschlüsselattribute existieren, die von einem anderen Nichtschlüsselattribut abhängig sind (vgl. gestrichelte Linie in Abbildung 53). Abbildung 53: Grafische Darstellung der 3NF Alte Tabelle Project: PjID PjName 10001 Joker 10002 Frankit PjTypeName Frankiermaschine Frankiermaschine 81 PjTypeFirstPjID 10000 10000 Neue Tabelle Project: PjID PjName 10001 Joker 10002 Frankit PjTypeID 1 1 Neue zusätzliche Tabelle ProjectType: PjTypeID PjTypeName 1 Frankiermaschine 6.5.5 PjTypeFirstPjID 10000 Boyce-Codd-Normalform (BCNF) Eine Relation befindet sich in der BCNF genau dann, wenn sie in der 3NF vorliegt und alle voll funktionalen Abhängigkeiten vom Primärschlüssel ausgehen (vgl. [CIS]). Das bedeutet, dass kein Nichtschlüsselattribut ein Primärschlüsselattribut identifizieren darf (vgl. gestrichelte Linie in Abbildung 54). Abbildung 54: Grafische Darstellung der BCNF 6.6 ODBC-Schnittstelle ODBC steht für Open DataBase Connectivity und ist eine standardisierte Schnittstelle, die durch standardisierte Methoden den Zugriff einer beliebigen Applikation auf eine beliebige (relationale) Datenbank beschreibt (vgl. [MSDN]). Im .NET-Framework werden hierfür Klassen zur Verfügung gestellt, die diese Methoden anbieten und somit die Anwendung unabhängig von der spezifischen (relationalen) Datenbank machen. Die vier wichtigen Klasen im .NET-Framework sind dabei folgende: OdbcConnection: Reräsentiert eine Datenbankverbindung. OdbcCommand: Repräsentiert einen SQL-Query oder eine benutzerdefinierte Routine (vgl. Kapitel 6.2.6). OdbcDataReader: Repräsentiert eine Ergebnisrelation, die durch einen SQL-Query zurückgeliefert wurde. 82 OdbcTransaction: Repräsentiert eine Transaktion. Durch die Verwendung von ODBC-Klassen im .NET Framework werden die Probleme mit den heterogenen Datenbanken gemindert. Das Definieren von Transaktionen mit entsprechenden Einstellungen für die Nebenläufigkeitskontrolle (vgl. 6.3.4) und der Verbindungsaufbau zur Datenbank werden durch die ODBC-Klassen durchgeführt. Die Nebenläufigkeitsanomalie Phantom Read (vgl. 6.3.3) kann allerdings nur durch Serialisieren der Transaktionen vermieden werden. 6.7 6.7.1 Konkrete Implementierung Verwendete Modellierungstechnik Zur Beschreibung des Datenmodells habe ich die IDEF1X-Notation gewählt, da das mir zur Verfügung stehende Tool ERwin17 diese Notation verwendet. Auf einer grafischen Benutzeroberfläche lassen sich damit Entitäten und ihre Beziehungen darstellen. Aus diesen Modellen können SQL-Scripte erzeugt werden, welche die Datenbankstruktur erzeugen. IDEF1X (siehe [IDEF]) ist eine Datenmodellierungssprache, welche auf dem Ansatz des Entity-Relationship-Modells (ER-Modell) basiert und außerdem Konzepte des Relationenmodells von [Cod 70] enthält. Ziel dieser Modellierungsform ist eine bessere grafische Repräsentation (siehe [Ade 94, S. 9 f.]). Genauso wie in einem ER-Modell werden Entitäten durch Rechtecke dargestellt. Die Attribute werden dabei direkt in die Rechtecke hineingeschrieben, wie in Abbildung 55 auf Seite 85 zu sehen ist. Die so genannten schwachen Entitäten (siehe [Vor 99, S. 22 f.]) im ER-Modell werden im IDEF1X-Modell als abhängige bezeichnet und durch ein Recheck mit abgerundeten Ecken dargestellt. Diese Entitäten ergeben nur zusammen mit einer unabhängigen Entität eine Information, so wie in Abbildung 55 auf Seite 85 die Entitäten Klassen ProjectEmployee, TeamEmployee und ActivityEmployee. Vererbung wird zwar im IDEF1X-Modell unterstützt, kann aber weder im ERwin noch in der relationalen Datenbank realisiert werden (siehe [Ett 99, S. 41 bis 47]). Die Primärschlüssel werden am oberen Ende einer Entität dargestellt und durch eine horizontale Linie von den übrigen Attributen getrennt. Fremdschlüsselattribute werden durch das Kürzel (FS) dargestellt. Während das ER-Diagramm nur die Abhängigkeiten beschreibt und Primärschlüssel definiert, werden diese in dem IDEF1X-Modell genauer spezifiziert. Bei den 17 r siehe Homepage von Computer Associates : http://www.ca.com 83 Beziehungen zwischen den Entitäten werden zwei Arten unterschieden: identifizierende und nicht-identifizierende. Bei einer identifizierenden Beziehung ist der Fremdschlüssel gleichzeitig ein Primärschlüssel, während bei einer nicht-identifizierenden Beziehung dies nicht der Fall ist. Ein Beispiel für eine identifizierende Verbindung ist die Verbindung zwischen Employee und EmployeeAccount in Abbildung 55. Das Primärschlüsselattribut EmployeeID in der Entität EmployeeAccount ist gleichzeitig der Fremdschlüssel zum Primärschlüsselattribut EmployeeID in Employee. In den meisten Fällen wurden in der Zeiterfassung nicht-identifizierende Beziehungen gewählt und ein entsprechend neuer Primärschlüssel wurde angelegt. Damit besitzt fast jede Entität nur einen Primärschlüssel und Abhängigkeiten zwischen den Primärschlüsseln können gar nicht erst auftreten. Weitere Gründe werden in Kapitel 6.7.5 aufgeführt. Nicht-identifizierende Beziehungen werden durch eine gestrichelte Linie dargestellt. Der ausgefüllte Punkt am Ende einer Beziehungslinie beschreibt, welche Entität durch einen Fremdschlüssel mit der dazugehörigen Entität verbunden ist. Der nicht ausgefüllte Punkt, wie in Abbildung 55 an der Beziehung zwischen Employee und ProjectTeam zu sehen ist, bedeutet, dass der Fremdschlüssel auch den Wert NULL besitzen darf, was sonst nicht der Fall ist. Das Tool ERwin bietet außerdem die Möglichkeit, die referenziellen Aktionen für das Einfügen (I-nsert), Ändern (U-pdate) und Löschen (D-elete) darzustellen. Dabei sind die in Kapitel 6.2.4 beschriebenen fünf Einstellungen möglich, wobei nur Schlüsselverbindungen, die auch Null sein dürfen, auf Set Null gesetzt werden dürfen. Der Ausdruck D:C bedeutet beispielsweise, dass das Löschen eines Datensatzes kaskadiert wird (siehe Kapitel 6.2.4), d. h., das Löschen eines Mitarbeiters (Employee) führt zu einem Löschen aller seiner Accounts (EmployeeAccount) (siehe Abbildung 55). 6.7.2 Entwurf des Datenmodells In diesem Abschnitt wird an einigen Beispielen gezeigt, welche konkreten Probleme sich bei der Entwicklung des relationalen Datenmodells ergeben haben und wie diese gelöst wurden. Wie bereits in Abbildung 55 zu sehen ist, ist die Struktur der Entitäten nicht ohne weiteres ersichtlich. Während in einem Klassenmodell Konzepte zur Verfügung gestellt werden, mit denen Beschreibungen der Realität im Modell abgebildet werden können (vgl. [Fra+ 96, 2.Kapitel]), können diese nicht direkt abgebildet werden. Beispielsweise ist ein externer Mitarbeiter eine spezielle Form eines Mitarbeiters und kann durch Vererbung im Klassenmodell auch so modelliert werden. Diese Möglichkeit bietet das relationale Datenmodell nicht. Ein weiteres Problem ist das Fehlen der Aggregationsbeziehung. Im Klassen84 modell von Abbildung 8 auf Seite 28 ist die Verbindung von Projekt (Project) zu Fachgruppe (ProjectTeam) eine Aggregation, d. h., ein Projekt besitzt Fachgruppen (siehe auch [Bit Koc 00, S.18 f.]). Diese Modellierungsform ist in IDEF1X nicht möglich (siehe [Ett 99, S. 48]). Eine Kompositionsbeziehung abzubilden, so wie sie in Abbildung 8 auf Seite 28 zwischen Mitarbeiter und Account besteht, ist in IDEF1X ebenfalls nicht möglich (siehe [Ett 99, S. 49]). Es besteht lediglich die Möglichkeit, diese über die Fremdschlüsseleigenschaften nachzubilden (siehe Kapitel 6.2.4). Wie in Abbildung 55, an der Verbindung zwischen Employee und EmployeeAccount zu sehen ist, wurde diese als Delete Cascade (D:C) gekennzeichnet. Abbildung 55: Datenmodell nach der IDEF1X-Notation (siehe Kapitel 6.7.1) 85 Das Datenmodell wurde direkt im ERwin erstellt. Ein Entwurf mit einem Klassenmodell hätte dazu verführt, durch zu viele Klassen und Vererbung eine Struktur zu entwerfen, die im IDEF1X-Modell, was von ERwin unterstützt wird, sehr unübersichtlich geworden wäre. In Kapitel 6.8.2 wird dieses Problem an einem Beispiel gezeigt. Kalenderwochen und Mitarbeiter Bei der Analyse mit Requirements Engineering (siehe Mitarbeiter in Kapitel 3.1.4 und Kapitel 3.1.2) und im Entwurf (siehe Kapitel 5.3.5) wurden lediglich Wochen bzw. Kalenderwochen erwähnt. Im Datenmodell müssen diese mit abgespeichert werden (siehe Week ), da Mitarbeiterwochen (siehe EmployeeWeek ) von diesen abhängig sind. Außerdem besitzen Wochen zwei zusätzliche Flags, die identifizieren, ob eine Kalenderwoche für interne bzw. externe Mitarbeiter bereits abgerechnet wurde, wobei hier nur von Vertragsmitarbeitern die Rede ist, d. h. Mitarbeitern, die in Projekten arbeiten und ihre Zeiten den Projekten zuordnen müssen. Bei den Vertragsmitarbeitern gibt es zwei Arten: interne und externe. Interne Mitarbeiter unterteilen sich wiederum in ”normale” interne Mitarbeiter, Studenten und Aushilfen. Da das relationale Datenmodell keine Vererbung anbietet, die Tabellen aber noch die Entitäten widerspiegeln sollen, wurde das Problem wie folgt gelöst: Externe Mitarbeiter besitzen in ihren Verträgen die EmployeeTypeID null. Eine EmployeeTypeID größer Null definiert einen internen Mitarbeiter, wobei in der Tabelle EmployeeType die verschiedenen Arten der internen Mitarbeiter (Stundenten, Aushilfen und ”normale interne Mitarbeiter”) abgespeichert werden. Damit ist die Liste der internen Mitarbeitertypen beliebig erweiterbar. Mitarbeiter und ihre Verträge Jeder Vertragsmitarbeiter besitzt eine beliebige Menge an Verträgen. Diese Verträge besitzen für jede Kalenderwoche Arbeitszeiten. Jede Vertragsmitarbeiterwoche (EmployeeWeek ) kann durch Setzen des Flags Finish geschlossen werden. In diesem Fall dürfen keine Zuordnungen der Arbeitszeiten zu Projekten, Fachgruppen oder Aufgabenkatalogen durchgeführt werden. Die Verträge der Vertragsmitarbeiter dürfen sich nicht überschneiden, da jeder Vertragsmitarbeiter zu jedem Zeitpunkt nur einen Vertrag besitzen darf. Mitarbeiter, die aus Sicht der Zeiterfassung keine Verträge besitzen, dürfen zwar Projektleiter oder Fachsprecher sein, besitzen aber entsprechend keine Einträge in der Tabelle EmployeeContract, wie in Abbildung 55 zu sehen ist. Projekte und Fachgruppen 86 Jedes Projekt besitzt eine beliebige Menge an Fachgruppen. Auch in diesem Fall gibt es zwei Arten von Projekten: Projekte mit Fachgruppen und Projekte ohne. Bei Projekten ohne Fachgruppen müssen aber ebenfalls Zuordnungen nach Aufgabenkategorien vorgenommen werden. Ein Eintrag in der Tabelle ActivityEmployee muss jedoch von einem ProjectTeam abhängig sein. Um keine weiteren Tabellen einzufügen, besitzt jedes Projekt eine Default-Fachgruppe, die dadurch gekennzeichnet ist, dass sie keinen Fachsprecher besitzt. Zeitzuordnungen auf Aufgabenkataloge in Projekten, die keine Fachgruppe besitzen, werden auf diese Default-Fachgruppe geschrieben. In den Ausgaben wird diese Fachgruppe unter dem Namen ”Sonstige Fachgruppen” dargestellt. Arbeitszeitzuordnungen auf Projekte, Fachgruppen und Aufgabenkatalog Die Zuordnungen der Arbeitszeiten zu den Projekten, Fachgruppen und Aufgabenkatalogen werden in den Tabellen ProjectEmployee, TeamEmployee und ActivityEmployee abgespeichert. Ein Überblick über beispielsweise einen Mitarbeiter in einer ausgewählten Kalenderwoche ist nur über mehrere Anfragen möglich. Im weiteren Verlauf wird noch gezeigt, wie dieses Problem in einer objektorientierten Datenbank besser gelöst werden kann. Zunächst wird die Mitarbeiterwoche (EmployeeWeek ) ermittelt. Für eine ausgewählte Kalenderwoche und einen ausgewählten Mitarbeiter wird diese durch einen Verbund von Employee, EmployeeContract, EmployeeWeek und Week ermittelt. Anschließend müssen, abhängig von EmployeeWeek, die darin enthaltenen Projekte (ProjectEmployee und Project) bestimmt werden. Für jedes Projekt wird die Liste aller zugeordneten Fachgruppen (TeamEmployee und ProjectTeam) und die darin enthaltenen Aufgabenkataloge (ActivityEmployee und Activity) ausgelesen. 6.7.3 (SQL-)Transaktionen Der Zugriff auf die relationale Datenbank erfolgt in der Zeiterfassung über eine Instanz der Klasse Database, wie in Abbildung 56 dargestellt, welche die ODBCSchnittstelle bzw. die ODBC-Klassen von .NET verwendet. Beim Erzeugen einer Instanz dieser Klasse wird eine serialisierte Transaktion geöffnet, die beim Entfernen dieser Instanz wieder geschlossen wird. Wie in Kapitel 6.3.4 schon beschrieben wurde, gibt es in einer relationalen Datenbank keine wirklich brauchbare Lösung, um eine optimistische Nebenläufigkeitskontrolle durchzuführen. In Kapitel 6.3.3 wurde gezeigt, dass das Phantom Read durchaus ein Problem darstellt. 87 Abbildung 56: Klasse Database Durch Serialisieren der Transaktionen ist dieses Problem gelöst. Da Performanz und eine hohe Last bei der Zeiterfassung keine allzu wichtigen Themen sind, kann diese Lösung auch hingenommen werden. Bei einem Fehler, weil beispielsweise ein Lock gesetzt ist, wird eine Exception geworfen, die entsprechend abgefangen werden muss. In Abbildung 57 ist ein Beispiel für eine Anwendung dieser Klasse dargestellt. Die getData-Methoden (siehe Abbildung 56) geben nach einem gesendeten Query (siehe db.Query) die gewünschten Attribute eines Tupels zurück. In der ODCBKlasse OdbcDataReader können die Attribute nur über die Spaltennummer abgefragt werden, da es aber sinnvoller ist, diese über ihren Namen (in Abbildung 57, Zeile 5 ”name”) zu identifizieren, werden in den getData-Methoden entsprechende Umwandlungen vorgenommen. Der Vorteil dieser Variante ist die Unabhängigkeit zu Odbc. Ein Austauschen der (relationalen) Datenbank, für die beispielsweise kein Odbc-Treiber existiert, hätte nur eine Änderung an dieser Klasse zur Folge. Das Protokollieren von gesendeten Queries beispielsweise müsste ebenfalls nur an dieser Klasse, genauer gesagt in der Methode Query, durchgeführt werden. 88 (1) (2) (3) (4) (5) ... (6) (7) Database db = new Database() ); db.Query( ”SELECT * FROM CostCenter ORDER BY CostCenterID” ); while( db.getNextRecord() ){ CostCenter data = (CostCenter)this.CreateObject(); data.Name = db.getData(”name”); } db.Dispose(); // zum Beenden einer Transaktion Abbildung 57: Beispielanwendung für die Klasse Database ohne Ausnahmebehandlung 6.7.4 Sichten Unabhängige Entitäten besitzen allein betrachtet keine sinnvollen Informationen und müssen mit abhängigen verbunden werden. Die abhängigen Entitäten können aber ebenfalls nicht sinnvoll allein betrachtet werden. Für die Anfragen nach einer Menge von Projekten werden beispielsweise auch die Namen der zugehörigen Projektleiter, Projekttypen und Projektgruppen benötigt. Aus diesem Grund wurden, wie in Abbildung 58 zu sehen ist, Sichten für verschiedene Entitäten definiert. Die verwendete Namenskonvention ist dabei ”<Tabellenname>View”. Sicht EmployeeAccountView EmployeeView EmployeeWeekView ProjectTeamView ProjectView ProjectEmployeeView TeamEmployeeView ActivityEmployeeView CurrentEmployee Zusätzliche Tabellen bzw. Sichten EmployeeView EmployeeContract, EmployeeType u. CostCenter Employee u. EmployeeContract Project u. Employee ProjectType, ProjectGroup, Employee u. ProjectTeam Project u. EmployeeWeek ProjectTeam u. EmployeeWeek Activity u. EmployeeWeek EmployeeView mit Einschränkung Abbildung 58: Sichten aus der Zeiterfassung Für Anfragen sind Sichten ein vorteilhaftes Konzept, um die Anfragen zu vereinfachen, wie in Abbildung 58 zu sehen ist. Das Löschen von abhängigen Entitäten kann dabei kaskadiert werden, wie dies beispielsweise bei Employee und EmployeeAccount der Fall ist. Wird ein Mitarbeiter 89 gelöscht, so werden alle dazugehörigen Accounts mit gelöscht. Beim Einfügen und Ändern von Entitäten ist dies etwas schwieriger. Wie bereits in Kapitel 6.2.7 erwähnt wurde, bestand keine Möglichkeit, in den Sichten Datensätze einzufügen oder diese zu ändern. In Abbildung 59 ist die Eingabemaske für Vertragsmitarbeiter zu erkennen. Wie dort zu sehen ist, werden Mitarbeiter-, Vertrags- und Accountdaten erfasst. Das Einfügen eines Vertragsmitarbeiters erstreckt sich in diesem Fall über die drei Tabellen Employee, EmployeeAccount und EmployeeContract. Abbildung 59: Screenshot: Eingabemaske der Vertragsmitarbeiter 6.7.5 Primärschlüssel und Identität Ein Problem bei der Datenmodellierung stellte die Definition der Primärschlüssel dar. Eine Komposition beispielsweise kann als eine identifizierende Verbindung zwischen zwei Entitäten modelliert werden, wobei die Fremdschlüssel gleich dem Primärschlüssel sind (vgl. [Ade 94, S. 13]). Ein Beispiel ist die Verbindung zwischen Fachgruppe und Projekt in Abbildung 8 auf Seite 28. Ein Projekt kann nur existieren, wenn die dazugehörige Fachgruppe existiert. Die Verbindung zwischen Fachgruppe und Projekt ist ebenfalls eine Komposition, d. h., diese Verbindungen können als identifizierende modelliert werden. Das Resultat war, dass eine Fachgruppe von den drei Schlüsseln, der Projektgruppe, dem Projekt und der Fachgruppe, abhängig war, d. h. einen zusammengesetzten 90 Primärschlüssel aus diesen drei Attributen besaß, wie in Abbildung 60 zu sehen ist. Abbildung 60: zusammengesetzter Primärschlüssel Dies stellt aber eine Verletzung der zweiten Normalform dar, da es keinen Unterschied macht, ob für die Identifizierung eines Datensatzes aus ProjectTeam das Attribut ProjectGroupID verwendet wird oder nicht. Aus diesem Grund wurde die Verbindung zwischen Projekt und Projektgruppe in eine nicht-identifizierende geändert. Ein weiteres Problem ist, dass sich bei identifizierenden Verbindungen die Schlüsseldefinition ”ausbreitet”, d. h. wenn ein Projekt beispielsweise nicht mehr durch eine Projektgruppe identifiziert wird, so würde das Löschen der Projektgruppe zu einer geänderten Definition in der Tabelle ProjectTeam führen. Das Primärschlüsselattribut ProjectGroupID wird dann in ProjectTeam ebenfalls gelöscht, obwohl keine direkte Verbindung zwischen ProjectTeam und ProjectGroup besteht. Ein weiteres Problem stellte die Tatsache dar, dass eine Entität, die durch mehr als ein Attribut im Primärschlüssel identifiziert wird, keine automatisch erzeugten Primärschlüssel (vgl. mit serial in Kapitel 6.2.2) erzeugen kann, d. h., der Primärschlüssel hätte manuell erzeugt werden müssen. Da sich die Anforderungen einige Male geändert haben (vgl. mit Prototyping in Kapitel 3.1.5), wurde dazu übergegangen, für jede Entität nur ein Attribut als Primärschlüssel zu verwenden und die Verbindungen zwischen Entitäten durch nicht-identifizierende zu ersetzen. Das Problem mit den Projektnummern, die als Primärschlüssel verwendet werden, wurde bereits in Kapitel 6.2.2 beschrieben. Aus diesem Grund wurde fast überall ein technischer Schlüssel eingeführt, der sozusagen die Objektidentität simulieren soll. Dieser ist in jeder Tabelle eindeutig und vom Anwender nicht änderbar bzw. sollte nicht geändert werden. 6.7.6 Referenzielle Integrität Die referenzielle Integrität verhindert, dass eine Datenbank in einen inkonsistenten Zustand kommen kann, wie in Abbildung 61 an einigen Beispielen für Projekt und 91 Projekttyp dargestellt ist. Komplexe Integritätsprüfungen können nur über Trigger realisiert werden, wobei die fehlende Kapslung hier ein Problem darstellt. Dadurch, dass an jeder beliebigen Stelle in der Datenbank Änderungen vorgenommen werden können, müssen verschiedenste Trigger an allen möglichen Stellen eingeführt werden. Änderungen an den Tabellen hätten Änderungen an den entsprechenden Triggern zur Folge, wobei die Abhängigkeiten und Integritätsprüfungen ziemlich schnell sehr komplex und unübersichtlich werden können. Das folgende Beispiel soll dies verdeutlichen: Eine Mitarbeiterwoche (EmployeeWeek ) darf nur dann den Zustand Finish=True besitzen, wenn bestimmte Voraussetzungen der Tabellen ProjectEmployee, TeamEmployee und ActivityEmployee erfüllt sind. Da diese drei Tabellen durch die fehlende Kapselung beliebig geändert und gelöscht werden können, müssen in diesen Tabellen ebenfalls entsprechende Überprüfungen vorgenommen werden. Dieses Datenmodell ist noch relativ einfach. Bei größeren Modellen, an denen mehrere Entwickler beteiligt sind, kann dies zu einem großen Problem werden, wenn sich die Abhängigkeiten über mehrere Tabellen erstrecken. • Ein Projekt kann keinem Projekttyp zugeordnet werden, welcher nicht existiert. • Ein Projekttyp kann nur gelöscht werden, wenn kein Projekt auf dieses Projekt verweist. • Ein Projekt, das eingefügt wird, muss auf einen gültigen Projekttypen verweisen. Abbildung 61: Beispiel für referenzielle Intrität zwischen Projekt und Projekttyp 6.8 6.8.1 Motivation zur Objektorientierung in Datenbanken Vorteile einer relationalen Datenbank Die relationale Datenbank bietet trotz der vielen Schwächen eine Reihe von Vorteilen, wie in Abbildung 62 zu sehen ist, wobei sich die letzten beiden Punkte auf die Tatsache beziehen, dass Daten in Tabellen abgespeichert werden und auf diese einfach zugegriffen werden kann. Wie schon gezeigt wurde, ist der Zugriff auf die Informationen, die durch die Beziehungen der Tabellen untereinander dargestellt werden, teilweise nur mit sehr komplizierten Queries möglich. 92 • In der Regel sind relationale Datenbanken auch bei sehr großen Datenmengen noch sehr leistungsstark. • Die relationalen Datenbanken werden in der Regel von großen Firmen entwickelt, die viel Erfahrung auf diesem Gebiet besitzen. • Relationale Datenbanken haben sich in der Vergangenheit schon mehrfach bewährt. • Durch Normalisierung wird Redundanz vermieden oder wenigstens gemindert. • Durch mathematische Regeln lassen sich die Abhängigkeiten, Einschränkungen und Bedingungen der Daten beschreiben und müssen nicht implementiert werden. • Durch den SQL-Standard besteht (zumindest theoretisch) eine Unabhängigkeit von Anwendung und Datenbank [Saa 03, S. 35]. • Ein relationales Datenmodell hat eine einfache Struktur (Tabellen und Schlüsselverbindungen). • Über ein entsprechendes Tool und SQL kann in einer relativ einfachen Form auf die Daten zugegriffen werden. Abbildung 62: Vorteile einer relationalen Datenbank 6.8.2 Nachteile einer relationalen Datenbank Anhand eines konkreten Beispiels sollen die Probleme des relationalen Datenmodells erklärt werden. Die Beschreibungen basieren auf dem Datenmodell von Abbildung 55. Wie in Abbildung 63 zu sehen ist, gibt es zwei Arten von Mitarbeitern, die im Folgenden kurz erklärt werden. Mitarbeiter, die keinen Vertrag besitzen (Employee) (vgl. Kapitel 6.7.2), können Projektleiter (projectLeader ) in einem Projekt und Fachsprecher (teamLeader ) in einer Fachgruppe sein. Außerdem besitzen sie Benutzerrechte (EmployeeRole) und einen Namen (EmployeeName). Mitarbeiter, die bereits Fachsprecher oder Projektleiter gewesen sind, dürfen nicht gelöscht werden, da beispielsweise Statistiken über vergangene Projekte oder Fachgruppen die richtigen Projektleiter und Fachsprecher enthalten müssen. Diese werden durch Löschen eines Flags ( active) als nicht aktiv gekennzeichnet. In dem Beispiel von Abbildung 63 wird dieses Flag über die Methoden SetActive und GetActive gesetzt bzw. gelesen. Vertragsmitarbeiter (EmployeeWithContract) besitzen zusätzlich Verträge. Die 93 Abbildung 63: Nachteile eines relationalen Datenmodels anhand eines Beispiels Unterscheidung zwischen diesen beiden Mitarbeitertypen wird in dem relationalen Datenmodell über einen Subquery realisiert, der prüft, ob der entsprechende Mitarbeiter mindestens einen Vertrag besitzt. In der Variante von Abbildung 63 ist diese mühselige Anfrage nicht nötig. Außerdem werden Mitarbeiter, die mindestens einen Vertrag besitzen, beim Löschen anders behandelt. Beim Löschen wird der aktuelle Vertrag beendet. In der Variante von Abbildung 63 wird diese Funktionalität durch Überschreiben der Methoden realisiert. In Abbildung 55 besitzt die Tabelle Employee ein Flag active. Dieses hat für Vertragsmitarbeiter keine direkte Bedeutung. Um die Struktur des Datenmodells übersichtlich zu halten, wurde diese Schwäche hingenommen. Die Datentypen der Attribute müssen atomar sein, d. h., komplexe Datentypen, wie im Klassenmodell z. B. durch Vererbung möglich sind, müssen in anderer Form abgebildet werden. Wie in Abbildung 55 zu sehen ist, ist die Unterscheidung von Mitarbeitern mit und Mitarbeitern ohne Vertrag nicht sofort ersichtlich. Um die Trennung der Klassen Employee, EmployeeName und EmployeeRole in dem relationalen Datenmodell zu realisieren, wären zusätzliche Tabellen und Fremdschlüsselverbindungen nötig, welche die Mitarbeiteranfragen weiter verkomplizieren würden. Die Entitäten eines relationalen Datenmodells enthalten keine Funktionalitäten. Es besteht zwar die Möglichkeit, Funktionalität über benutzerdefinierte Routinen zu definieren, allerdings können diese nicht direkt an die Entitäten gebunden werden und nur einfache Datentypen zurückliefern. Eine benutzerdefinierte Routine, die alle 94 Mitarbeiter zurückliefert, die eine bestimmte Bedingung erfüllen, ist beispielsweise nicht möglich. Das Problem mit den Primärschlüsseln und den Identitäten wurde bereits in Kapitel 6.7.5 beschrieben. Durch die fehlende Kapselung (vgl. Kapitel 6.7.6) besteht keine Trennung von Schnittstelle und Realisierung, d. h., Daten können beliebig auf allen Tabellen geändert werden. Komplexe Integritätsprüfungen durch z. B. Trigger müssen alle denkbaren Fälle abfangen. Eine Entwicklung eines sehr großen Datenmodells von mehreren Entwicklern ist nur mit sehr viel Aufwand möglich. Ein Datenmodell in mehrere Teile zu zerlegen und nur über fest definierte Schnittstellen miteinander zu kommunizieren kann zwar vereinbart werden, wird aber in der Datenbank nicht unterstützt. 6.8.3 Object-Oriented Database System Manifesto Im Object-Oriented Database System Manifesto von 1995 [Atk+ 95] wurden die Anforderungen untersucht, die eine objektorientierte Datenbank erfüllen muss. Die Eigenschaften lassen sich in zwei Gruppen einteilen. Zum einen wurden die Anforderungen an eine objektorientierte Programmiersprache und zum anderen die Anforderungen an eine Datenbank untersucht. Eine ”gute” objektorientierte Datenbank sollte all diese Anforderungen erfüllen. Objektorientierte Eigenschaften: Komplexe Datentypen: Komplexe Datentypen müssen sich mithilfe von Konstruktoren aus einfachen (atomaren) Datentypen, wie zum Beispiel integer, boolean oder string, zusammensetzen lassen. Des Weiteren soll es verschiedene Arten von komplexen Konstruktoren, wie zum Beispiele Tupel, Set, Bag, Listen oder Arrays, geben. Die Objektkonstruktoren müssen orthogonal sein, d. h., jeder Konstruktor muss an jedes Objekt anwendbar sein. Objektidentität: Jedes Objekt muss eine eindeutige und von den Attributen unabhängige Identität besitzen, die systemweit (oder wenigstens datenbankweit) gültig ist. Damit können zwei Arten von Objektgleichheit unterschieden werden: identisch (das gleiche Objekt) und gleich (gleiche Werte, aber unterschiedliche Identität). Kapselung: Kapselung verhindert unzulässige Zustandsänderungen und verbirgt den Implementierungsteil. Damit entsteht eine saubere Trennung zwischen Schnittstelle und Implementierung und Änderungen in der internen Struktur werden nach außen nicht sichtbar. 95 Typen oder Klassen: Ein Typ in einem objektorientierten System fasst Objekte mit gleichen Eigenschaften zusammen. Dieser besteht auf einem Interface und der Implementierung. Nach außen sichtbar ist nur das Interface und die Implementierung bleibt dem Anwender diese Typs verborgen. Die Implementierung besteht aus Daten und Funktionalitäten. Eine Klasse wird zwar genauso wie ein Typ definiert, bietet aber noch zwei weitere Aspekte: Objekterzeugung und Objektcontainer. Durch einen new Operator werden Instanzen eines Objekts erzeugt und über den Objektcontainer können Operationen auf einer Menge aller Objekte dieser Klasse durchgeführt werden. Vererbung: Vererbung und Klassenhierarchien sollen möglich sein, um Attribute und Methoden wiederzuverwenden, zu erweitern, zu überschreiben oder zu spezialisieren. Overriding, Polymorphismus und dynamisches Binden: Overloading bedeutet, dass verschiedene Methoden mit gleichem Namen und unterschiedlichen Parametern definiert werden. Beim Aufruf einer Methoden wird anhand der Parameter entschieden, welche Implementierung verwendet wird. Durch Overriding wird dynamisches Binden möglich. In einer vererbten Klasse wird eine Methode überschrieben, d. h., die Implementierung wird geändert. Damit wird zur Laufzeit entschieden (late binding), welche Implementierung verwendet wird. Sprach- und Berechnungsvollständigkeit: Man kann jede berechenbare Funktion ausdrücken, was in SQL nicht vollständig möglich ist. Erweiterbarkeit von Typen: Das Datenbanksystem hat eine vordefinierte Menge von Datentypen, die verwendet werden können. Des Weiteren soll es aber auch möglich sein, neue Typen zu definieren, die nicht von den vordefinierten Typen unterschieden werden können. Datenbankeigenschaften: Persistenz: Die Lebensdauer eines Objektes soll länger sein als die Lebensdauer einer Applikation und soll im gleichen Zustand in einem weiteren Prozess verwendet werden können. (sekundäres) Datenmanagement: Sekundäres Datenmanagement ist eine Ansammlung von Mechanismen, die für den Anwender der Datenbank nicht sichtbar sind und z. B. die Performanz verbessern sollen. Diese sind z. B. Indizierung, Pufferung, Zugriffsmanagement, Daten-Cluster oder Queryoptimierung. Es wird gefordert, dass der Anwender keinen zusätzlichen Code schreiben muss, um z. B. einen Index aktuell zu halten o. Ä., d. h., es soll eine Trennung zwischen der logischen und physikalischen Ebene des Systems geben. 96 Nebenläufigkeit: Mehrere Benutzer sollen parallel auf einer Datenbank arbeiten können, ohne dass es zu inkonsistenten Zuständen kommt. Diese Eigenschaft beschreibt im Wesentlichen die Problematik, die schon in Kapitel 6.3.3 beschrieben wurde. Recovery: Im Falle eines Ausfalls durch einen Hardware- oder Softwarefehler, muss eine Rekonstruktion des alten und konsistenten Zustandes möglich sein. Ad hoc Abfragemöglichkeit: Durch eine einfach Anfragesprache soll es möglich sein, Inhalte aus der Datenbank auszulesen. Die Anfragesprache sollte dabei folgende Bedingungen erfüllen: 1. Sie sollte einfach sein, bzw. es sollte möglich sein, in kurzen Anfragen Informationenen erhalten. 2. Sie sollte effizient sein (z. B. durch Query-Optimierung). 3. Sie sollte unabhängig von der Applikation sein, d. h., die Anfragesprache sollte auf jeder möglichen Datenbank gleichermaßen funktionieren. Diese Anforderungen werden im folgenden Kapitel anhand einer objektrelationalen Datenbank untersucht. Bei der objektrelationalen Datenbank wird von einer SQL-99-komformen Datenbank ausgegangen, d. h., es wird geprüft, inwieweit eine Datenbank, die diesem Standard entspricht, die gestellten Anforderungen erfüllt. Den Abschluss bildet ein kurzer Überblick über die Möglichkeiten mit einer objektorientierten Datenbank. Dabei bildet die Datenbank FastObjects .NET von Poet die Grundlage. 97 7 7.1 Implementierung mit objektrelationaler Datenbank Einleitung Während in der relationalen Datenbank eine strikte Trennung zwischen Daten und Semantik besteht, soll diese Trennung durch Hinzufügen weiterer Anwendungslogik in die Datenbank verringert werden. Durch die Bildung von komplexen und geschachtelten Datentypen können beliebige Strukturen gebildet werden. Zusätzlich kann Verhalten an die Tupel gebunden werden, wodurch Tupel zu Objekten im objektorientierten Sinne werden. Das Ziel des objektrelationalen Datenmodells ist es, ein Klassenmodell eins-zu-eins auf das Datenmodell abbilden zu können. Im Idealfall existiert die komplette (objektorientierte) Anwendungslogik in der objektrelationalen Datenbank und nur ein einfaches grafisches Benutzerinterface wird benötigt, um Funktionalitäten auszuführen und Daten, die gekapselt sind, abzufragen und zu manipulieren. Dabei sollen die Vorteile einer relationalen Datenbank nicht verloren gehen. Bei der Entwicklung einer objektrelationalen Datenbank gibt es prinzipiell zwei Herangehensweisen. Die erste Möglichkeit ist die Entwicklung eines objektrelationalen Datenmodells auf der Basis eines Klassenmodells. Dieses Thema wird in Kapitel 7.5 kurz angesprochen. Der andere Weg, der hier detaillierter vorgestellt wird, besteht darin, das relationale Datenmodell schrittweise um objektrelationale Konzepte zu erweitern. Als Vergleichsgrundlage dient das relationale Datenmodell in Abbildung 55 aus Kapitel 6.7.2 mit den Vergleichskriterien aus Kapitel 6.8.3. Wie bereits erwähnt wurde, ist der SQL-99 Standard, der die objektrelationalen Konzepte enthält, eine Erweiterung des SQL-92 Standards, wodurch sich schon erahnen lässt, dass dieser ziemlich umgangreich ist. Durch die Erweiterung von SQL-92 besteht in der objektrelationalen Datenbank die Möglichkeit relationale und objektrelationale Konzepte beliebig miteinander zu kombinieren. Die SQL-Dialekte der real existierenden Datenbanksysteme unterstützen die SQL99 Norm nur in höchst unvollständiger Form und sind zudem sehr heterogen (vgl. [Luf 02]). Eine konkrete Implementierung mit einer objektrelationalen Datenbank konnte nicht vorgenommen werden, da die zur Verfügung stehende Informix Datenbank 3.31 einige grundlegende Konzepte nicht unterstützt. Aus diesem Grund wird im Folgenden von einer SQL-99 konformen Datenbank ausgegangen. Größtenteils basieren die folgenden Kapitel auf den Darstellungen von [Tür 03]. Ausgehend von Kapitel 6 werden in diesem Kapitel die Erweiterungen für die Datendefinition (siehe Kapitel 7.2) und die daraus resultierenden Erweiterungen für 98 die Datenmanipulation und die Datenabfrage untersucht (siehe Kapitel 7.3). 7.2 7.2.1 Erweiterte Datendefinition Einleitung Durch Erweiterungen des relationalen Datenmodells um Konzepte wie komplexe Datentypen, Methoden, Objektidentitäten, Kapselung und Vererbung sollen die Vorteile einer relationalen Datenbank mit denen der Objektorientierung kombiniert werden. Im Folgenden werden die objektrelationalen Konzepte von SQL-99 vorgestellt, die dies ermöglichen. Basierend auf dem Datenmodell in Abbildung 55 aus Kapitel 6.7.2 werden jeweils Beispiele vorgestellt, die zeigen, wie das relationale Datenmodell erweitert werden kann. Benutzerdefinierte Typen und strukturierte Typen bilden die Grundlage zur Definition von komplexen und geschachtelten Typen. Dabei werden die benutzerdefinierte Typen in unbenannte und benannte unterteilt. Unbenannte Typen sind Tupeltypen, Arrays und Refererenztypen. Im Gegensatz dazu gibt es die Distinct Datentypen (vgl [Tür 03, S. 50 f.]), die, ähnlich zu dem Konzept der Domänen (vgl. Kapitel 6.2.1), neue Typen definieren. Im Gegensatz zu den Domänen sind diese streng typisiert. Benutzerdefinierte Datentypen können als Attribute in Tabellen definiert werden und geben somit der Tabelle mehr Struktur. Strukturierte Typen sind klassenähnliche Typen, die durch Definition einer Objektidentität zu Klassen werden. Von diesen können Instanzen gebildet werden, die ähnlich den Objekten im objektorientierten Sinne sind. Die Klassen bieten das Konzept der Vererbung an und ermöglichen dynamisches Binden, wie in Kapitel 7.2.4 beschrieben wird. Verwaltet werden strukturierte Typen in typisierten Tabellen. Typisierte Tabellen bilden sozusagen einen Container (vgl. [Luf 99]) für Objekte bzw. strukturierte Typen. Durch die Definition von Referenzen in den strukturierten Typen werden die in der relationalen Datenbank verwendeten Verbunde ersetzt, d. h., auf die abhängigen Tabellen wird durch eine aufgelöste Referenz zugegriffen (vgl. 6.4.1). Eine Erweiterung der Sichten des relationalen Datenmodells (vgl. 6.2.7) sind die typisierten Sichten. Durch diese können Sichten auf strukturierte Typen bzw. Objekte definiert werden. 7.2.2 Distinct-Typen Ähnlich zu dem Prinzip der Domänen definieren Distinct-Typen neue Datentypen. Für Distinct-Typen kann keine Einschränkung definiert werden. Sie sind lediglich 99 eine Kopie des angegebenen Basistyps. Der entscheidene Vorteil ist, dass diese streng typisiert sind. Das Konzept der Vererbung bieten Distinct-Typen nicht. 7.2.3 Unbenannte Typkonstruktoren Definiert wird ein unbenannter Typ durch einen Typkonstruktor. Im Folgenden werden die drei in 7.2.1 vorgestellten unbenannten Typkonstruktoren vorgestellt. Tupeltypkonstruktor Durch Tupeltypkonstruktoren lassen sich Tupel bilden, die als Attribute in Tabellen verwendet werden können. Logisch zusammengehörige Attribute können somit zusammengefasst werden und geben dem relationalen Datenmodell mehr Struktur. Wie in Abbildung 64 zu sehen ist, können der Name und die Benutzerrechte eines Mitarbeiters jeweils als Tupel definiert werden. Ein Mitarbeiter besitzt dann nur noch die zwei Attribute: Name und Role. Die Gruppierung von Attributen ist, vor allem wenn es sich um Tabellen mit sehr vielen Attributen handelt, ein gutes Konzept um verständlichere Modelle zu erzeugen. Zugegriffen wird auf die Elemente eines Tupeltyps über die Punktnotation, wie in Abbildung 64,(5) gezeigt. (1) (2) (3) (4) ... (5) ... CREATE TABLE Employee ( Name ROW( Firstname VARCHAR(50), Lastname VARCHAR(50) ), Role ROW( Admin BOOLEAN, DepartLeader BOOLEAN, ... ) ) SELECT ... FROM Employee WHERE ... Employee.Name.Firstname Abbildung 64: Beispiel für Tupeltypkonstruktor Arraytypkonstruktor Ein weiteres Konzept der unbenannten Typkonstruktoren ist der Arraytypkonstruktor. Für die Typen, die in einem Array enthalten sind, sind alle Elementtypen zulässig. Komplexe Datentypen und geschachtelte Arrays (vgl. [Tür 03, S. 47]) sind nicht möglich, d. h., SQL-99 ist nicht vollständig orthogonal, so wie es in [Atk+ 95] (vgl. 6.8.3) gefordert wurde. Für den Datenbankentwurf bedeutet dies, dass in der Entwicklung immer Ausnahmeregeln und Sonderfälle beachtet werden müssen und die Möglichkeiten des Datenbankentwurfs eingeschränkt sind. Problematisch ist dies vor allen dann, wenn ein Klassenmodell in einer objektrelationalen Datenbank abgebildet werden soll (sie- 100 he Kapitel 7.5). CREATE TABLE Employee ( ... Accounts VARCHAR(15) ARRAY[20] ... ) Abbildung 65: Beispiel für Arraytypkonstruktor Die Accounts der Mitarbeiter aus der Zeiterfassung sind ein gutes Beispiel für die Verwendung von Arrays (vgl. Abbildung 65). Um der ersten Normalform zu entsprechen, wurden die Accounts in eine separate Tabelle EmployeeAccount ausgelagert und über die Fremdschlüsselverbindung EmployeeID mit der Tabelle Employee verbunden (vgl. Abbildung 55 aus Kapitel 6.7.2). Da diese Tabelle nur ein elementares Attribut, nämlich Windowsname enthält, kann diese als ein Array in Employee verwendet werden. Wie in Abbildung 65 zu sehen ist, besteht darüber hinaus die Möglichkeit, die Menge der Elemente in dem Array zu beschränken. Diese Beschränkung wäre in der relationalen Datenbank nur durch zusätzliche Integritätsbedingungen möglich (vgl. 6.2.5). Die Meinungen, ob es sich bei den Array und Tupeltypen um eine Verletzung der ersten Normalform handelt, gehen dabei auseinander (vgl. [Eis+ 99, S. 2] und als Beispiel [Saa 03, S. 533]). Prinzipiell bilden diese Konstrukte nur eine andere Form der Darstellung. Über einen Unnest-Operator lässt sich ein Array wieder in eine Tabelle transformieren, wie in Abbildung 66 dargestellt ist. Abfrage auf der Tabelle von Abbildung 55: SELECT * FROM Employee e, EmployeeAccount a WHERE e.EmployeeID=a.EmployeeID Abfrage auf der Tabelle von Abbildung 65: SELECT * FROM Employee UNNEST(Accounts) Abbildung 66: Beispiel für eine SQL-Anfrage auf einem Array Referenztypkonstruktor Während in einer relationalen Datenbank die Abhängigkeiten der Tabellen untereinander über Schlüsselverbindungen definiert werden, besteht bei einer objektrelationalen Datenbank die Möglichkeit, diese über Referenzen zu verbinden. Referenzen sind, anders als Fremdschlüsselverbindungen, streng typisiert und können nur auf 101 typisierte Tabellen angewendet werden. Das Konzept der typisierten Tabellen wird in Kapitel 7.2.4 noch detaillierter beschrieben. Ein Beispiel für eine Referenz ist die Verbindung von Employee und Project (vgl. Abbildung 55 aus Kapitel 6.7.2). Während in dem relationalen Datenmodell die Projektleiter (ProjectLeader ) der Projekte über einen Verbund aus Employee und Project ermittelt werden müssen, können diese über Referenzen direkt angesprochen werden. Eine Anfrage aller Projekte mit ihren Projektleitern, die Bedingung X erfüllen, könnte dann über eine Referenzauflösung realisiert werden, wie im Beispiel von Abbildung 67 dargestellt. Referenzen haben zum einen den Vorteil, dass dadurch Queries verständlicher formuliert werden können, zum anderen sind Zugriffe über Referenzen sehr viel effizienter, als aufwendige Verbunde über mehrere Tabellen. Definition in Project: COLUMN ProjectLeaderID REF(Employee) .. Alter Query: SELECT e.Lastname as ProjectLeaderLastname FROM Project p, Employee e WHERE p.ProjectLeaderID = e.EmployeeID AND X Neuer Query: SELECT ProjectLeaderID->EmployeeID FROM Project WHERE X Abbildung 67: Beispiel für einen Referenztypkonstruktor Dieses Beispiel ist noch relativ einfach. Bei aufwendigeren Anfragen, die sich über mehrere Tabellen erstrecken, sieht man den Nutzen. Eine Anfrage, die beschreibt, in wie vielen Projekten der Projektgruppe X ein Mitarbeiter Y bereits Projektleiter war, würde dann wie in Abbildung 68 aussehen. SELECT COUNT(*) FROM Project p WHERE p->ProjectGroupID->Name=X AND p->ProjectLeaderID->Lastname=Y Abbildung 68: Beispiel für die Vorteile von Zugriffen über Referenzen Die Beispiele bildeten jedoch nur 1:1-Beziehungen ab. Zur Realisierung einer 1:nBeziehung muss ein Array der Größe n von Referenzen gebildet werden. Abbildung 69 stellt die 1:n-Beziehung zwischen Mitarbeitern und ihren Verträgen dar. Statt einer ungerichteten m:n-Beziehung muss der Umweg über zwei gerichtete 1:n-Beziehungen gegangen werden (vgl. [Lau 01]). 102 CREATE TYPE EmployeeType AS (... contract REF(ContractType) Array[n] ...); Abbildung 69: Beispiel für 1:n-Relation 7.2.4 Strukturierte Typen Strukturierte Typen sind ebenfalls benutzerdefinierte Typen mit einigen Erweiterungen (vgl. Abbildung 70). Sie entsprechen in etwa dem Konzept der Klasse und enthalten Attribute und Methoden. Durch Vererbung ermöglichen sie das Konzept der Substituierbarkeit. Jedes Attribut wird vom System automatisch gekapselt. Im Folgenden wird beschrieben, wie diese Konzepte realisiert wurden und welche Schwierigkeiten sich dabei ergeben. komplexe Datentypen: Strukturierte Typen können mehr als ein Attribut definieren und jedes Attribut kann wiederum ein beliebiger Datentyp sein. Verhalten: Das Verhalten eines strukturierten Typs kann durch Methoden, Prozeduren und Funktionen realisiert werden. Kapselung: Für jedes Attribut wird vom System eine Observer- und eine Mutatormethode generiert (get- und set-Methoden). Vererbung: Jeder strukturierte Typ kann spezialisiert und generalisiert werden. Abbildung 70: Merkmale eines strukturierten Typs (basiert auf [Eis+ 99]) Wie in Abbildung 71 dargestellt, besteht ein strukturierter Typ aus einem Typnamen, Attributen und Methodendeklarationen. Damit ein strukturierter Typ zu einem Objekt im objektorientierten Sinne wird, muss eine Objektidentität definiert werden. Es besteht zwar die Möglichkeit, diese abhängig von den Attributen oder noch schlimmer benutzerdefiniert zu definieren, da diese Einstellungen aber dem Grundgedanken (vgl. [Tür 03, S. 57 f.]) einer unabhängigen und systemverwalteten Objektidentität widersprechen würden, sollten diese durch den Ausdruck ”REF IS SYSTEM GENERATED” als vom System generiert gesetzt werden (vgl. auch Kapitel 6.8.3). Ein strukturierter Typ kann von einem anderen strukturierten Typen erben und zusätzliche Attribute und Methoden definieren und Methoden überschreiben. Dadurch wird Substituierbarkeit von strukturierten Typen möglich, d. h., überall, wo ein bestimmter Typ erwartet wird, kann auch ein abgeleiteter Typ eingesetzt werden. Attribute 103 CREATE TYPE <Typname> [UNDER <Suptertypname>] AS ( <Attribute>) [[NOT] INSTANTIABLE] [[NOT] FINAL] [<OID-Typspezifikation>] [<Methodendeklaration>] Abbildung 71: Aufbau eines strukturierten Typs Die Definition der Attribute erfolgt in einer ähnlichen Form wie die Definition der Attribute in einer Tabelle. Jedes Attribut besitzt einen Namen, einen Datentyp und optional einen Defaultwert. Für jedes Attribut werden vom System zwei Methoden erzeugt, welche die Attribute durch so genannte Observer - und Mutator -Methoden kapseln. Das Lesen bzw. Schreiben eines Attributs wird zwar wie ein direkter Attributszugriff durchgeführt, führt aber intern die entsprechende Methode aus. Die Methoden können überschrieben werden, wobei für jedes Attribut genau eine Observer - und eine Mutator -Methode vorhanden ist. Verschiedene Sichten auf ein Attribut sind damit nicht möglich. Dadurch dass die Observer - und die Mutator -Methoden den gleichen Namen wie ihre Attribute besitzen, kann eigentlich nicht wirklich von Kapslung gesprochen werden, da Änderungen an einem Attribut die Schnittstelle nach außen verändern würden (vgl. mit dem Punkt Kapselung aus Kapitel 6.8.3). Die einzige Form von Kapselung, die möglich ist, ist, die Bedingungen in einer überschriebenen Mutator- oder Observermethode zu definieren. Methoden Die Methodendeklaration erfolgt direkt in der Definition eines strukturierten Typs. Die dazugehörige Methodenimplementierung muss separat erzeugt werden und an den entsprechenden strukturierten Typ gebunden werden. Es gibt drei Arten von Methoden, die jeweils mit einem entsprechenden Schlüsselwort gekennzeichnet werden müssen: Instanzmethoden, Konstruktormethoden und statische Methoden. Die Instanz- und die Konstruktormethoden besitzen einen impliziten Self-Parameter (die Objektidentität oid ). Neben dem Überladen (overloading) von Methoden besteht die Möglichkeit, Methoden zu überschreiben. Methoden, die überschrieben wurden, müssen, genauso wie in C#, durch das Schlüsselwort OVERRIDING gekennzeichnet werden. Substituierbarkeit und das Überschreiben von Methoden ermöglichen dynamisches Binden. Neben den Aufrufen der Methoden in anderen Methoden können diese auch direkt in den SQL-Queries verwendet werden, um zum Beispiel in einer Where-Klausel eine Prüfung vorzunehmen. Im SQL-99 werden dabei einige 104 Einschränkungen definiert, wie in Kapitel 7.3 noch beschrieben wird. Diese verhindern unerwünschte Seiteneffekte. Zu jedem instanziierbaren strukturierten Typ wird ein Defaultkonstruktor angelegt, analog zu dem Defaultkonstruktor in der Objektorientierung. Der Konstruktor liefert eine Instanz des jeweiligen strukturierten Typs zurück. Außerdem besteht die Möglichkeit, weitere Konstruktoren mit Parametern zu definieren. Abstrakte und nicht weiter vererbbare Typen Durch den Zusatz Not Instantiable kann ein strukturierter Typ als abstrakt definiert werden, d. h., von diesem können keine Instanzen gebildet werden. Allerdings können keine abstrakten Methoden definiert werden. Der Zusatz FINAL gibt an, dass von diesem Typ nicht abgeleitet werden darf, und ist vergleichbar mit dem sealed in C#. Typprüfung Über das Konstrukt IS OF können Objekte auf ihre Typen hin überprüft werden, wobei mit dem Zusatz ONLY angegeben werden kann, ob genau dieser Typ (ohne seine Subtypen) oder ein Typ inklusive seiner Subtypen überprüft wird. Das Casten eines strukturierten Typs auf einen Subtypen ist durch TREAT (<Supertypname>) AS (<Subtypname>) ebenfalls möglich. Soweit ist (fast) alles so, wie man es von einer objektorientierten Sprache erwartet. Einige Konzepte, wie beispielsweise Sichtbarkeiten18 oder Interfaces, werden nicht unterstützt. Des Weiteren besteht keine Möglichkeit, Typen in Komponenten oder Packages und damit das Datenmodell in mehrere Teilmodelle zu unterteilen. 7.2.5 Typisierte Tabellen Eine typisierte Tabelle basiert auf einem strukturierten Typ und enthält eine Menge von strukturierten Typen. Gemäß [Atk+ 95] wird in einer objektrelationalen Datenbank zwischen (strukturierten) Typen und Tabellen (Klassen) unterschieden. In Abbildung 72 ist der Definitionsaufbau einer typisierten Tabelle vereinfacht dargestellt. Typisierte Tabellen können, genau wie strukturierte Typen, vererbt werden. Eine abgeleitete typisierte Tabelle erbt alle Attribute und Methoden und kann Methoden überschreiben. Die Methoden und Attribute werden durch den entsprechenden strukturierten Typen vorgegeben. Des Weiteren können Attribute und Methoden 18 public, private, protected 105 CREATE TABLE <Tabellenname> OF <Typname> [UNDER <Suptabellenname>] Abbildung 72: Vereinfachter Definitionsaufbau einer typisierten Tabelle hinzugefügt werden, wobei sich dabei ein Problem ergibt (vgl. auch [Tür 03, S. 7579]). Bei der Anfrage auf einer typisierten Tabelle wird zwischen flacher und tiefer Extension unterschieden. Eine tiefe Extension beinhaltet alle Tupel einer Tabelle und alle Tupel der typisierten Subtabelle dieser Tabelle, während die flache Extension nur die Tupel der Supertabelle enthält. Bildet man nun eine tiefe Extension auf einer typisierten Tabelle, die mehrere Subtabellen enthält, so besteht keine Möglichkeit (auch durch explizites Casten nicht), auf die hinzugefügten Attribute oder Methoden der Subtabellen zuzugreifen. Das Ergebnis einer tiefen - genauso wie einer flachen Extension ist wiederum nur eine Tabelle, die Spalten und Zeilen enthält. Neu hinzugefügte Spalten der Subtypen erscheinen in der tiefen Extension nicht (siehe auch [Tür 03, S. 76 bis 79]). An dem Beispiel von Abbildung 63 auf Seite 94 kann man sehen, dass durch eine flache Extension auf Employee die Menge aller Mitarbeiter zurückgegeben wird, die keine Verträge besitzen. Die tiefe Extension auf Employee liefert die Menge aller Mitarbeiter zurück. Da keine abstrakten Methoden definiert werden können, ist Vererbung nur in sehr eingeschränktem Maß möglich. Es besteht lediglich die Möglichkeit, anstelle einer abstrakten Methode eine Methode zu definieren, die eine Exception zurückliefert. Das Problem dabei ist, dass typisierte Tabellen prinzipiell nur Tabellen mit einer speziellen Spalte für die Objektidentität sind. Die Attribute des entsprechenden strukturierten Typs werden in Attribute einer Tabelle umgewandelt. Dadurch sind direkte Manipulationen an den Attributen möglich, ohne dass auf die Mutator- und Observer-Methoden zugegriffen wird. 7.2.6 Typisierte Sichten Ein weiteres Konzept sind die typisierten Sichten. Eine typisierte Sicht ermöglicht eine Sicht auf ein Objekt, d. h., sie basiert auf einem strukturierten Typen und definiert auf diesen eine SQL-Anfrage. Im Gegensatz zu den Tupelsichten haben die Objekte einer typisierten Sicht eine Objektidentität und auf ihnen können Methoden aufgerufen werden. Außerdem kann angegeben werden, ob es sich bei der entsprechenden Anfrage um eine flache oder eine tiefe Extension handelt. 106 Typisierte Sichten können vererbt werden, wobei der strukturierte Typ der Subsicht direkt oder indirekt von dem strukturierten Typ der basierenden typisierten Sicht abgeleitet werden muss. Abbildung 73: Beispiel für eine typisierte Sicht Wie in Abbildung 73 zu sehen ist, ist ein Mitarbeiter mit Vertrag (EmployeeWithContract) eine Erweiterung eines Mitarbeiters (Employee) (vgl. auch Kapitel 6.8.2). Die typisierten Sichten beschränken sich darauf, dass nur Mitarbeiter zurückgegeben werden, die im Moment aktiv sind. Wie schon in Kapitel 6.8.2 beschrieben wurde, besitzen Mitarbeiter mit und ohne Vertrag jeweils unterschiedliche Implementierungen für die Abfrage und das Setzen des aktiven Status, wobei in diesem Beispiel nur die Abfrage (Active()) berücksichtigt wird. Eine tiefe Extension auf der typisierten Sicht AktiveMitarbeiter liefert alle Mitarbeiter zurück, die im Moment aktiv sind. Dies beinhaltet auch die Mitarbeiter mit Vertrag. Intern wird die SQL-Anfrage für die typisierte Sicht AktiveMitarbeiter und alle darin enthaltenden Subsichten, in diesem Fall nur AktiveMitarbeiterMitVertrag, ausgeführt (vgl. [Tür 03, S. 79-84]). Eine flache Extension auf der typisierten Sicht AktiveMitarbeiter liefert nur die Mitarbeiter ohne Vertrag zurück, die im Moment aktiv sind. 7.3 Erweiterte Datenabfragen und -manipulation Entsprechend zu der erweiterten Datendefinition wurde in SQL-99 auch die Datenselektion angepasst. Die Verwendung von Referenzen führt dazu, dass über die Abhängigkeiten der Tabellen navigiert werden kann, wie schon gezeigt wurde. Die Anfragen lassen sich somit übersichtlicher formulieren und sind leistungsfähiger, da keine Verbunde mehr gebildet werden müssen. 107 Die Referenztypen enthalten intern die Objektidentität des referenzierten Objekts. Über einen Pfeiloperator (vgl. mit Abbildung 67 und 68 auf Seite 102) können Referenzen aufgelöst werden und liefern somit das referenzierte Objekt zurück. Methoden werden auf ihren Referenzwerten ausgeführt und können in den SQL-Querys (fast) beliebig verwendet werden. Beispielsweise könnte eine SQL-Anfrage in ihrer Where-Klausel einen Methodenaufruf enthalten, wie schon in Kapitel 7.2.6 beschrieben wurde. Dadurch dass objektrelationale und relationale Techniken beliebig kombiniert werden können, sind somit beliebig komplizierte Anfragen möglich. Bisher wurde immer von einer SQL-99 konformen Datenbank ausgegangen. Da die Realität aber ganz anders aussieht, ist z. Z. ein Mischen dieser beiden Techniken nötig. Beispielsweise bietet die mir zur Verfügung stehende Informix Datenbank keine Referenzen an. Es hätten sich zwar beliebig komplexe Datentypen definieren lassen, aber entsprechend kompliziert wären auch die Anfragen geworden. Zur Vermeidung von unerwünschten Seiteneffekten wurden in SQL-99 einige Einschränkungen definiert. Beispielsweise dürfen in einer Where-Klausel keine Methoden oder sonstigen benutzerdefinierten Routinen aufgerufen werden, die Änderungen an den Daten vornehmen (vgl. [Tür 03, S. 256 f.]). Die Änderungen durch ein Update-Statement werden auf eine Tabelle beschränkt, d. h., die Daten einer aufgelösten Referenz dürfen nicht verändert werden. Die Nebenläufigkeitsprobleme, wie in Kapitel 6.3 beschrieben wurde, sind in einer objektrelationalen Datenbank die gleichen. 7.4 Bewertung nach Datenbankmanifesto Konzeptionell bietet SQL-99 interessante Konzepte um Objektorientierung in der relationalen Datenbank zu ermöglichen. Im Folgenden wird das Konzept der objektrelationalen Datenbank anhand der in Kapitel 6.8.3 geforderten Bedingungen von [Atk+ 95] untersucht. 7.4.1 Komplexe Datentypen Wie in Kapitel 7.2 beschrieben wurde, bietet SQL-99 verschiedene Möglichkeiten, um komplexe Datentypen zu definieren. Distinct-, Tupel-, Arraytypen ermöglichen es, mehr Struktur in das Datenmodell zu bringen. Mit den strukturierten Typen lassen sich Typen bilden, die, ähnlich zu einer Klasse, mehrere Typen zu einem Typen zusammenfassen. Allerdings sind die Konstruktoren nicht vollständig orthogonal, so wie gefordert wurde. 108 7.4.2 Objektidentität Durch das Konzept der strukturierten Typen und die vom System generierten Objektidentitäten ist eine Unterscheidung von gleichen und denselben Objekten möglich. Allerdings muss diese Eigenschaft explizit definiert werden. Es besteht auch die Möglichkeit, zustandsabhängige oder selbst definierte Objektidentitäten zu definieren, was aber der Idee einer Objektidentität widerspricht. 7.4.3 Kapselung Die Anforderung nach einer sauberen Trennung zwischen Schnittstelle und Implementierung ist nicht gegeben, da keine Sichtbarkeiten definiert werden können und alle strukturierten Typen und Methoden prinzipiell public sind. Die Kapselung der Attribute ist auch nur in einem sehr eingeschränkten Maß gegeben, da für jedes Attribut genau eine Mutator - und eine Observer -Methode definiert wird. Verschiedene Sichten eines Attributs sind damit nicht möglich. Dadurch dass die Mutatorund die Observermethode den gleichen Namen wie ihre Attribute haben, würden Änderungen nach außen sichtbar. Die Mutator - und Observer -Methoden sind aber ein geeignetes Mittel um Konsistenzprüfungen vorzunehmen, d. h. eine unzulässige Zustandsübergabe abzufangen. 7.4.4 Typen- und Klassenhierarchien Die Unterteilung von Klasen (typisierte Tabellen) und Typen (strukturierte Typen) existiert so, wie es auch gefordert wurde. Auf einer strukturierten Tabelle lassen sich, wie auch auf einer einfachen Tabelle, beliebige Operationen für eine Menge von Objekten ausführen. Die geforderte Trennung zwischen Schnittstelle und Implementierung eines Typs ist nicht gegeben (vgl. mit Kapselung 7.4.3). 7.4.5 Vererbung In einem eingeschränkten Maß ist auch Vererbung möglich. Die Definition von abstrakten Methoden ist nicht möglich. Zusätzlich definierte Attribute oder Methoden eines strukturierten abgeleiteten Typen können bei einer tiefen Extension auf den Basistypen auch durch explizites Casten nicht verwendet werden (siehe Kapitel 7.2.5). Ein weiteres Problem ist, dass strukturierte Tabellen nur strukturierte Typen des gleichen Typs beinhalten dürfen. Abgeleitete Typen müssen in abgeleiteten Tabellen abgelegt werden (s. Kapitel 7.5). 7.4.6 Override, Overload und spätes Binden Overloading existiert sowohl für Methoden als auch für Funktionen und Prozeduren. Dynamisches Binden, wie in Kapitel 7.2.6 an einem Beispiel gezeigt wurde, ermöglicht es, Methoden zur Laufzeit zu ermitteln. 109 7.4.7 Sprach- und Berechnungsvollständigkeit Die Forderung nach Sprach- und Berechnungsvollständigkeit ist bereits durch die in Kapitel 6.2.6 beschriebenen benutzerdefinierten Routinen gegeben. In den Methoden können dieselben Funktionalitäten wie in den benutzerdefinierten Routinen verwendet werden, womit sich alle berechenbaren Operationen ausführen lassen. 7.4.8 Erweiterbarkeit von Typen Wie schon in dem Punkt Kapselung beschrieben wurde, können (fast) beliebige Typen gebildet und verwendet werden. Das Typsystem von SQL-99 macht dabei keine Unterscheidung zwischen benutzerdefinierten und vorgegebenen Typen. 7.5 Klassenmodell in objektrelationales Datenmodell transformieren Basierend auf der Vorgehensweise von [Fin 02, S. 63-68] wird in diesem Kapitel ein Ansatz für eine Transformation von Klassenmodell auf objektrelationales Modell vorgestellt. Eine entsprechende Anwendung mit einer identischen Klassenstruktur wird aber auch in einem objektrelationalen Datenmodell immer nötig sein, da in der objektrelationalen Datenbank kein grafisches Benutzerinterface oder irgendeine andere Schnittstelle nach außen implementiert werden kann. Datentypen nachbilden: Zunächst müssen die benötigten einfachen Datentypen im objektrelationalen Datenmodell angelegt werden, sofern sie in der Form noch nicht existieren. Klassen werden zu strukturierten Typen: Klassen mit ihren Attributen werden zu strukturierten Typen mit einer vom System generierten Objektidentität. Diejenigen Attribute, die auf eine weitere Klasse verweisen, müssen als Referenzen abgebildet werden. 1:n-Beziehungen werden als Array von Referenzen modelliert und m:n-Beziehungen werden durch zwei Beziehungen dargestellt. Vererbung nachbilden: Die Vererbungsbeziehungen werden in strukturierten Typen nachgebildet. Dabei sollte zu jedem strukturierten Typ eine entsprechende strukturierte Tabelle angelegt werden. Eine strukturierte Tabelle kann nur Typen des genau gleichen Typs enthalten. Subtypen in eine strukturierte Tabelle einzufügen geht nicht (vgl. [Fin 02, S. 66]). Diese müssen dann in die entsprechende abgeleitete Tabelle (also die Tabelle des Subtypen) eingeführt werden. 7.6 Zusammenfassung Wie an den Punkten von Abschnitt 7.4 gezeigt wurde, ließen sich viele Anwendungen komplett in eine objektrelationale Datenbank auslagern. Das große Problem 110 ist die benötigte Abwärtskompatibilität zu SQL-92 und die damit verbundene fehlende Kapselung. Eine größere Entwicklung mit mehreren Entwicklern würde eine erhöhte Disziplin der Entwickler erfordern, da vereinbarte Schnittstellen nicht in der Datenbank realisiert werden könnten. Die Entwicklung eines Frameworks in einer objektrelationalen Datenbank wäre beispielsweise durch die fehlenden abstrakten Methoden und die fehlenden Sichtbarkeiten nicht in der Form möglich, wie in einer objektorientierten Programmiersprache. Das eigentliche Problem ist aber ganz anderer Art. In den real existierenden objektrelationalen Datenbanken werden immer nur einige der Konzepte realisiert und es ist erforderlich, dass die relationalen mit den objektrelationalen Konzepten gemischt werden. Dadurch wird die Entwicklung sehr viel aufwendiger als bei einer Trennung von relationaler Datenbank und Anwendung. 111 8 8.1 8.1.1 Vergleich: relationale und objektrelationale Datenbank Relationale Datenbank Modellierungsmöglichkeiten und Normalisierung Ein großes Problem beim Entwurf war die Trennung zwischen Datenmodell und Klassenmodell. Erschwerend kam noch hinzu, dass es zwei Arten von Klassenmodellen gab: das informative Klassenmodell aus dem Requirements Engineering (vgl. Abbildung 8 auf Seite 28 und das Klassenmodell des Entwurfs der persistenten Objekte (vgl. Abbildung 26 auf Seite 51). Um die Probleme der eingeschränkten Modellierungsmöglichkeiten zu verringern, bildete das Datenmodell die Basis für den Entwurf und das Klassenmodell der Analyse diente nur als Informationsgrundlage. Bei der Modellierung des Datenmodells wurden bewusst einige Normalisierungsschritte nicht vorgenommen, da diese das Datenmodell unübersichtlich gemacht und die Tabellen nicht mehr die Entitäten der Realität dargestellt hätten. Ein Beispiel ist das Attribut active in der Tabelle Employee (vgl. Abbildung 55 auf Seite 85), welches für Vertragsmitarbeiter, d. h. Mitarbeiter, die eine Verbindung zu EmployeeContract besitzen, keine Bedeutung hat. Da der Unterschied zwischen Vertragsmitarbeitern und Mitarbeitern ohne Vertrag nicht allzu groß war, stellte diese ”Schwäche” kein großes Problem dar. In dem Beispiel von Abbildung 74 hingegen ist dies etwas komplizierter. Die links dargestellten Klassen lassen sich auf zwei Arten abbilden. Die erste Möglichkeit enthält alle Attribute, die möglich sind, d. h., in jedem Datensatz sind Daten vorhanden, die keine Bedeutung haben, so wie beispielsweise das Attribut active in der Tabelle Employee (vgl. Abbildung 55 auf Seite 85). Die zweite Möglichkeit besteht darin, die Klassen direkt als Tabellen abzubilden und die Vererbung durch Schlüsselverbindungen zu verbinden. Der Nachteil dieser Variante ist, dass für jede Anfrage an B oder C jeweils ein Verbund mit der Tabelle A durchgeführt werden muss und die ursprüngliche Modellierungsform nicht mehr ersichtlich ist. Ein weiteres Problem, was sich aus der Trennung von Datenmodell und Applikation über die SQL- Schnittstelle ergibt, ist, dass die SQL-Queries erst zur Laufzeit überprüft werden können, da dies nur ein einfacher String ist. Ein vorheriges Überprüfen, ob beispielsweise Tabellen oder Attribute der Tabelle existieren, ist nicht 112 Abbildung 74: Zwei Möglichkeiten für Vererbung im ER-Modell möglich. Dies ist vor allem bei Änderungen sehr aufwendig, da der entsprechende Programmteil, der den geänderten Query enthält, jeweils durchlaufen werden muss. 8.1.2 Definition von Primärschlüsseln In Kapitel 6.7.5 wurde bereits das Problem mit zusammengesetzten Primärschlüsseln beschrieben. Die Definition von technischen Schlüsseln, die vom System erzeugt werden, aus einem Attribut bestehen, welches unabhängig von den Werten des Datensatzes ist, und die Definition von nicht-identifizierenden Verbindungen stellte sich als sehr vorteilhaft heraus. Die zweite Normalform musste nicht mehr betrachtet werden, da sie in diesem Fall nicht mehr auftreten kann. Die einzige Überprüfung zur Vermeidung von Redundanzen war die Betrachtung der Abhängigkeiten der (Nichtschlüssel-)Attribute untereinander. Ausgenommen waren dabei die Tabellen, welche m:n-Beziehungen darstellten. Die Entitäten können dann nur noch über ihre definierten Abhängigkeiten verbunden werden. Wie in Abbildung 60 auf Seite 91 zu sehen war, war es bei den 113 zusammengesetzten Primärschlüsseln auch möglich, Tabellen miteinander zu verbinden, die nicht direkt in Beziehung stehen, wie beispielsweise in Abbildung 60 Fachgruppen (ProjectTeam) und Projektgruppen (ProjectGroup). In diesem Fall kann aber wiederum das Problem Phantom Read (vgl. Kapitel 6.3.3) auftreten, da das Projekt hier nicht betrachtet wird und damit auch nicht gelockt werden kann. 8.1.3 Integritätsbedingungen Integritätsbedingungen zwischen Entitäten werden durch Fremdschlüssel realisiert. Für komplexere Bedingungen können Trigger verwendet werden. Trigger haben allerdings den Nachteil, dass sie nur auf Ereignisse in einer Tabelle reagieren können, d. h., für eine komplexere Überprüfung müssten verschiedenste Trigger definiert werden, um eine Integritätsbedingung zu erfüllen. Ein Beispiel ist die Überprüfung, die sicherstellt, dass Daten in den Mitarbeiterwochen nur geändert werden können, wenn diese noch nicht geschlossen sind (vgl. mit dem Attribut finish in der Tabelle EmployeeWeek ist (vgl. Abbildung 55 auf Seite 85). Für diese Überprüfung wären vier Trigger für die folgenden Tabellen nötig: EmployeeWeek, ProjectEmployee, TeamEmployee und ActivityEmployee. Da diese das Datenmodell recht kompliziert machen und bei jeder Änderung manuell mit geändert werden müssten, wurde auf die Verwendung von Triggern verzichtet. 8.1.4 Abfragemöglichkeiten und Datenmanipulation Bei der Formulierung der Abfragen müssen alle denkbaren Abhängigkeiten mit betrachtet werden, d. h., wenn beispielsweise eine Liste mit Projekten ermittelt werden soll und noch nicht genau feststeht, ob die abhängigen Projektleiter wirklich benötigt werden, so müssen diese in der Anfrage mit angeben werden. Die andere Möglichkeit ist, die geforderten Daten explizit bei Bedarf anzufordern, wobei hier sperrende Transaktionen verwendet werden sollten. Durch die Verwendung von Sichten können die Anfragen zwar erleichtert werden, aber Sichten ”verstecken” die aufwendigen Anfragen nur. Beim Erzeugen, Ändern oder Löschen von Datensätzen muss wieder auf die hinter den Sichten liegenden Tabellen zugegriffen werden. Das Ändern, Löschen und Einfügen von Datensätzen ist pro Query nur auf eine Tabelle beschränk, d. h. Operationen dieser Art, die sich über mehrere Tabellen erstrecken, müssen in mehreren Queries formuliert werden. 114 8.1.5 Nebenläufigkeit und Performanz Einer der großen Vorteile einer relationalen Datenbank ist die Performanz. Wie sich aber herausgestellt hat, ist es sinnvoll, für jede Entität ein Attribut als Primärschlüssel zu definieren, der unabhängig vom Zustand der Datensätze ist und vom System bzw. von der Datenbank erzeugt wird, d. h., die Tabellen können nur über ihre definierten Schlüsselverbindungen miteinander verbunden werden. Dadurch müssen bei den Verbund-Operationen auch genau diese Verbindungen berücksichtigt werden, wodurch aufwendige Verbunde über mehrere Tabellen nötig sind. Die Nebenläufigkeitsprobleme habe gezeigt, dass Phantom Read durchaus zu einem Problem führen kann, was nur durch Serialisieren der Transaktionen gelöst werden kann. Inwieweit die relationalen Datenbanken dann immer noch so leistungsstark sind, ist fraglich. 8.2 Verbesserungen durch eine objektrelationale Datenbank? Bei einer Realisierung mit einem objektrelationalen Datenmodell kann das erstellte Klassenmodell sowohl für die Anwendung als auch für die Datenbank verwendet werden, d. h., umständliche Umwandlungen oder von vornherein eingeschränkte Modellierungstechniken sind nicht mehr nötig. Die in Abbildung 74 dargestellten Klassen ließen sich eins-zu-eins in einer objektrelationalen Datenbank abbilden. Eine Businesslogik wird aber auch in einer objektrelationalen Datenbank immer nötig sein, da keine Möglichkeiten für die Gestaltung einer grafischen Benutzeroberfläche oder eines anderen Interfaces gegeben sind. Der Zugriff erfolgt ebenfalls über SQL, wobei eine Überprüfung auf syntaktische Korrektheit auch erst zur Laufzeit ausgeführt werden kann. Die Problematik mit den Primärschlüsseln ist in diesem Fall nicht gegeben, da für jeden strukturierten Typen eine vom System generierte Objektidentität ermittelt werden kann. Die Verwendung von aufgelösten Referenzen führt dazu, dass Queries einfacher formuliert werden können und verständlicher sind. Des Weiteren sind keine aufwendigen Verbundoperationen mehr nötig. Durch die Definition von Methoden in den strukturierten Typen können Funktionalitäten, die sonst nur in der Businesslogik realisiert wurden, direkt in der Datenbank ausgeführt werden. Allerdings sind die Möglichkeiten nach SQL-99 im Vergleich zu einer objektorientierten Programmiersprache eingeschränkter. Die Transaktionsprobleme sind in einer objektrelationalen Datenbank aber immer noch die gleichen, wobei sich durch das komplexere Datenmodell mehr Anwendungssemantik in die Datenbank verlagern lässt und damit weniger Queries an die 115 Datenbank nötig sind. 8.3 Vergleich objektrelational zu relational zusammengefasst relational objektrelational Flache Strukturen Vererbung Primärschlüssel Objektidentität Verbundoperationen aufgelöste Referenzen Trigger und benutzerdefinierte Routinen Methoden Sichten Objektsichten (typisierte Sichten) eingeschränkte Kapselung Abbildung 75: Überblick relationale zu objektrelationaler Datenbank Wie in Abbildung 75 zu sehen ist, bietet eine objektrelationale Datenbank im Vergleich zu einer relationalen viele Vorteile. Leider ist dieser Ansatz nur Theorie, wobei sich hierbei auch die Frage stellt, ob die Vorteile einer relationalen Datenbank (vgl. Kapitel 6.8.1) in einem objektrelationalen Datenmodell immer noch gegeben sind. Die Idee der objektrelationalen Erweiterung war, die Vorteile der Objektorientierung mit denen der relationalen Datenbank zu verbinden. 9 9.1 Zusammenfassung und Ausblick Objektorientierte Datenbank Einen völlig anderen Ansatz verfolgt die objektorientierte Datenbank. Sie bringt, im Gegensatz zu einer objektrelationalen Datenbank, nicht die Anwendungssemantik in die Datenbank, sondern die Persistenzeigenschaften in die Programmiersprache. Das Datenmodell kann als Klassenmodell entworfen werden und über einen ”Zusatz” werden automatisch Persistenzeigenschaften realisiert. Eine Möglichkeit ist der Attributemechanismus von .NET (.NET-Attribute). Dieser erlaubt es u. a., über Reflexion Objektinformationen zur Laufzeit zu bestimmen. Die FastObjects Datenbank von Poet ist ein Beispiel für eine objektorientierte Datenbank, die diesen Mechanismus verwendet. Genauso wie in einem relationalen oder einem objektrelationalen Datenbankkonzept muss hierfür eine Transaktion geöffnet werden. In dieser Transaktion können Daten erzeugt, gelesen, geändert und gelöscht werden. Beim Schließen der Transaktion werden die geänderten Daten automatisch auch in der Datenbank aktualisiert. 116 In Abbildung 76 ist ein Beispiel dargestellt für die Definition eines konkreten persistenten Objekts aus der Zeiterfassung. (1) [Persistent] (2) public class CostCenterImpl : CostCenter { (3) public CostCenterImpl(){} (4) public override string Name{...} (5) private string m OOName; (6) } (7) IObjectScope scope (8) = FastObjects.Database.Get(<Datenbank>).GetObjectScope(); (9) scope.Transaction.Begin(); (10) foreach( CostCenterImpl p in scope.GetExtent( typeof(CostCenterImpl) ) ) (11) // Irgendetwas mit p machen (6) scope.Transaction.Commit(); Abbildung 76: Beispiel für eine Implementierung mit objektorientierter Datenbank Sobald die ersten Objekte ermittelt wurden, kann auf die abhängigen Objekte direkt zugegriffen werden (Persistence by Reachability). Diese Objekte müssen nicht explizit aus der Datenbank ausgelesen werden. In der relationalen und der objektrelationalen Datenbank hätten dafür alle benötigten abhängigen Objekte bzw. Tupel in dem Query mit ausgelesen werden müssen. In dem Beispiel von Abbildung 76 kann beispielsweise das Attribute m OOName (Zeile 5) über die Property Name geändert werden. Nach dem Commit ist diese Änderung dann persistenz, ohne dass explizite Queries an die Datenbank geschickt werden, die diese Änderung vornehmen. Um auf Objekte zugreifen zu können, wurde von der ODMG-Untergruppe OMG der Standard OQL entwickelt, der, ähnlich zu SQL, eine Abfragesprache für eine objektorientierte Datenbank definiert. Die Syntax ist dabei sehr ähnlich zu SQL-92. Der Unterschied zu SQL ist, dass, die Anfragen auf einer Extension statt auf einer Relation formuliert werden, d. h. auf einer Menge von Objekten. Im Gegensatz zu SQL-99 liefert eine OQL-Anfrage ”echte” Objekte zurück. Abhängige Daten können dabei genauso wie bei SQL-99 über Navigation angesprochen werden. Anstelle von Events bietet die FastObjects .NET Datenbank Events an, an denen sich Methoden registrieren können. Die auftretenden Events sind dabei die gleichen wie bei einem Trigger: Ändern, Löschen, Einfügen und Lesen von Objekten. 117 Neben der pessimistischen Nebenläufigkeitskontrolle existiert in FastObjects die Möglichkeit, eine (automatische) optimistische Nebenläufigkeitskontrolle zu verwenden, die in einer relationalen oder objektrelationalen Datenbank nur durch zusätzliche Attribute und manuell realisiert werden kann. Unter Umständen kann es sinnvoll sein, die Daten nicht unbedingt gleich zu sperren oder die Transaktionen zu serialisieren. Trotzdem soll aber gesichert sein, dass keine inkonsistenten Zustände auftreten. Eine Möglichkeit, die persistenten Klassen im Klassenmodell zu kennzeichnen, könnte ein Stereotyp sein (beispielsweise persistent). Das Klassenmodell könnte in der Analyse entwickelt und im Entwurf verfeinert werden. Für die Implementierung muss dieses dann nicht mehr geändert werden. Des Weiteren bietet die FastObject .NET Datenbank noch Mechanismen zum sekundären Datenmanagement an. Recovery wird nach eigenen Angaben ebenfalls unterstützt, d. h., im Fall eines Ausfalls wird der alte (konsistente) Zustand wieder hergestellt. 9.2 Persistenz Framework und Datenbankvergleich Das in Kapitel 5.3 entwickelte Framework sollte einen Vergleich von relationaler und objektrelationaler Datenbank ermöglichen. Das Problem, was hierbei bestand, war, dass durch diese Struktur von vornherein ein objektiver Vergleich ausgeschlossen ist. Eines der zentralen Konzepte der relationalen Datenbank ist die Vererbung. Dadurch, dass jedes konkrete persistente Objekt und jeder konkrete Manager von einer entsprechenden Klasse abgeleitet werden musste, war in dieser Struktur von vornherein kein objektiver Vergleich möglich. 9.3 Entwicklungsprozess Die Vorgehensweise, zunächst eine relationale Datenbank zu verwenden und anschließend die gleiche Anwendung mit einer besseren Variante, wie beispielsweise einer objektorientierten Datenbank, zu realisieren, stellte sich ebenfalls nicht als vorteilhaft heraus. Folgendes Szenario soll den Grund dafür verdeutlichen: 1. Eine Änderungen der Anforderungen wird verlangt (siehe Kapitel Prototyping in Kapitel 3.1.5). 2. Diese Änderung musste (manuell) überprüft werden (siehe Kapitel 3.2). 3. Anschließend wurden diese Änderungen (halb)automatisch in das Requirements Document übernommen (siehe Kapitel 3.4). 118 4. Das ERwin-Datenmodell wurde angepasst (siehe Kapitel 6.7.2). 5. Das entsprechende informative Datenmodell wurden angepasst (siehe Kapitel 3.3.1). 6. Die Struktur des Persistenz-Frameworks wurde geändert (siehe Kapitel 5.3.5). 7. Diese Änderung muss in der konkreten Komponente, welche die Implementierung mit der relationalen Datenbank vornimmt, geändert werden. Wäre die erste Wahl für die verwendete Datenbanktechnik eine objektorientierte Datenbank gewesen, so wären nur die ersten drei Schritte und eine Anpassung an ein Klassen-/Datenmodell nötig gewesen. 9.4 Zusammenfassung der wichtigsten Erkenntnisse Im Folgenden werden die wichtigsten Erkenntnisse stichpunktartig zusammengefasst: • Für die Verwaltung der Requirements ein unterstützendes Tool verwenden. • Die Systemgrenzen ganz genau abgrenzen und genau definieren, wo die Anwendung nicht mehr weitermacht. • Ein nicht unwesentliches Maß an ”Fingerspitzengefühl”, Intuition und Erfahrung ist beim Requirements Engineering immer nötig und kann auch nicht durch Erlernen von bestimmten Techniken ersetzt werden. • Die Entwicklung eines Frameworks ist kompliziert, da es schwierig ist, alle möglichen Aspekte vorherzusehen. • Die Verwendung eine Frameworks ist einfach, wenn man die Schnittstelle genau kennt. • Das Ziel genau spezifizieren und nicht aus den Augen verlieren. • Eine Web-Applikation besitzt nicht nur Vorteile (siehe Abbildung 29 auf Seite 54). • Bei der Modellierung mit einer relationalen Datenbank sollte auf zusammengesetzte Schlüssel verzichtet werden. Ausnahme ist die Abbildung einer m:nBeziehung. 119 9.5 Offene Frage Eines der Hauptprobleme war, die verschiedenen Modellierungstechniken, wie in Kapitel 9.3 beschrieben, konsistent zueinander zu halten. Sowohl die Trennung nach dem Model View Controller Pattern als auch die Trennung von Datenbank und Anwendung hat Vor- und Nachteile. Vorteile: • Die Komponenten lassen sich einfach austauschen bzw. ersetzen. • Eine Komponente enthält nur einen bestimmten Aspekt eines Problems, wie beispielsweise die Steuerung der Benutzeroberfläche oder die Datenstruktur. Nachteil: • Es existieren redundante Informationen in den verschiedenen Modellen, d.h., eine Änderung wird eventuell an mehreren Stellen durchgeführt. Der andere Weg wäre, zunächst die Anforderungen zu erheben, diese zu überprüfen, und erst wenn alle die Requirement ”fehlerfrei” sind, zum Entwurf überzugehen. Das Problem ist nur, wie realistisch ist die Anforderung, dass eine Requirement ”fehlerfrei” ist? Existiert für das in Abbildung 77 dargestellte Fragezeichen eine brauchbare Lösung? 120 Abbildung 77: Auswirkung einer Anforderungsänderung (vgl. mit Kapitel 9.3) 121 Literatur [Ade 94] IDEF-1X - Eine Methode zur Datenmodellierung H.H. Adelsberger, F. Körner, 1994, Universität GH Essen [Atk+ 95] The Object-Oriented Database System Manifesto, 1995 M. Atkinson, F. Bancilhon, D. DeWitt, K. Dittrich, D. Maier, S. Zdonik www-2.cs.cmu.edu/People/clamen/OODBMS/Manifesto/htManifesto/Manifesto.html [Bit Koc 00] Objektorientierte Analyse und Design Die Fusion-Methode unter Verwendung von UML, M. Bittner und W. Koch, 2000 [CIS] Normalisierung Begleitende Folien zur Vorlesung Datenbanksysteme (DBS) im Fachbereich Computergestützte InformationsSysteme (CIS) an der Technischen Universität Berlin (TUB) [Cod 70] A Relational Model of Data for Large Shared Data Banks E. F. Codd, 1970 http://www.acm.org/classics/nov95/ [Con 99] Modeling Web Application Architectures with UML Rational Software White Paper J. Conallen, Rational Software, June 1999 [Eis+ 99] SQL:1999, formerly known as SQL3 A. Eisenberg, J. Melton , 1999 [Esp 04] Das ASP.NET-Seitenobjektmodell MSDN, Entwickler Bibliothek D. Esposito, 2004 [Ett 99] IDEF1X VS UML A Comparative Analysis B.Ettlinger, 1999, Artikel aus ”The Erwin Insider” (Tips, Tricks and Articles of Interest to ERwin and BPwin Users) [FO 04a] FastObjects .NET Script zur Schulung ”Einführungs-Workshop C#” 08.01.2004 [FO 04b] FastObjects .NET Programmer’s Guide Poet Software, 2004 [Fra+ 96] Delegation: Eine sinnvolle Ergänzung gängiger objektorientierter Modellierungskonzepte U. Frank, S. Halter, 1996 122 [Fin 02] Anbindung objektorientierter Software an objektrelationale Datenbanken Diplomararbeit an der Universität Hamburg im Fachbereich Softwaretechnik M. Finsterwalder, 2002 [Geb 04] Datenbanken Prof. Dr. K.F. Gebhardt, 2004 [Gli 04] Spezifikation und Entwurf von Software Vorlesung im WS 2003/2004 von Prof. Dr. M. Glinz (Institut für Informatik der Universität Zürich) http://www.ifi.unizh.ch/groups/req/courses/ses/ [GotDotNet] http://de.gotdotnet.com/quickstart/aspplus/doc/authandauth.aspx [IDEF] IDEF Family of Methods Knowledge Based Systems, Inc http://www.idef.com [IEEE610.12-1990] IEEE Standard Glossary of Software Engineering Terminology, IEEE Std.610.12-1990 [IEEE830-1998] IEEE Recommended Practice for Software Requirements Specifications, IEEE Std 830-1998 [Inf 99] SQL Reference Guide, Version 6.0, 1999 [Lau 01] Object-Oriented Features of SQL:1999 Workshop-Folien, F. Laux, 2001 [Lin 01] Dynamisches Verhalten in UML Dynamisches Verhalten in UML Prof. Dr. rer. nat N. Link, WS 2001/2002, LKIT an der FH Karlsruhe [Loh 03] Einstieg in ASP.NET, Für Einsteiger und Umsteiger, M. Lohrer, Galileo Computing, 2003 [Luf 99] Beitrag im Informatik-Lexikon der Gesellschaft für Informatik e.V., J. Lufter, 1999 [Luf 02] Abbildung normkonformer objektrelationaler Sprachmittel auf reale DBMS, J. Lufter, 2003 [MSDN] Microsoft Developer Network http://msdn.microsoft.com/ 123 [MSDN ASP.NET] ASP.NET Technology Backgrounder Microsoft Corporation, 2001 msdn.microsoft.com/library/en-us/vbcon/html/vbconasptechnologybackgrounder.asp [MSDN .NET Framework FAQ 01] Microsoft .NET Framework FAQ Microsoft Corporation, 2001 http://msdn.microsoft.com/library/en-us/dndotnet/html/faq111700.asp [Mös 03] Vorlesung im Institut für Systemsoftware an der Johannes Kepler Universität (JKU) Linz, Österreich ”Softwareentwicklung mit C#” Institut für Systemsoftware, Fachbereich Informatik Johannes Kepler Universität Linz H. Mössenböck, 2003 http://www.ssw.uni-linz.ac.at/Teaching/Lectures/CSharp/ [NetLexikon] Net-Lexikon http://www.net-lexikon.de [Pla 03] Implementierung von Datenbanktransaktionen mit Microsoft .NET, M. Platt, 2003, Artikel aus der MSDN Entwickler Bibliothek [ReqDoc] Requirements Dokument zu dieser Diplomarbeit C. Schweter, 2004 [Rup 01] Requirement Engineering - der Einsatz natürlichsprachlicher Methoden bei der Ermittlung und Qualitätsprüfung von Anforderungen, C. Rupp, Paper 2001 [Rup 02] Requirements-Engineering und -Management C. Rupp, Hanser-Verlag, 2002 [Saa 03] Objektdatenbanken, 2003 Gunter Saake, Can Türker, Ingo Schmitt [Sah 00] Anforderungsanalyse für die Werkzeugunterstützung der Methode FUSION und Entwurf einer Benutzungsschnittstelle B. Sahin, Diplomarbeit im Fachgebiet Softwaretechnik, Technischen Universität Berlin, 2000 [Sch 02] Einsatz von Applikationsservern Untersuchung am Beispiel des Sybase ”Enterprise Application Server” Diplomarbeit an der FH Brandenburg, FB Informatik und Medien, A. Schwarzbauer, 2002 http://ots.fh-brandenburg.de -> abgeschlossene Diplomarbeiten 124 [Scr+ 97] Object persistence in object-oriented applications Artikel aus dem IBM Systems Journal, Vol. 36, V.Srinivasan, D. T. Chang [Som 00] Software Engineering 6th Edition Powerpoint Presentations von Ian Sommervielle zum gleichnamigen Buch http://www.comp.lancs.ac.uk/computing/resources/SE6/Slides/ [Som Saw 97] Requirements Engineering - A good practice guide Ian Sommerville und Pete Sawyer, 1997 [Tür 03] SQL:1999 & SQL:2003 Objektrelationales SQL, SQLJ & SQL/XML, 2003 Can Türker, 2003 [UML] UML Notation Guide OMG-Unified Modeling Language, v1.5, 2003 [ViSEK] Virtuelles Software Engineering Kompetenzzentrum http://www.visek.de [Vor 99] Unterlagen zur Vorlesung Datenbanksysteme 22.Juli 1999, Oliver Vornberger Universität Osnabrück Fachbereich Mathematik und Informatik Praktische Informatik 125 A Requirements Document 126