Diplomarbeit Dependency Injection als Mittel zur Verbesserung der Softwarequalität durch zentralisierte Objekterzeugung September 2007

Größe: px
Ab Seite anzeigen:

Download "Diplomarbeit Dependency Injection als Mittel zur Verbesserung der Softwarequalität durch zentralisierte Objekterzeugung September 2007"

Transkript

1 Diplomarbeit Dependency Injection als Mittel zur Verbesserung der Softwarequalität durch zentralisierte Objekterzeugung September 2007 Sebastian Sanitz Wohlwillstr Hamburg sebastian@sanitz.net Matrikelnummer: Betreuer: Dr. Wolf-Gideon Bleek Zweitbetreuer: Prof. Dr. Winfried Lamersdorf Universität Hamburg Fachbereich Informatik Arbeitsbereich Softwaretechnik Vogt-Kölln-Str Hamburg

2

3 Inhaltsverzeichnis 1 Einleitung Motivation Lösungsansätze Vorgehensweise Aufbau der Arbeit Grundlagen Begriffsklärungen und Abgrenzung Designprinzipien Zusammenfassung Gegenstand der Arbeit Das CommSy Die vorhandene Architektur Muster im JCommSy Ergebnisse der Vermessung Zusammenfassung Lösungsansätze Explizite Abhängigkeiten Dependency Injection Dependency Injection Frameworks Vereinfachung der Tests durch Mock-Objekte Zusammenfassung Beschreibung der praktischen Lösung Ziele der Umstellung Planung Umstellung Zusammenfassung Ergebnis Bewertung der Vorgehensweise Bewertung der Umstellung Zusammenfassung I

4 7 Ausblick 62 Messergebnisse 65 Literaturverzeichnis 68 Abbildungsverzeichnis 72 Tabellenverzeichnis 73 Danksagung 74 Selbstständigkeitserklärung 75 II

5 Kapitel 1 Einleitung 1.1 Motivation Objektorientierte Software-Systeme sind ab einer gewissen Größe schwer zu warten und nur mit erhöhtem Aufwand zu erweitern. Eine Ursache ist die Erzeugung von Objekten. Sie ist in diesen Systemen meist verteilt auf den gesamten Sourcecode. Eine Klasse erzeugt sich die konkreten Objekte, die es für die Erledigung ihrer Aufgaben benötigt. Fehler schleichen sich leichter in eine Anwendung, wenn das System stark voneinander abhängig und die Komponenten untereinander eng gekoppelt sind. Das Schreiben von Komponenten-Tests für solche Systeme kann sehr aufwendig sein. Es erfordert das Aufsetzen von vielen abhängigen anderen Komponenten. Auf den gesamten Sourcecode sind Informationen zu konkreten Typen verteilt. Durch diese Verweise entsteht eine enge Kopplung innerhalb des Systems. Es gibt keine Trennung von Implementation und Schnittstelle. Diese fehlende Trennung ist ein Anzeichen für schlechte Qualität, denn es erschwert das Testen und die Erweiterbarkeit. Beispielhaft ist in Abbildung 1.1 dargestellt, wie ein BuecherService auf ein Repository zugreift. Es erzeugt sich eine Instanz der Klasse RdbmsBuecherRepository und benutzt diese für ihre Aufgaben. Eine Komponente die ihre abhängigen Objekte selber erzeugt, lässt sich nur schwer testen. Sämtliche abhängigen Objekte werden im Test auch erzeugt. Diese abhängigen Objekte können für den Test nicht durch Dummy- oder Mock-Objekte 1 ersetzt werden. Es wird somit unmöglich einen Komponenten-Test für eine Klasse bzw. ei- 1 Mock-Objekte sind Dummy-Objekte, die für einen Test rudimentär eine Schnittstelle implementieren und dabei definierte Aufrufe erwarten. Abbildung 1.1: Direkte Abhängigkeit 1

6 2 KAPITEL 1. EINLEITUNG Abbildung 1.2: Lösung mit Factory-Muster ne kleine Komponente aus wenigen Klassen zu schreiben. Jeder Test wird immer zu einem Integrations-Test, der das Aufsetzen von vielen Teilen des Systems erwartet. Dadurch werden Komponenten-Tests unfreiwillig schwierig aufzusetzen und zu formulieren. Eine Änderung des Systems durch den Austausch einer Komponente wird erschwert, wenn diese verteilt im System referenziert wird. Gibt es keine Trennung von Schnittstelle und konkreter Implementierung, muss die Klasse in allen referenzierten Klassen ersetzt werden. Somit schlägt sich ein Austausch der Implementierung einer Komponente auf den gesamten Sourcecode nieder. 1.2 Lösungsansätze Ein Versuch das Problem zu lösen ist die Verwendung von Singletons oder Factories, wie beschrieben in [GHJV94]. Hier ist es die spezielle Aufgabe einer anderen Klasse, die konkreten Objekte zu erzeugen. Die benutzende Klasse greift nur noch über die Schnittstelle auf die konkreten Objekte zu. Die Schnittstelle und Implementierung sind besser von einander getrennt. Auch lässt sich die Erzeugung der konkreten Implementierung einer Komponente auf weniger Teile im Sourcecode beschränken. Das Beispiel der Factory ist in Abbildung 1.2 dargestellt. Die Klasse Buecher- Service benutzt das Repository nur noch mit der Schnittstelle BuecherRepository. Für die Erzeugung ist die Klasse RepositoryFactory zuständig. Hinter der statischen Methode erzeugerepository wird die Erzeugung des Repositories gekapselt. Die Methode erzeugt ein Objekt vom Typ RdbmsBuecherRepository. Der BuecherService hat keine direkte Abhängigkeit mehr zu der konkreten Implementierung RdbmsBuecherRepository. Trotzdem lässt sich das System dadurch nicht leichter testen. Die konkreten Implementierungen lassen sich nicht einfach mit Mock-Objekten ersetzen. Die erzeugende Klasse, im Beispiel die Factory, müsste sich im Testfall anders verhalten als

7 1.2. LÖSUNGSANSÄTZE 3 Abbildung 1.3: Lösung mit Dependency Injection im produktiven Betrieb. Die vorgeschlagene Lösung dieser Diplomarbeit ist eine Umstellung auf Dependency Injection. Bei Dependency Injection werden Objekte nur an einer klar definierten Stelle im System erzeugt. Objekte benutzen nur Schnittstellen der Klassen die benötigt werden. Das benutzende Objekt kennt trotzdem nur die Schnittstelle, nicht aber den konkreten Typ des abhängigen Objektes. Bei Dependency Injection verwaltet ein Container die Erzeugung der Objekte. Der Container übergibt den erzeugten Objekten ihre abhängigen Objekte. Diese Übergabe erfolgt entweder im Konstruktor oder wird per Methode gesetzt. Durch eine Konfiguration des Containers wird festgelegt, welche konkreten Objekte erzeugt werden sollen. Informationen zu einem konkreten Typ befinden sich nicht mehr verteilt im gesamten Sourcecode. Die Information, welche konkreten Objekte für welche Schnittstelle erzeugt werden soll, steht bestenfalls nur noch in der Konfiguration des Containers für Dependency Injection. Die Abhängigkeiten eines Objektes sind klar zu erkennen, entweder an der Schnittstelle oder dem Konstruktor. Die abhängigen Objekte werden nur noch anhand der Schnittstelle benutzt. Dadurch lassen sich diese für einen Komponenten-Test leicht durch Dummy- oder Mock-Objekte ersetzen. Somit kann diese Komponente unabhängig von den anderen Komponenten getestet werden. Für eine Anpassung oder Erweiterung des Systems kann die Implementierung eines Objektes einfacher ausgetauscht werden. Die Information über den konkreten Typ der Implementierung befindet sich nur noch in der Konfiguration des Containers. Die konkrete Implementierung der Anpassung oder Erweiterung muss die

8 4 KAPITEL 1. EINLEITUNG Schnittstelle implementieren. Nur in der Konfiguration muss die angepasste oder neue Komponente registriert werden. Es ist nicht mehr nötig den gesamten Sourcecode bei einer Anpassung zu ändern. Abbildung 1.3 zeigt das Beispiel umgestellt auf Dependency Injection. Der Bücher- Service bekommt ein Bücher-Repository im Konstruktor gesetzt. Der Container ist zuständig für die Erzeugung von Objekten. Er kennt über seine Konfiguration die konkreten Implementierungen. Er erzeugt in diesem Fall ein RdbmsBuecherRepository bevor er einen BuecherService erzeugt. Es gibt keine direkte oder indirekte Abhängigkeit mehr zwischen dem Bücher-Service und der konkreten Implementierung des Bücher-Repositories. 1.3 Vorgehensweise Für die Diplomarbeit werde ich ein bestehendes objektorientiertes System auf Dependency Injection umstellen. Als System ist das CommSy [JJP02] ausgewählt. Der Begriff CommSy steht für Community System. Das CommSy ist ein webbasiertes System zur Unterstützung von vernetzter Projektarbeit. Teile des CommSys sind in Java implementiert. Diese werde ich umstellen auf Dependency Injection. Hierbei möchte ich erforschen, wie bei der Umstellung eines großen objektorientierten Systems auf Dependency Injection vorgegangen werden kann. Durch die praktische Arbeit lassen sich Regeln ableiten, die bei einer Umstellungen zu beachten sind und auch für andere Projekte nützlich sind. Es werden unvermeidbar Fehler auftreten. Wenn diese typisch sind für die Umstellung, dann werde ich diese beschreiben und versuchen, Gegenmaßnahmen zu erörtern. Des weiteren werde ich das System vor, während und nach der Umstellung vermessen. Mit den Ergebnissen werde ich versuchen, die Umstellung qualitativ zu bewerten. 1.4 Aufbau der Arbeit In Kapitel 2 werden die grundlegenden Begriffe für diese Diplomarbeit definiert. Der Begriff Software-Architektur wird mit einer Abgrenzung zu Dependency Injection vorgestellt. Es wird der Begriff Software-Qualität definiert und als Grundlage für die Motivation benutzt. Das Kapitel beschreibt weiter Design-Prinzipien, um eine hohe Software-Qualität zu erreichen. Abschliessend werden die Qualitätsmerkmale für Software Änderbarkeit, Wartbarkeit, Funktionalität, Zuverlässigkeit und Testbarkeit definiert und beschrieben, wie sich die direkte Erzeugung von Objekten im Sourcecode auf diese Merkmale auswirkt. Anschließend wird in Kapitel 3 der Gegenstand der Arbeit erörtert. Es wird das Software-System CommSy vorgestellt und die vorgefundene Architektur beschrieben. Die Software wird dort vermessen und die Ergebnisse der Vermessung interpretiert.

9 1.4. AUFBAU DER ARBEIT 5 Im Kapitel 4 werden verschiedene Lösungsansätze aufgezeigt, um direkte Erzeugung von Objekten verteilt im Sourcecode zu zentralisieren. Dabei werden die Muster Singleton und Plugin erörtert. Das Prinzip Dependency Injection wird dabei eingehend eingeführt. Im Kapitel 5 wird der praktische Teil der Arbeit beschrieben. Hier stelle ich meine Vorgehensweise bei der Umstellung des CommSy auf Dependency Injection vor. Dabei erläutere ich die einzelnen Schritte, die für diese Umstellung notwendig waren. Das Ergebnis der praktischen Arbeit wird in Kapitel 6 vorgestellt. Die Vorgehensweise der Umstellung wird bewertet. Hier wird beschrieben und bewertet, wie sich die Umstellung auf die Architektur und Software-Qualität des Systems ausgewirkt hat. Der Ausblick in Kapitel 7 stellt weitere Fragestellungen vor, die sich durch diese Arbeit ergeben haben, aber nicht durch diese Arbeit beantwortet wurden. Weitere verwandte Themen werden benannt.

10 Kapitel 2 Grundlagen Die grundlegenden Begriffe für diese Diplomarbeit werden in diesem Kapitel definiert und voneinander abgegrenzt. In dem ersten Teil des Kapitels wird dabei das Ziel der Diplomarbeit über den Begriff der Software-Qualität motiviert. Der zweite Teil zeigt Design-Prinzipien zur Erreichung einer hohen Software-Qualität. Diese Prinzipien werden bei der Problembeschreibung benutzt, um typische Schwachstellen objektorientierter Software-Systeme ohne Dependency-Injection aufzuzeigen. 2.1 Begriffsklärungen und Abgrenzung Zunächst soll der Begriff Software-Architektur geklärt werden. In [KFBR06] wird Software-Architektur wie folgt definiert: Software-Architektur Die Software-Architektur ist die grundlegende Organisation eines Systems, dargestellt durch dessen Komponenten, deren Beziehungen zueinander und zur Umgebung, sowie Prinzipien, die den Entwurf und die Evolution des Systems bestimmen. Diese Arbeit beschäftigt sich mit der Erzeugung von Objekten innerhalb eines Software-Systems, also einem wichtigen Bestandteil der Software-Architektur. Für eine Software-Architektur werden von [KFBR06] Ziele definiert. Diese Ziele lassen sich in drei Kategorien einteilen: Die vom Kunden gestellten funktionalen und qualitativen Ziele für das Produkt. Die organisatorischen und technologischen Rahmenbedingungen der Entwicklung. Die zu erwartende Flexibilität der Ziele dieser beiden Kategorien. Diese Arbeit wird sich weniger mit den funktionalen Zielen einer Architektur beschäftigen können, denn diese sind abhängig vom fachlichen Auftrag des Kun- 6

11 2.1. BEGRIFFSKLÄRUNGEN UND ABGRENZUNG 7 Abbildung 2.1: Qualitätsmerkmale dens. Somit konzentriert sich die Arbeit auf die qualitativen Ziele der Software- Architektur. Trotzdem sollte die Software-Architektur beachten, dass ein Software- System auch auf Änderungen fachlicher Ziele flexibel reagieren muss. Diese Arbeit wird beide Ziele berücksichtigen, sowohl die Flexibilität, auf Änderungen fachlicher Anforderungen reagieren zu können, als auch das Ziel hohe Qualität zu verfolgen. Software-Qualität Software-Qualität wird in der Norm ISO/IEC 9126 für Softwareprodukte durch Qualitätsmerkmale wie Funktionalität, Zuverlässigkeit, Benutzbarkeit, Effizienz, Änderbarkeit und Wartung, Übertragbarkeit beschrieben. Die einzelnen Merkmale können weiter untergliedert werden. Die Software-Qualität eines Software-Systems wird durch diese Merkmale mit einem Qualitätsmodell beschrieben. Bewertet wird die Software-Qualität durch Qualitätsindikatoren oder Metriken. Anglehnt an die Norm ISO/IEC 9126 werden die in Abbildung 2.1 dargestellten Qualitätsmerkmale wie folgt beschrieben: Funktionalität Bezeichnet die Fähigkeit des Software-Systems die fachlichen Aufgaben zu erledigen. Das Merkmal Funktionalität wird unterteilt in die Submerkmale Angemessenheit, Richtigkeit und Sicherheit. Zuverlässigkeit Unter Zuverlässigkeit wird die Wahrscheinlichkeit verstanden, mit der Software die beabsichtigten Aufgaben korrekt erledigt. Das Merkmal Zuverlässigkeit wird unterteilt in die Submerkmale Reife, Fehlertoleranz, Robustheit, Wiederherstellbarkeit und Konformität. Benutzbarkeit Die Benutzbarkeit ist gegliedert in die Merkmale Verständlichkeit, Erlernbarkeit, Bedienbarkeit, Attraktivität, und Konformität. Effizienz Die Effizienz beurteilt das Verhältnis von eingesetzten Ressourcen und der Leistung der Software. Die Effizienz wird wiederum unterteilt in Zeitverhalten, Verbrauchsverhalten und Konformität. Änderbarkeit und Wartung Die Änderbarkeit und Wartung eines Softwaresystems beschreibt die Möglichkeit des Systems, auf neue fachliche oder technische Anforderungen reagieren zu können. Sie wird beschrieben durch Analysierbarkeit, Modifizierbarkeit, Stabilität und Prüfbarkeit.

12 8 KAPITEL 2. GRUNDLAGEN Übertragbarkeit Unter der Übertragbarkeit eines Software-Systems versteht man die Fähigkeit eines Software-Systems, auf ein anderes System übertragen werden zu können. Sie wird beschrieben durch Anpassbarkeit, Installierbarkeit, Koexistenz, Austauschbarkeit und Konformität. Für die weitere Arbeit wird besonders auf die Qualitätsmerkmale Zuverlässigkeit, Änderbarkeit und Wartung eingegangen. Die Bedeutung dieser Qualitätsmerkmale bezüglich der Erzeugung von Objekten in Software-Systemen wird in den nächsten Abschnitten dieses Kapitels erörtert. Testen als Vorrausetzung für Zuverlässigkeit, Änderbarkeit und Wartung Die Zuverlässigkeit eines Software-Systems, also die korrekte Erledigung der Aufgaben, lässt sich am besten durch Software-Tests überprüfen. Indirekt sind auch die Merkmale Änderbarkeit und Wartung von der Testbarkeit eines Systems abhängig. Je leichter ein System zu testen ist, desto einfacher ist es, dieses System auf neue fachliche oder technische Anforderungen anpassen zu können. Testbarkeit ist somit eine der wichtigsten Vorrausetzung für die Qualitätsmerkmale Zuverlässigkeit, Änderbarkeit und Wartung. Zunächst wird der Begriff Testen definiert, um anschließend Testbarkeit von Software näher zu betrachten. In [Bin99] wird Testen definiert als das Ausführen eines Programmes, bzw. von Programmteilen, unter verschiedenen Kombinationen von Eingaben und Zuständen, wobei erwartete und reale Ausgaben verglichen werden. Es ist insbesondere bei interaktiven Programmen praktisch unmöglich alle erdenkbaren Kombinationen von Eingaben zu simulieren und mit den erwarteten Ausgaben zu vergleichen. In [Dij72] wird deshalb ausgeführt: Man kann nur die Anwesenheit von Fehlern, nicht deren Abwesenheit beweisen. Testen kann also nicht formal die Korrektheit von Software beweisen, noch Evaluation oder konstruktive Kritik bei der Qualitätssicherung ersetzen. Das Testen von Software ist neben Analyse, Entwurf, Implementation, sowie Einsatz und Wartung, Teil jeder Vorgehensweise bei der Entwicklung von Softwaresystemen. Nach [Bin99] werden Software-Tests unterteilt in Komponenten-, Integrations- und Akzeptanztests. Dabei wird die Größe und Zusammengehörigkeit der jeweils zu testenden Softwarekomponenten als Unterscheidungsmerkmal gewählt. Bei einem Komponententest wird eine kleine Einheit getestet. Bei objektorientierten Systemen handelt es sich hier um eine Klasse oder mehrere eng zusammenhängende Klassen. Fehler können lange unentdeckt bleiben, wenn keine Komponententests geschrieben werden. Tests auf dieser Ebene prüfen eine wesentlich größere Menge von möglichen Eingaben und Zuständen, als dies ein Integrationstest oder Systemtest könnte. Die Zeit, bis einen Fehler gefunden wird, lässt sich deutlich reduzieren, wenn eine zu prüfende Klasse ausgiebig durch die Entwickler getestet wird. Das Zusammenspiel mehrerer zusammengehörender Einheiten soll beim Integrationstest geprüft werden. Bei der Entwicklung eines objektorientierten Systems lässt sich zwischen Komponententests und Integrationstests schwer trennen, besonders wenn eine Komponente von mehreren anderen Komponenten abhängt. Die Abhängigkeiten mehrerer Komponenten für die Integrationstests zu beschreiben, wird

13 2.1. BEGRIFFSKLÄRUNGEN UND ABGRENZUNG 9 durch die Arbeit adressiert und eine einfache Lösung mit Dependency Injection angeboten. Der Systemtest soll das fertige System als Ganzes prüfen. Hierbei wird nicht nur die Funktionalität des Systems anhand der Ein- und Ausgaben und das Zusammenspiel der verschiedenen Komponenten geprüft. Zusätzlich wird überprüft, ob die nichtfunktionalen Anforderungen erfüllt werden, wie z.b. die Performanz. Testbarkeit In dem vorigem Abschnitt wurde behauptet das Testen und eine einfachere Testbarkeit das Erreichen hoher Qualität erleichtert. Durch Tests können adressierte Fehler ausgeschlossen werden. Je leichter ein Software-System zu testen ist, desto eher lässt sich mit diesem System eine hohe Qualität bzgl. der Merkmale Zuverlässigkeit, Änderbarkeit und Wartung erreichen. Es muss nun genauer betrachtet werden, welche Vorraussetzungen für eine einfache Testbarkeit notwendig sind und warum dies zu guter Qualität führt. Bei einem Test wird ein Teil der Software ausgeführt. Um diesen Teil, bzw. diese Komponente auszuführen, muss diese eventuell initialisert werden. Beim Test muss betrachtet werden, welche Klasse getestet wird und welche abhängigen Klassen in dieser Komponente benutzt werden. Es kann von den abhängigen Typen mehrere Ausprägungen geben. Es ist wichtig, dass der Test direkt nur die zu testende Komponente überprüft und nicht indirekt die abhängigen Klassen oder Komponenten. Das wird am Beispiel aus der Einführung in Abbildung 1.1 verdeutlicht. Der Komponenten-Test für den Bücherservice soll nur den Bücherservice testen, nicht aber das BuecherRepository. Ein BücherService benutzt ein BuecherRepository, insofern muss dieser bei der Ausführung der Tests für den BuecherService vorhanden sein. Das BuecherRepository ist die abhängige Komponente, es muss sich vor der Ausführung in einem eindeutigen und definierten Zustand befinden, um Aussagen über die zu erwartenden Ergebnisse zu machen. Es kann sogar von Vorteil sein, eine andere Implementierung für den Test zu benutzen. Wenn z.b. das BuecherRepository auf eine Datenbank zugreift, dann ist es einfacher das BuecherRepository durch eine Mock- oder Dummy-Implementierung zu ersetzen, die nicht auf die Datenbank zugreift. Der Test für den BuecherService soll nur den BuecherService prüfen, nicht aber das BuecherRepository oder gar die Datenbank und deren Zustand. Für den eigentlichen Test ist es also wichtig zu wissen, welches BuecherRepository benutzt wird und in welchem Zustand sich die abhängige Komponente befindet. Das Beispiel hat gezeigt, das für den Test einer Klasse oder einer Komponente die abhängigen Klassen oder Komponenten wichtig sind. Diese abhängigen Klassen müssen leicht zu initialisieren sein, damit die Klasse einfach getestet werden kann. Ein Komponenten-Test wird erleichtert, wenn sich abhängige Komponenten mit wenig Aufwand durch andere Implementierungen ersetzen lassen. Das eine abhängige Komponente leicht ausgetauscht werden kann, ist ein direktes Indiz für eine leichte Erweiterbarkeit und Änderbarkeit und somit für bessere Qualität der Software. Es zeigt sich also, dass einfache Testbarkeit zu einem besseren Design führt. Ein-

14 10 KAPITEL 2. GRUNDLAGEN fache Testbarkeit und eindeutige Abhängigkeiten fördern gute Strukturierung und Erweiterbarkeit. 2.2 Designprinzipien Für die Erstellung qualitativ hochwertiger Software haben sich über die Zeit bestimmte Design-Prinzipien in der Softwaretechnik als nützlich herausgestellt. In diesem Abschnitt wird eine Auswahl bekannter, aus der Literatur entlehnter Designprinzipien vorgestellt. Hierbei soll auch die Frage geklärt werden, wie groß eine Komponente sein darf. Wieviele Klassen dürfen zu einem Modul gehören und welche Klassen gehören zu welchen Modulen? Die Auswahl der Design-Prinzipien habe ich aufgrund von eigener Erfahrung aus realen Projekten vorgenommen. Dieser Abschnitt wird diese Prinzipien vorstellen und erörtern, warum diese Designprinzipien zu hoher Qualität beitragen. Die gewählten Design-Prinzipien werden bei den Ergebnissen der Arbeit in Kapitel 5 wieder betrachtet. Dort wird analysiert, welche Auswirkung die Prinzipien auf die gewählte Lösung haben. Lose Kopplung Lose Kopplung ist ein fester Begriff in der Softwaretechnik. In [YC79] wird Kopplung und Kohäsion als Beziehungen zwischen und innerhalb von Modulen beschrieben. Unter Kopplung versteht man die Abhängigkeiten zwischen Modulen bzw. die Wahrscheinlichkeit, wenn ein Modul verändert wird, dass abhängige Module angepasst werden müssen. Die Kohäsion beschreibt die Abhängigkeiten innerhalb eines Moduls. Lose Kopplung führt zu schmalen Schnittstellen zwischen den Modulen. Je mehr sich Module untereinander kennen, desto enger sind sie gekoppelt. Je weniger die Module voneinander kennen, desto loser sind sie gekoppelt. Single-Responsibility-Principle Das Single-Responsibility-Principle wird von Robert C. Martin in [Mar03] beschrieben: A class should have only one reason to change. Das Prinzip beschreibt, dass eine Klasse genau nur eine Verantwortung haben und daher genau nur eine Abstraktion abdecken soll. Hätte eine Klasse mehrere Verantwortlichkeiten, dann würde es auch mehrere Gründe geben, warum sich die Klasse ändern könnte. Änderungen an dieser Verantwortlichkeit sollen dann nur an dieser einen Klasse gemacht werden müssen oder die Klasse muss aufgeteilt werden. Eine Klasse kann mehrere Verantwortungen im Laufe der Zeit bekommen, wenn die funktionalen Anforderungen eines Systems im Laufe der Zeit heranwachsen. Dann wird es an der Zeit, diese unterschiedlichen Verantwortungen auf mehrere Klassen aufzuteilen.

15 2.2. DESIGNPRINZIPIEN 11 Abbildung 2.2: Klient ist nicht offen und geschlossen Open-Closed-Principle Das Prinzip wird von Bertrand Meyer in [Mey97] beschrieben. Es besagt, dass ein Modul offen sein soll für Erweiterungen, aber geschlossen für Veränderungen. Damit ist die Grundlage für die Eigenschaften objektorientierter Software bzgl. Erweiterbarkeit und Wiederverwendung beschrieben. Wie kann nun ein Modul gleichzeitig offen für Erweiterungen und geschlossen für Änderungen sein? Die Erweiterung eines Moduls ist nötig, wenn neue fachliche Anforderungen erfordern, dass das Modul um neues Verhalten erweitert wird. Das Modul soll geschlossen sein gegen Änderungen. Die Erweiterungen sollen möglich sein, ohne das der Sourcecode oder die Bibliothek des Moduls geändert werden muss. Die Erweiterung kann erreicht werden über die Implementierung abstrakter Klassen. Das Modul bietet eine abstrakte Klasse an, über deren Implementierung das Verhalten des Moduls erweitert werden kann, ohne es zu verändern. Die Abbildung 2.2 zeigt ein einfaches Design, das nicht dem open-closed-principle entspricht. Der Klient und der Anbieter sind konkrete Klassen. Wenn der Klient einen anderen Anbieter benutzen soll, dann muss dafür der Klient verändert werden und den anderen Anbieter direkt benennen. Die Abbildung 2.3 zeigt dagegen ein Design das dem open-closed-principle entspricht. Der Klient benutzt nur die abstrakte Klasse KlientenSchnittstelle. Die abstrakte Klasse KlientenSchnittstelle bietet abstrakte Methoden an. Diese Klasse und deren Methoden werden von einer konkreten Klasse, dem Anbieter, implementiert. Soll nun der Klient einen anderen Anbieter benutzen, so kann eine andere Implementierung der KlientenSchnittstelle benutzt werden. Für diese Erweiterung muss der Klient nicht geändert werden, trotzdem ist er offen für Erweiterungen. Vertragsmodell Das Vertragsmodell wird von Bertrand Meyer in [Mey97] genau beschrieben. Es wird auch häufiger unter dem Namen Design-by-Contract oder abgekürzt als DBC geführt. Mit dem Vertragsmodell führt Meyer eine Beziehung zwischen zwei Objekten ein, die aus Zusicherung, Vorbedingung, Nachbedingung und Invarianz besteht.

16 12 KAPITEL 2. GRUNDLAGEN Abbildung 2.3: Klient ist beides, offen und geschlossen (Strategy-Muster) Liskov-Substitution-Principle Das Liskov-Substitution-Principle wurde von Barbara Liskov in dem Artikel [LW94] beschrieben. Es sagt aus, dass Typen ersetzbar sein sollen durch Subtypen. Ursprünglich ist es eine Definition von Typisierung und eine Einordnung, was Subtypen sind. Das ist nicht zu verwechseln mit der Typisierung, die eine Programmiersprache liefert wie z.b. Java. Dort kann es z.b. der Fall sein, das eine Subklasse gebildet wird, die nicht dem Liskov-Substitution-Principle entspricht. Interface-Segregation-Principle Das Interface-Segregation-Principle wird beschrieben in [Mey97] als: Clients should not be forced to depend upon interfaces that they do not use. Das Prinzip besagt, dass eine Klasse, die von sehr unterschiedlichen Klassen benutzt wird, auch unterschiedliche Schnittstellen anbieten muss. Wenn diese Trennung über die Schnittstelle nicht wäre, dann müssten alle abhängigen Klassen des Anbieters auch angepasst werden. Common-Closure Principle Die Klassen in einem Package sollen geschlossen gegenüber Veränderungen sein. Eine Veränderung soll nur Auswirkungen innerhalb eines Packages haben. Dieses Prinzip ist die Verallgemeinerung des Single-Responsibility-Principle von Seite 10. Genau wie beim Single-Responsibility-Principle eine Klasse nur einen Grund haben sollte für eine Veränderung, sollten alle Klassen eines Packages nur einen Grund haben angepasst zu werden. Das Prinzip besagt somit auch, dass ein Package genau eine Verantwortung haben sollte. Eine Änderung an dieser Verantwortlichkeit sollte auch nur dieses Package betreffen. Durch diese Forderung wird Wartbarkeit vor Wiederverwendbarkeit gestellt. Mit diesem Prinzip ist für die Arbeit eine geeignete Größe für die Definition aller zusammenhängenden Klassen gefunden, wie sie im Abschnitt Testbarkeit auf Seite 9 gesucht wurde. Zu einem Modul gehören also alle Klassen in einem Package bei einem Komponenten-Test, damit ist der Komponenten-Test ausreichend klein. Alle

17 2.3. ZUSAMMENFASSUNG 13 anderen Klassen außerhalb dieses Packages gehören nicht zu einem Komponenten- Test. YAGNI Das Prinzip YAGNI ist eine Abkürzung und steht für You ain t gonna need it. Es bezeichnet den Ausdruck, wenn Software auf Vorrat gebaut wird. Es sollte nichts programmiert werden, für das aktuell keine fachliche oder technische Notwendigkeit besteht. 2.3 Zusammenfassung In diesem Kapitel wurden die Grundlagen der Arbeit beschrieben, um in den weiteren Kapiteln der Arbeit darauf verweisen zu können. Der Begriff Qualität wurde anhand bekannter Definitionen vorgestellt. Testbarkeit ist als wichtigster Faktor für die Qualität von Softwaresystemen erkannt und beschrieben worden. Dabei wurde die Wichtigkeit möglichst einfacher Initialisierung von Softwaretests festgestellt. Wenn es möglich ist Komponenten-Tests zu schreiben ohne abhängige Klassen anderer Komponenten zu benutzen, zeigt das direkt die Erweiterbarkeit und Qualität der Software. In diesem Fall kann die Komponente auch in einem anderen Kontext benutzt werden. Abschliessend wurden aus der Literatur entlehnte, in der Softwaretechnik etablierte Designprinzipien vorgestellt. Insbesondere mit dem Common-Closure-Principle ist eine geeignete Größe gefunden worden, um zu definieren, wieviele und welche Klassen zu einem Komponenten-Test gehören: Nur die Klassen in einem Package gehören zu einem Komponenten-Test, dann ist der Test ausreichend klein.

18 Kapitel 3 Gegenstand der Arbeit In diesem Kapitel wird das CommSy genauer beschrieben. Zuerst wird das CommSy fachlich erläutert und dabei die Frage geklärt, welchen Zweck es erfüllt. Der technische Hintergrund wird erläutert, der Unterschied zwischen CommSy und dem Gegenstand der Arbeit, dem JCommSy, sowie die Technologien, mit denen das JCommSy realisiert ist. Im zweiten Abschnitt wird die vorgefundene Architektur des CommSys beschrieben. Dabei wird neben einer abstrakten Beschreibung der Software, insbesondere die Erzeugung von Objekten betrachtet. Hierbei werden auch die Probleme der vorgefundenen Architektur bzgl. der direkten Erzeugung von Objekten für Testbarkeit und Erweiterbarkeit gezeigt. Dabei wird das CommSy mit Metriken vermessen und untersucht, ob das JCommSy die im vorigen Kapitel vorgestellten Designprinzipien beachtet. 3.1 Das CommSy Das Community System, kurz CommSy, ist aus einem universitären Projekt zum Wissensmanagement entstanden, in dem unterstützende Dienste zur Projektarbeit und für Arbeitsgruppen entwickelt wurden. Sein technischer Kern ist eine dynamische Webserver-Applikation, die die Kommunikation zwischen den Mitgliedern eines Projektes erlaubt. Das System wurde in einer großen Anzahl von Projekten benutzt und wissenschaftlich ausgewertet. Die Entwicklung des Prototypen begann mit zwei bis fünf Personen. Seitdem haben viele Lehrveranstalter das CommSy in Veranstaltungen unterschiedlicher Universitätskontexte verwendet, u.a. bei der Internationalen Frauenuniversität. Fachlicher Hintergrund Das CommSy ist eine Webanwendung zur Unterstützung der Kommunikation von Lehrveranstaltungen. Das Ziel ist gemeinsames Lernen. Das CommSy benutzt die Metapher der Räume. So gibt es einen Gemeinschaftsraum, auf den alle eingetragenen Benutzers des CommSys zugreifen können. Für einzelnen Lehrveranstaltungen 14

19 3.1. DAS COMMSY 15 Abbildung 3.1: Screenshot CommSy gibt es Projekträume. Für jeden dieser Projekträume gibt es eine Übersicht. Um in einen Projektraum zu kommen, muss eine Mitgliedschaft beantragt und genehmigt werden. Es können somit nur genehmigte Teilnehmer am Geschehen im Projektraum teilhaben. Die Abbildung 3.1 zeigt einen Screenshot der Übersicht eines exemplarischen Projektraumes eines CommSys. Ein einzelner Projektraum wird wiederum untergliedert in unterschiedliche Rubriken. Typische Rubriken sind z.b. Ankündigungen, Termine, Materialien oder Diskussionen. So können z.b. besondere Ereignisse im Zusammenhang mit der Lehrveranstaltung angekündigt werden. Es ist möglich eine Diskussion zu einem bestimmten Thema zu starten, bei der alle Benutzer des Raumes teilnehmen können. Es ist auch möglich Materialien, z.b. Dokumente den Teilnehmern zur Verfügung zustellen. Für jeden Projektraum können einzelne Rubriken ein- oder ausgeblendet werden. Das System wurde aufgrund der Projektanforderungen stetig weiterentwickelt. Zuerst wurde das CommSy für die Unterstützung von Projekten in der Hochschullehre entwickelt, es wird dort für Seminare und Vorlesungen eingesetzt. Mittlerweile wird das CommSy auch in anderen Bereichen benutzt um vernetzte Projektarbeit zu unterstützen. Das CommSy wird zurzeit aktiv weiterentwickelt und stetig an neue Anforderungen angepasst.

20 16 KAPITEL 3. GEGENSTAND DER ARBEIT Abbildung 3.2: Architektur PHP-CommSy Technischer Hintergrund Das Projekt CommSy ist ursprünglich in der Programmiersprache PHP realisiert. Es benutzt für die Speicherung der Daten eine MySQL-Datenbank. Die Architektur des PHP-CommSys wird in Abbildung 3.2 gezeigt. Ein Webserver mit PHP-Engine beantwortet die Anfragen der Webbrowser. Das CommSy bezieht seine Informationen aus der Datenbank, aktualisiert diese und schreibt dorthin je nach Anfrage auch neue Informationen. Seit 2004 wird das CommSy schrittweise umgestellt auf die Plattform Java unter dem Namen JCommSy. Hier werden die Technologien Servlets und JavaServer Pages (JSP) benutzt. Es erfolgt eine schrittweise Umstellung der einzelnen Kategorien. Für die schrittweise Umstellung wird die aktuelle Session, der Zustand der Anwendung, vom PHP-System in die Datenbank serialisert. Der Zugriff auf die Daten und die Synchronisation erfolgt über eine Session-ID und die gleiche MySQL-Datenbank. Ein Filter deserialisiert diese Informationen vor jedem Zugriff für die Java-Anwendung. Diese Information beinhaltet den aktuellen Benutzer und seine Rechte. 3.2 Die vorhandene Architektur Das vorhandene CommSy besteht aus zwei großen Teilprojekten, der Version in PHP und der migrierten Version in Java. Das alte CommSy ist geschrieben in PHP und wird in dieser Arbeit nicht detailliert betrachtet. Die abstrakte Beschreibung aus dem vorigen Kapitel ist für die Arbeit und den praktischen Teil ausreichend. Für die Arbeit ist der neue in Java realisierte Teil von Interesse, das JCommSy. Die dort vorgefundene Architektur entspricht dem Muster Model-View-Controller. Bei diesem Muster ist die Anwendung in drei Komponenten aufgeteilt, das Model, die View und den Controller. Das Model beinhaltet im Muster die Anwendungslogik und Daten. Ein typisches Beispiel für ein Model im JCommSy ist das Objekt Room. Das Objekt modelliert einen Raum im JCommSy, dort sind der Name und weitere Informationen gespeichert. Im Model werden mit Objekten die fachlichen Entitäten und die Geschäftslogik modelliert. Die Benutzungsschnittstelle, das User Interface (UI), wird durch View und Controller repräsentiert. Der Controller verarbeitet die Eingaben des Programms und aktualisiert das Model. Die View ist zuständig für die Darstellung der Ausgabe. Meistens registriert sich die View als Callback beim Model für inhaltliche Änderungen am fachlichen Modell,

21 3.2. DIE VORHANDENE ARCHITEKTUR 17 Abbildung 3.3: MVC - Architektur damit diese Änderungen sofort angezeigt werden können. Die Trennung zwischen Model, View und Controller soll die Erweiterbarkeit und Testbarkeit erhöhen. Der Ursprung des MVC-Musters sind Desktopanwendungen. Das komplette Muster ist in der Abbildung 3.3 gezeigt. Bei einer Webanwendung wie dem JCommSy ist die View meist mit JavaServer Pages (JSPs) realisiert. Beim JCommSy wird der Controller durch ein Servlet realisiert. Das Servlet bearbeitet die Eingaben, die durch einen Webbrowser geschickt werden, und liest dafür aus dem HTTP-Request die Parameter aus. Im Bereich der Webandwendungen wird noch weiter unterschieden zwischen MVC1 und MVC2. Die Unterscheidung liegt in der Geschichte der Webanwendungen, die in Java geschrieben wurden. In Abbildung 3.4 ist die MVC1-Architektur dargestellt. Hier waren noch View und Controller in der JSP vereint. Somit ist hier die JSP nicht nur für die Darstellung zuständig, dort werden auch die Aufgaben des Controllers übernommen. In JSP-Seiten wird mit HTML die Darstellung definiert. Zusätzlich kann in den JSP-Seiten auch Java-Code aufgerufen werden. Da MVC1 die View und den Controller in der JSP-Seite vereint, wird diese bei komplexeren Anwendungen schnell unübersichtlich. Aus diesem Grund ist MVC1 keine vollständige MVC-Architektur, es entstammt nur der Zeit, in der die ersten Präsentationsframeworks für Java entwickelt wurden. Bei der MVC2 Architektur, wie in Abbildung 3.5 gezeigt, wurden der Controller und die View getrennt, um so wenig wie möglich ausführbaren Code im View zu benutzen. Der Controller ist als Servlet realisiert und leitet die Anfragen an das Model weiter. Die View in MVC2 benutzt JSP als Technologie für die Ausgabe. Durch die Trennung von View und Controller handelt es sich bei MVC2 um ein vollständiges Model-View-Controller-Muster. Für die weitere Betrachtung der Architektur wurde der Kontrollfluss innerhalb der Anwendung betrachtet. Der Kontrollfluss geht vom Servlet aus, ausgelöst durch eine Anfrage von einem Browser. Das CommSy-Servlet analysiert die Anfrage. Zum Beispiel wird geprüft, ob aktuell ein Benutzer angemeldet ist oder welche Funktion der Benutzer ausgewählt hat. Das CommSy-Servlet leitet die Anfrage weiter an Actions oder ComponentCommands, entsprechend der Funktion, die der Benutzer ausgewählt hat. Die Actions oder ComponentCommands lesen die Parameter aus,

22 18 KAPITEL 3. GEGENSTAND DER ARBEIT Abbildung 3.4: MVC1 - Architektur Abbildung 3.5: MVC2 - Architektur

23 3.2. DIE VORHANDENE ARCHITEKTUR 19 stoßen entsprechende fachliche Funktionen an und leiten anschließend weiter an eine JSP-Seite. Das JCommSy ist also als klassische MVC2-Architektur realisiert. Neben dieser statischen Analyse muss auch der dynamische Aspekt der Anwendung betrachtet werden. Damit wird jetzt ein zentrales Thema dieser Arbeit behandelt, es wird die Fragestellung beantwortet, welche Objekte zu welchem Zeitpunkt andere Objekte erzeugen bzw. wie sie auf andere Objekte zugreifen können. Hierfür werden der Kontrollfluß und anschließend die fachlichen Services genauer betrachten. Kontrollfluss Für eine Analyse des Systems ist eine genaue Betrachtung des Kontrollflusses wichtig. Es muss analysiert werden, an welchen Stellen durch das Servlet-Framework bzw. den Applikations-Server der JCommSy-Code aufgerufen wird. Die Frage nach den Einstiegspunkten des Kontrollflusses ist für die Analyse der Objekterzeugung wichtig und für die Planung einer Umstellung auf eine der möglichen Lösungen von Nöten. Eine genauere Betrachtung des Sourcecodes hat gezeigt, dass nicht nur durch Servlets der Kontrollfluss vom Servlet-Container bzw. dem Servlet-Framework an das JCommSy-System weitergereicht wird. Es werden im JCommSy auch Filter eingesetzt, z.b. für die Migration. Die Filter werden vor und nach dem Aufruf des Servlets durch den Servlet-Container aufgerufen. Dort liest ein Filter den angemeldeten Benutzer aus der aktuellen Session und prüft, ob die angefragte Funktionalität überhaupt durch das Java-System behandelt werden kann. Damit sind nicht nur Services, sondern auch die Filter ein Einstiegspunkt für den Kontrollfluss im JCommSy. Neben diesen direkten Einstiegspunkten in den Kontrollfluss fallen bei der Analyse des Sourcecodes die Component Commands auf. Sie wurden durch die Arbeit von Christoph Hohmann [Hoh07] als Erweiterung der Architektur eingeführt. Bei der Erzeugung einer darzustellenden Seite im JCommSy wird dynamisch zur Laufzeit ein Baum von Component Commands erstellt. Dieser Baum entspricht in seiner Struktur dem Aufbau der Seite. Für jede Darstellungskomponente findet sich ein Pendent im erstellten Baum der Component Commands. Diese Component Commands stellen die Funktion bereit die in der Darstellung angeboten werden. Durch diese Architektur sollen häufig verwendete Elemente in der Darstellung einfacher wieder zu verwenden sein bei der Implementierung neuer Funktionalitäten. Diese Komponenten sind für diese Arbeit von Interesse, denn diese Bäume werden bei jedem Zugriff auf das JCommSy entsprechend der Anfrage neu erzeugt. Es findet also Objekterzeugung statt. Diese Objekte benutzen für die Erledigung ihrer Aufgaben Services. Für die Services greifen sie auf die ServiceRegistry bzw. das ServiceRegistrySingleton zu. Das Singleton und weitere Muster werden wir später noch auf Seite 22 und folgend betrachten. Die Component Commands unterscheiden sich aber im Bezug auf die Erzeugung von den Services. Ein solches Component Command wird bei jeder Anfrage neu erzeugt. Für einen Service muss für die gesamte Laufzeit der Anwendung nur einmal ein Objekt erzeugt werden. Der dahinter liegende Unterschied zwischen den Services und den Component

24 20 KAPITEL 3. GEGENSTAND DER ARBEIT 1 public void execute(item item, CallContext cc, C HttpServletRequest request) throws CommsyException { 2 // Load topics which are attached to the item 3 List<Link> links = ServiceRegistrySingleton.getLinkServiceC ().getitems(item.getitemid(), ItemType.TOPIC); 4 Map<ItemID, Topic> topics = ServiceRegistrySingletonC.getTopicService().getItemsMap(ItemCollectionUtilC.linkedIDs(links, item)); 5 Map<ItemID, User> creators = C ServiceRegistrySingleton.getUserService().C getitemsmap(itemcollectionutil.creatorids(links))c ; 6 // Der Rest der Methode ist hier nicht von Interesse... 7 } Listing 3.1: Zugriff auf Services im DetailedTopicsCommand Commands ist der Zustand dieser Objekte. Die Services im JCommSy sind zustandslos implementiert. Außerhalb der Methoden sind keine Variablen definiert, die durch eine Anfrage verändert werden. Die Services benutzen selber nur zustandslose andere Services. Aus diesem Grund kann ein Exemplar eines Services gleichzeitig für viele unterschiedliche Anfragen genutzt werden. Die Commands haben einen Zustand entsprechend der konkreten Anfrage, in dessen Kontext sie gerade benutzt werden. Daher kann ein Exemplar eines Commands nur für eine Anfrage erzeugt und benutzt werden. Aus der Beobachtung von Services und Component Commands lässt sich feststellen, dass Exemplare dieser Objekte abhängig von Kontexten unterschiedlich häufig erzeugt werden. Es gibt Objekte, die nur einmal pro Anwendung erzeugt werden, und Objekte, die nur in einem bestimmten Kontext, wie z.b. einer Session oder einem Komponenten-Baum, jeweils einmal erzeugt werden. Services Fachliche Funktionen sind häufig in Services gekapselt. Services sind neben Fachwerten und Geschäftsobjekten eine der wichtigsten Abstraktionen die beim JCommSy genutzt werden. Es gibt z.b. Services, die Objekte in der Datenbank persistieren, suchen oder aktualisieren 1. Diese Services benötigen Ressourcen, z.b. eine Datenbankanbindung oder sie benutzen weitere Services. Um auf Services zuzugreifen, wird eine Singeleton-Factory benutzt. Hier wird mit dem Muster Singleton, siehe auch [GHJV94], der Zugriff auf die Services ermöglicht. Ein statisches Attribut verweist auf die einzige vorhandene Instanz. Der Zugriff auf diese Instanz erfolgt über eine statische Methode. 1 Diese Serviceobjekte werden auch DAO genannt, für Data Access Object

25 3.3. MUSTER IM JCOMMSY 21 Abbildung 3.6: Abhängigkeiten über das ServiceRegistrySingleton Um die Architektur genauer zu beurteilen, muss der Kontrollfluss an einem konkreten Beispiel betrachtet werden. Ein Beispiel ist der Zugriff in einer Methode aus der Klasse DetailedTopicsCommand auf den LinkService wie gezeigt in Listing 3.1. Dort werden alle Verweise geladen. Hierfür wird der LinkService benötigt. Der wird über die Klasse ServiceRegistrySingleton bezogen, diese hat eine statische Methode getlinkservice. Nach dem selben Muster wird für die Bearbeitung der Anfrage auf den TopicService und den UserService zugegriffen. Die Abhängigkeiten ausgehend von der Klasse DetailedTopicsCommand sind in Abbildung 3.6 gezeigt. Das Command greift auf das ServiceRegistrySingleton zu. Das hat ein statische Feld mit einer ServiceRegistry. Daher wurde sie als Singleton bezeichnet, denn sie erzeugt nur einmal diese Registry. Diese Registry wird benutzt bei der Abfrage zum aktuellen LinkService. Die Registry selber ist kein Singleton. Sie erzeugt aber bei der Initialisierung einen LinkService. Dafür muss die Registry eine konkrete Implementierung benutzen, den LinkServiceImpl. Alle Klassen benutzen das Interface LinkService, bis auf die ServiceRegistry. Diese erzeugt initial die konkrete Implementierung für den LinkService und kennt daher die Implementation LinkServiceImpl. Somit hat auch das DetailedTopicsCommand eine implizite Abhängigkeit zu dieser konkreten Implementierung. Der Ursprung dieser Abhängigkeit ist die direkte Objekterzeugung in der Registry und das dadurch entstandene Wissen um die konkrete Implementierung dieses Services. 3.3 Muster im JCommSy Um einen Einblick in die Architektur des JCommSy zu bekommen, wird diese mit Entwurfsmustern beschrieben. Zuerst werden die benutzten Muster erläutert und anschließend wird die Benutzung und Anpassung dieser Muster im JCommSy beschrieben.

26 22 KAPITEL 3. GEGENSTAND DER ARBEIT 1 public class Singleton { 2 private Singleton() {} 3 private static Singleton instance = null; 4 public static Singleton instance() { 5 if (instance == null) 6 instance = new Singleton(); 7 return instance; 8 } 9 10 // weitere fachliche Methoden 11 } Listing 3.2: Singleton-Muster Singletons Das Entwurfsmuster Singleton ist in [GHJV94] beschrieben. Dort wird es als Erzeugungsmuster kategorisiert. Ein Singleton soll sicher stellen, dass ein Objekt nur einmal erzeugt werden kann. Das Singleton liefert dabei den Zugriff auf dieses Exemplar des Objektes. Im Listing 3.2 ist dargestellt wie in Java ein Singleton implementiert wird. Das einzige Exemplar der Klasse wird in einer statischen Klassenvariable gespeichert. Der Zugriff auf dieses Exemplar erfolgt über eine statische Methode. Diese Methode liefert das einzige Objekt dieser Klasse zurück. Falls noch kein Objekt dieser Klasse erzeugt wurde, wird eines erzeugt und der statischen Klassenvariable zugewiesen. Bei einem weiteren Zugriff über die Methode instance wird genau wieder dieses Exemplar zurück gegeben. Die Sichtbarkeit des Konstruktor wird als private deklariert, somit können nur Methoden aus dieser Klasse ein Exemplar erzeugen. Singletons haben den Vorteil, dass sie einen zentralen Zugriffpunkt haben und nur genau ein Exemplar dieser Klasse zulassen. Genau dieses Verhalten kann auch als nachteilig angesehen werden. Ein Singleton hat mindestens zwei Verantwortungen. Einmal bietet es die fachlichen Funktionen der Klasse an und zum anderen stellt es sicher, dass nur ein Exemplar dieser Klasse erzeugt wird. Damit widerspricht das Singleton einer strikten Auslegung des Single-Responsibility-Principles. Singletons sind für die Testbarkeit von Nachteil. Greift das getestete Objekt auf ein Singleton zu, besteht keine einfache Möglichkeit das Singleton vom Test zu isolieren. Das Singleton gehört dann immer zu den Klassen die mit dem eigentlich zu testenden Objekt mitgetestet werden. Service Locator Das Muster Service Locator wird beschrieben in [ACM03]. In diesem Buch werden gängige Muster in J2EE-Umgebungen beschrieben. Das Klassendiagramm zum Muster Service Locator ist in Abbildung 3.7 dargestellt. Der Service Locator soll die auf-

27 3.3. MUSTER IM JCOMMSY 23 Abbildung 3.7: Klassendiagramm J2EE Service Locator, aus [ACM03] wendige Suche nach verteilten Services in diesen J2EE-Umgebungen kapseln und vereinfachen. Der Service Locator übernimmt die Lokalisierung der Komponenten, sucht mit einem InitialContext nach einer Factory für den gesuchten Service. Diese Factory erzeugt oder lokalisiert den Service und der Service Locator gibt diesen Service als Ergebnis der Suche zurück. Wenn keine J2EE-Komponenten wie z.b. EJBs verwendet werden und auch Services nicht über einen InitialContext verteilt werden, kann ein vereinfachter Service Locator benutzt werden. Diese vereinfachte Beschreibung befindet sich auch in [Fow04]. In diesem Fall erzeugt der Service Locator die Services selber, anstatt diese über einen InitialContext o.ä. zu beziehen. In Abbildung 3.8 ist ein Klassendiagramm dargestellt, das die Benutzung eines einfachen Service Locators darstellt. Hier bezieht der BuecherService das benötigte BuecherRepository über einen Service Locator. Der Service Locator bietet somit eine Abstraktion über die Lokalisierung oder Erzeugung des benutzten Services an. Es besteht nur noch eine indirekte Beziehung vom benutzenden Klienten und dem konkreten Anbieter. Im Beispiel kennt der BuecherService direkt nur die Schnittstelle BuecherRepository, nicht aber die konkrete Implementierung. Die Implementierung des konkreten BuecherService ist im Service Locator verankert, dieser erzeugt im Beispiel bei Bedarf das konkrete BuecherRepositoryImpl. Die Benutzung eines Service Locators wirkt sich im Vergleich zu Singletons besser auf Tests aus. Für den Test kann der Service Locator programmatisch konfiguriert werden, so das er eine gewünschte Implementierung beim Zugriff liefert. Der Nachteil dieser Lösung liegt darin, das die Möglichkeit den Service Locator programmatisch zu konfigurieren nur für Tests implementiert werden muss, diese Funktionalität

28 24 KAPITEL 3. GEGENSTAND DER ARBEIT Abbildung 3.8: Klassendiagramm eines einfachen Service Locators 1 public static void setdatabaseservice(databaseservice C service) { 2 ServiceRegistrySingleton.getInstance().C setdatabaseservice(service); 3 } 4 5 // usw. Listing 3.3: Ausschnitt aus der Klasse ServiceConfigurator ist für den Einsatz der Software nicht unbedingt notwendig. Einsatz der Muster im JCommSy Betrachtet man die Nutzung der Muster Singleton und Service Locator im JCommSy fällt sofort das ServiceRegistrySingleton auf, siehe Abbildung 3.6. Die Klasse hat eine statische Klassenvariable, die genau eine ServiceRegistry referenziert und bietet eine statische Methode als einzigen Zugriffspunkt zu dieser ServiceRegistry an. Die Klasse ServiceRegistrySingleton hat nur statische Methoden für den Zugriff und verwaltet eine ServiceRegistry, somit ist diese Klasse im eigentlichen Sinne kein Singleton. Hier entspricht die Klasse dem Single-Responsibility- Principle. Die Klasse ist nur für die Verwaltung der ServiceRegistry zuständig. Sie verhindert, dass mehrerer Exemplare der Registry vorhanden sind und bietet einen gemeinsamen Zugriffspunkt an. Für die Konfiguration der Tests gibt es im JCommSy die Klasse ServiceConfigurator. Mit Hilfe dieser Klasse können Tests einen eigenen Service setzen. In Listing 3.3 ist die Methode setdatabaseservice exemplarisch aufgeführt. Für alle Services, die im JCommSy verwendet werden, bietet der Configurator eine Methode zum Austausch des jeweiligen Service an.

29 3.4. ERGEBNISSE DER VERMESSUNG Ergebnisse der Vermessung Für die Vermessung des Sourcecodes sind die Metriken von Robert C. Martin aus [Mar03] benutzt worden, die dort als stability metrics bezeichnet werden. Die wichtigsten Maße dieser Metriken sind afferent couplings, efferent couplings, abstractness und instability. Diese Metriken werden in dieser Arbeit benutzt, um die Abhängigkeiten zwischen den Packages zu analysieren. Bei der Erläuterung der einzelnen Maße wird jeweils mit angegeben, welches Design-Ziel durch die jeweilige Metrik überprüft werden kann. Metriken von Robert C. Martin Für die Metriken von Robert C. Martin werden Packages analysiert und es werden die Kennzeichnungen eines Packages als stabil oder instabil und konkret oder abstrakt eingeführt. In einem Package in Java werden eine oder mehrere Klassen und Interfaces gebündelt. Jedes Package hat einen eindeutigen Namen. Im Namensraum des Packages sind Klassen eindeutig. Packages werden benutzt um in größeren Projekten Klassen zu gruppieren. Für die Metriken werden die Abhängigkeiten der Klassen eines Packages betrachtet. Es wird ein Package als stabil definiert, wenn es von Klassen anderer Packages benutzt wird. In Abbildung 3.9 ist das Package D stabil, es wird von Klassen der Packages B und C benutzt. Das Package D hat keine Abhängigkeiten, es ist unabhängig. Daher muss es nicht angepasst werden, wenn sich andere Packages verändern. Andere Packages sind abhängig vom stabilen Package. Im Gegensatz dazu ist Package C instabil gekennzeichnet. Es ist abhängig von den Packages D, E und F, denn Package C müsste auf Änderungen in einem der Packages D, E oder F angepasst werden. Ob ein Package als stabil oder instabil bezeichnet wird, ist somit unabhängig von der Reife oder der Qualität der Software. Vielmehr beschreibt die Stabilität, wie aufwendig es ist, Klassen innerhalb eines Packages anzupassen. Sind andere Packages abhängig von einem Package und müssen bei Änderungen angepasst werden, dann wird dieses Package als stabil gekennzeichnet, denn es erschwert die Änderungen. Sind keine anderen abhängigen Packages vorhanden, so wird dieses als instabil gekennzeichnet, da Änderungen an dem Package keine Anpassungen in anderen Packages erfordern. Ein stabiles Package sollte möglichst abstrakt sein. Warum? Nach dem Open- Closed-Principle, siehe Seite 11, soll ein Modul geschlossen sein für Änderungen und offen für Anpassungen. Diese Problematik wird durch Schnittstellen gelöst. Abhängige Module sollen die Schnittstellen benutzen. Diese Schnittstellen sind geschlossen für Änderungen. Anpassungen können in dem Package in konkreten Klassen dieser Schnittstelle implementiert werden. Nach dem Open-Closed-Principle sollten also abhängige Klassen anderer Packages möglichst abstrakte Klassen oder Schnittstellen benutzen. Somit sollten Packages abstrakter sein, je mehr sie von anderen Packages benutzt werden. Oder anders ausgedrückt, so stabil wie ein Package ist, so abstrakt

30 26 KAPITEL 3. GEGENSTAND DER ARBEIT Abbildung 3.9: Abhängigkeiten zwischen Packages soll es sein. Dieses wird in [Mar03] auch als stable-abstractions principle (SAP) bezeichnet. Ein Package gilt als abstrakt, wenn die dort definierten Klassen nicht direkt instanzierbar sind, es sich also um Interfaces oder abstrakte Klassen handelt. Das Package gilt als konkret, wenn es sich bei den Klassen in dem Package um konkrete Klassen handelt, die instanzierbar sind. Um für diese Begriffe Messwerte und Dimension zu benutzen, müssen die Begriffe afferent couplings, efferent couplings definiert werden: Afferent Couplings C a Die Anzahl der Klassen, die außerhalb des Packages von Klassen innerhalb des Packages abhängig sind. Efferent Couplings C e Die Anzahl der Klassen die innerhalb des Packages abhängig sind von Klassen anderer Packages. Instabilty I Wird berechnet aus der Formel: I = C e C a + C e Die Werte dieser Metrik in dem Intervall von 0 bis 1. Ein Package mit dem Wert I = 1 wird als maximal instabil benannt und ein Package mit dem Wert I = 0 ist maximal stabil. Um den Grad der Abstraktheit eines Packages zu benennen, müssen die Anzahl der konkreten und der abstrakten Klassen gezählt werden, dafür werden die Maße N c, N a und A definiert: Anzahl der Klassen N c Die Anzahl der Klassen innerhalb des Packages.

31 3.4. ERGEBNISSE DER VERMESSUNG 27 Anzahl der abstrakten Klassen N a Packages. Die Anzahl der abstrakten Klassen innerhalb des Abstractness A Wird berechnet aus der Formel A = N c N a Die Werte dieser Metrik liegen innerhalb des Intervalls von 0 bis 1. Ein Package mit dem Wert A = 1 hat nur abstrakte Klassen bzw. Schnittstellen. Dagegen hat ein Package mit dem Wert A = 0 gar keine abstrakten Klassen. Aus den beiden Maßen Abstractness und Instability lässt sich ein Diagramm erstellen. Auf der X-Achse wird der Grad der Abstraktion gekennzeichnet, auf der Y-Achse wird die Stabilität eingetragen. Jedes Package der Software lässt sich jetzt in diesem Diagramm eintragen. Die einzelnen Packages werden dabei in drei Gruppen unterteilt. Entweder sie befinden sich in der Hauptreihe zwischen den Punkten A = 0, I = 1 und A = 1, I = 0, darunter oder darüber. Der Bereich über dieser Reihe bis zum Punkt A = 0, I = 0 wird als zone of pain gekennzeichnet. Es deutet an, dass viele Klassen in dem Package nicht abstrakt sind und trotzdem viele andere Klassen von diesem Package abhängig. Das erschwert eine Anpassung dieses Packages, denn sie erfordert die Anpassung der Klassen in den abhängigen Packages. Der Bereich unter der Hauptlinie bis zum Punkt A = 1, I = 1 wird zone of uselessness genannt. Ein Package in diesem Bereich hat viele abstrakte Klassen und wird von wenig Klassen anderer Packages benutzt. Es sind sehr wahrscheinlich viele unnötige Schnittstellen und abstrakte Klassen in diesem Package. Für die Packages aus dem Beispiel sind die Werte in Abbildung 3.10 markiert. Der Abstand zu dieser Hauptreihe wird als Distance bezeichnet. Je größer der Abstand zu der Hauptreihe, desto mehr ist das Package entweder in der zone of pain oder in der zone of uselessness. Für die Berechnung der Distance gilt folgende Formel: D Distance Beschreibt den Abstand zur Hauptreihe D = A + I 1 2 D Normalized Distance Ist der normalisierte Abstand zur Hauptreihe. Die Werte befinden sich im Intervall von 0 bis 1. D = A + I 1 Für die Packages aus der Abbildung 3.9 sind die entsprechenden Werte für C a, C e, N c, N a, A, I und D in Tabelle 3.1 eingetragen. Betrachtet man aus der Tabelle 3.1 die Packages mit dem größten Abstand zur Hauptlinie findet man die Packages B mit D = 0, 75 und D mit D = 0, 5. Package B befindet sich in der zone of uselessness. Es hat sechs abstrakte Klassen von insgesamt acht und es gibt keine Klasse aus einem anderen Package das von B abhängt.

32 28 KAPITEL 3. GEGENSTAND DER ARBEIT abstractness 0.8 E C B 0.6 main sequence D A instability Abbildung 3.10: A-I-Diagramm Package C a C e N c N a A I D A B ,75 1 0,75 C ,8 0,4 0,2 D ,5 0,5 E ,8 0 0,2 Tabelle 3.1: Messwerte für das Beispiel

33 3.4. ERGEBNISSE DER VERMESSUNG 29 Package C a C e N c N a A I D domainvalue ,00 0,00 1,00 item.search ,00 0,15 0,85 util ,00 0,15 0,85 presentation ,03 0,22 0,75 service.persistence ,00 0,60 0,60 Tabelle 3.2: Messwerte für JCommSy sortiert Das deutet an, das unnötig viele abstrakte Klassen in B benutzt werden. Package D befindet sich in der zone of pain. Es hat vier Klassen und keine davon ist abstrakt. Es gibt aber zwei Klassen aus anderen Packages die von D abhängen. Das deutet an, das eine Änderung von D aufwendig wird, da mindestens die zwei abhängigen Klassen angepasst werden müssen. Messwerte aus dem JCommSy Das JCommSy wurde vor der Umstellung gemessen. Die Werte für das JCommSy befinden sich in Tabelle A-1 auf Seite 66. Bei den Werten fallen ein paar Packages durch eine höhere Distanz auf. In Tabelle 3.2 sind fünf Packages mit der höchsten Distanz absteigend sortiert aufgelistet. Das entsprechende Diagramm dazu ist in Abbildung 3.11 dargestellt. Anhand der Grafik und der Messwerte ist sofort zu erkennen, dass das Package service.persistence sich im Bereich der zone of uselessness befindet. Es hat nur abstrakte Klassen. Trotzdem wird es nicht von vielen Klassen anderer Packages benutzt. Die anderen Packages befinden sich in der zone of pain. Es muss nicht unbedingt ein schlechtes Zeichen sein, wenn sich ein Package in dieser Zone befindet. Ein typisches Beispiel sind Klassen mit Hilfsmethoden, die sich sehr wahrscheinlich niemals verändern werden, z.b. String-Utils. Falls es sich um solche Klassen handelt, kann man diese kennzeichnen als non-volatile, also als nicht flüchtig oder permanent. So gekennzeichnete Packages werden in dieser Metrik nicht mehr berücksichtigt. Typischerweise hat das Package mit den Fachwerten, hier domainvalues, einen schlechten Wert in der Distanz und ist in der zone of pain. Fachwerte sind häufig als konkrete Klassen implementiert, es gibt in diesen Packages also relativ wenig abstrakte Klassen. Es stellt sich die Frage, ob Fachwerte als non-volatile markiert werden können, weil sie von ihrer Natur aus unveränderlich sind. Eine andere Sicht ist es für Fachwerte nur noch Interfaces zu benutzen, und diese über statische Methoden oder Factories zu erzeugen. Die Definition eines Fachwertes wird sich wie die Anforderung eines Kunden an die Software auch verändern können. Desweiteren könnte man fordern Fachwerte nicht mehr universell im ganzen System einzusetzen, sondern spezielle Fachwerte nur für bestimmte Schichten oder Bereiche des Systems zu benutzen.

34 30 KAPITEL 3. GEGENSTAND DER ARBEIT abstractness service.persistence main sequence item.search,util domainvalue presentation instability Abbildung 3.11: A-I-Diagramm für ausgewählte Packages aus dem JCommSy Tests im JCommSy Die indirekte Abhängigkeit der Servlets und Commands zu den konkreten Services zeigt sich in den Tests als Hindernis. In den meisten Tests für Klassen die von Services abhängig sind, werden auch alle abhängigen Services mitbenutzt. Sie können nicht einfach ausgetauscht werden. Alle Tests im JCommSy benutzen daher implizit sämtliche abhängigen Objekte mit. Es handelt sich also nicht um Komponententests im eigentlichen Sinne. Es wird nicht nur das Verhalten einer einzelnen Komponente geprüft, sondern implizit auch das Verhalten der anderen abhängigen Objekte. Das bereitet allen Tests einen enormen Aufwand, einen zuverlässigen Zustand vor dem Test bereitzustellen. Es werden im JCommSy-Code in der Vorbereitung der Tests die abhängigen Services der zu testenden Klasse aufgerufen und versucht, diese in einen definierten Zustand zu bringen. Bei den eigentlichen Tests wird indirekt auch die Funktionalität der abhängigen Services mit getestet. Als Beispiel hierfür wird in Listing 3.4 die Methode setup aus dem Test MaterialServiceHibernate gezeigt, die vor jedem Test in diesem Testfall aufgerufen wird. Für jeden Test werden hier die beiden Services für Links und Materialen explizit gesetzt am ServiceConfigurator gesetzt. Durch diese Abhängigkeiten sind fast alle Tests sehr aufwändig in ihrer Beschreibung und in der Ausführung sehr langsam. Die komplette Testsuite mit ca. 900 Tests dauert in der Ausführung fast fünf Minuten. Viele der Tests initalisieren aufwendig die Service Registry, nur um Funktionen des getesteten Objektes zu prüfen. Diese In-

35 3.4. ERGEBNISSE DER VERMESSUNG 31 1 protected void setup() throws Exception { 2 setupjunitdatabaseservice(); 3 Persister.deleteAll(Material.class); // usw.. 4 _service = new MaterialServiceHibernate(); 5 ServiceConfigurator.setMaterialService(_service); 6 ServiceConfigurator.setLinkService(new C LinkServiceHibernate()); // usw. 7 } Listing 3.4: Ausschnitt aus dem Test MaterialServiceHibernate itialisierung kostet viel Zeit und ist für den eigentlichen Test nicht notwendig. Damit Entwickler Tests häufig ausführen, sollte die Ausführung der Tests möglichst schnell sein. An diesem Punkt gibt es somit Potential zur Verbesserung. Neben dem umständlichen Aufsetzen der Tests ist die Fehlersuche bei fehlschlagenden Tests ein Problem. Bei der Suche muss nicht nur die getestete Klasse untersucht werden, warum nicht das vom Test erwartete Ergebnis liefert. Auch die abhängigen Objekte und Services können einen Grund für das Fehlschlagen des Tests sein. Im folgenden beschreibe ich die Gründe, warum mit dieser Architektur das Testen erschwert ist: Verschleppen von Zuständen Reihenfolge der Ausführung Abhängigkeiten der Objekte unklar Die Architektur ermöglicht das Verschleppen von Zuständen, wenn ein Test einen ungewollten Zustand hinterlässt, z.b. in dem er einen Service über den Service Configurator ausgetauscht hat. Der folgende Test kann ggf. einen anderen Zustand erwarten und fehlschlagen. Die Tests können ungewollt abhängig werden von der Reihenfolge der Ausführung der Tests. Dass Tests Zustände verschleppen, liegt unter anderem daran, dass die Abhängigkeiten der Objekte unklar sind. Ein Test muss alle abhängigen Klassen der zu testenden Klasse kennen und eventuell austauschen. Direkte Abhängigkeiten zu anderen Services sind nur erkennbar über den Aufruf am Service Locator. Indirekte Abhängigkeiten sind schon viel schwerer zu erkennen, hierfür muss in den abhängigen Services nach Aufrufen am Service Locator gesucht werden. Das Testen wird im JCommSy weiterhin dadurch erschwert, das drei unterschiedliche aber zentrale Datenbanken mit unterschiedlichem Inhalt für die Tests benutzt werden. Diese Datenbanken werden nicht an einem zentralen Ort konfiguriert. Zudem ist bei ihnen auf den ersten Blick auch nicht ersichtlich, mit welchen Daten für welchen Zwick sie gefüllt sind. Auf Grund dieser komplizierten Randbedingungen für Tests werden für viele Klassen im JCommSy gar keine Komponententests geschrieben. Das ist eindeutig

36 32 KAPITEL 3. GEGENSTAND DER ARBEIT ein Nachteil, denn Tests sind ein Voraussetzung für die Qualität der Software, wie schon in Kapitel 2.1 beschrieben. Das Ziel dieser Arbeit sollte also die Vereinfachung des Erstellens von Komponententests beinhalten. 3.5 Zusammenfassung In diesem Kapitel wurde das JCommSy vorgestellt. Dabei wurde der fachliche Hintergrund gezeigt. Es wurde beschrieben, wer das System benutzt und welche Aufgaben damit erledigt werden. Die Migration des PHP-Systems CommSy zum Javabasierten System JCommSy wurde gezeigt. Im JCommSy wird eine typische MVC2- Architektur benutzt. Der vorhandene Code wurde an Beispielen gezeigt. Das JCommSy-System wurde vor der Umstellung vermessen. Für die Vermessungen wurden die Metriken von Robert C. Martin über stabile und abstrakte Packages verwandt. Die wichtigsten Ergebnisse sind vorgestellt worden. Die Muster Singleton und Service Locator wurden vorgestellt. Mit diesen Mustern wurde der Zugriff im JCommSy auf Services veranschaulicht. Hierbei wurden besonders die Abhängigkeiten der Services durch das Singleton-Muster betrachtet. Die Schwierigkeiten, die aus diesen Abhängigkeiten für die Tests und damit für die Qualität der Software entstehen, wurden erläutert. Der Kontrollfluss und insbesondere die Einstiegspunkte wurden gezeigt, denn sie sind für die Analyse der Objekterzeugung und die Planung einer Umstellung von Bedeutung.

37 Kapitel 4 Lösungsansätze Neben den notwendigen Grundlagen wurde der Gegenstand der Arbeit, das JCommSy, beschrieben. Der Code wurde vermessen und die Tests wurden vorgestellt. Dabei wurde gezeigt, dass auch indirekte Abhängigkeiten von Klienten zu Anbietern diese miteinander koppeln und sich negativ auf die Testisolation und Testbarkeit auswirken. Im Rahmen des JCommSy sind konkret die Aufrufe an der Service Registry aufgefallen. Nur diese Aufrufe zeigen, welche Services von einer Klasse benutzt werden. Diese Abhängigkeiten zu Anbietern sind nicht sofort im Klienten ersichtlich, da sie im Sourcecode der Klasse verteilt sind. Diese Services sind nur mit erhöhtem Aufwand für Tests durch andere Implementierungen zu ersetzen. Bei Änderungen und Erweiterungen, z.b. durch geänderte fachliche Anforderungen, können diese Services auch nur mit größerem Aufwand durch eine andere Implementierung ersetzt werden. Dieses Kapitel wird Lösungen zu den beschriebenen Problematiken vorstellen. Zuerst wird eine Lösung vorgestellt, wie Abhängigkeiten explizit gemacht werden können. Der zweite Abschnitt zeigt eine mächtigere Lösung, wie Abhängigkeiten mit Dependency Injection ausdrücklich dargestellt und verwaltet werden können. Abschließend wird beschrieben, warum Dependency Injection die Testbarkeit im JCommSy vereinfachen kann. 4.1 Explizite Abhängigkeiten Bei der Betrachtung des Gegenstandes ist aufgefallen, das Abhängigkeiten zu anderen Objekten, insbesondere Services, im JCommSy nicht explizit gemacht sind. Um abhängige Services zu finden, reicht die Suche in den Import-Statements nicht aus. Die Abhängigkeiten sind nur innerhalb der Klasse zu finden - durch die Suche nach einem Aufruf des Service Locators. In allen vorgestellten Lösungen in Kapitel 3.3 hat der Klient den Anbieter selber erzeugt oder versucht, ihn über ein Singleton oder einen Service Locator ausfindig zu machen. In beiden Fällen ist der Klient aktiv, um den Service zu lokalisieren oder zu erzeugen, um ihn anschließend benutzen zu können. Genau dort setzt die erste Lösung an. Der Klient kümmert sich nicht selber um die Referenz zum benötigten 33

38 34 KAPITEL 4. LÖSUNGSANSÄTZE 1 public class A { 2 private A a; 3 private B b; 4 public A (B b, C c) { 5 this.a = a; 6 this.b = b; 7 } 8 // fachliche Methoden usw. Abbildung 4.1: Beispiel für abhängige Klassen Listing 4.1: Klasse A mit direkten Abhängigkeiten im Konstruktor Anbieter, sie kann ihm gesetzt werden. Der Klient würde eine Schnittstelle anbieten, an der der Anbieter gesetzt werden kann (und muss). Das bedeutet, dass der Klient nicht mehr selber versucht den Anbieter zu lokalisieren, sondern eine andere Instanz diese Aufgabe erledigen muss. Der Klient selber hat nur eine Referenz über eine Exemplarvariable auf den Anbieter. Diese Referenz benutzt der Klient für Aufrufe am Anbieter. Um die Lösung zu verdeutlichen, wird als Beispiel das Klassendiagramm in Abbildung 4.1 benutzt. Hier wird gezeigt das die Klasse A direkt von der Klasse B und C abhängt. Indirekt gibt es eine Abhängigkeitsbeziehung von A auch zu den Klassen D, E und F. In dem Beispiel würde die Klasse A z.b. eine Methode anbieten, um B und um C zu setzen. Hierfür bieten sich zwei Möglichkeiten an. Entweder werden die abhängigen Anbieter über Methoden gesetzt, z.b: public setservices(b b, C c) Die Objekte können auch im Konstruktor übergeben werden, dann würde die Klasse im Konstruktor als Parameter B und C haben, das ist beispielhaft in Listing 4.1 dargestellt. Durch diese Methoden werden die Abhängigkeiten zu den benötigten Anbietern sichtbar. Um abhängige Services zu erkennen, sind nicht mehr die Aufrufe an einem Service Locator oder deren direkte Erzeugung zu suchen. Schon an den Signaturen der Methoden einer Klasse lässt sich erkennen, welche Objekte benötigt werden.

39 4.1. EXPLIZITE ABHÄNGIGKEITEN 35 Abbildung 4.2: Explizite Abhängigkeiten am Beispiel des Bücherservices Um das gesamte System zu erzeugen, hat die Klasse B dann auch eine Methode um D und E zu setzen usw. Die zentrale Konfiguration muss dann die benötigten Objekte in umgekehrter Reihenfolge ihrer Abhängigkeiten erzeugen. Zuerst wird es die Objekte erzeugen die keine weiteren Abhängigkeiten besitzen. In diesem Fall sind das D, E und F. Anschließend kann diese Konfiguration dann B und C erzeugen und deren Abhängigkjeiten setzen. Zum Schluss könnte A erzeugt werden und die benötigten B und C gesetzt bekommen. Für die Zusammenstellung der Objekte wird ein neues Objekt benötigt. Seine Aufgabe ist genau diese Zusammenstellung. In [Fow04] wird diese Klasse daher auch Assembler genannt. Häufig findet sich auch die Bezeichnung Container für solche Objekte. Die Abbildung 4.2 zeigt die Lösung angewandt auf das in den vorigen Kapiteln benutzte Beispiel mit dem Bücherservice. An diesem Bild ist durch die Pfeile für Abhängigkeitsbeziehungen zu erkennen, dass keine indirekte Verbindung mehr zwischen dem Bücherservice und der konkreten Implementierung des Bücherrepositories besteht. Bei der Zusammenstellung der Klassen ist zu beachten, ob dem Objekt nur direkte Abhängigkeiten gesetzt werden oder ob dem Objekt auch alle indirekten Abhängigkeiten übergeben werden müssen. Es ist einfacher den Objekten nur die direkten Abhängigkeiten zu setzen. In dem Beispiel aus Abbildung 4.1 muss dem Objekt der Klasse A nur ein Exemplar von B und eines von C gesetzt werden. Das Objekt der Klasse A benötigt in dem Fall nicht die indirekten Abhängigkeiten D, E und F. Entsprechend muss vorher dem Exemplar von B jeweils ein Exemplar von D und E übergeben werden usw. Nur die expliziten Abhängigkeiten zu verwalten ist einfacher als auch die im-

40 36 KAPITEL 4. LÖSUNGSANSÄTZE pliziten Abhängigkeiten den Objekten übergeben zu müssen. Die Schnittstelle einer Klasse würde sich erweitern um Methoden oder Parameter für die Exemplare der Klassen, die auch indirekt abhängig sind. Im Beispiel müsste dann die Klasse A alle Abhängigkeiten in der Schnittstelle aufweisen, also B, C, D, E und F. Diese indirekten Abhängigkeiten würde das Exemplar A nicht selber benutzen, sondern nur weiterschleifen und sie den Objekten B und C übergeben. Es kann notwendig sein, dass bei einer Umstellung eines Systems nicht alle Klassen sofort angepasst werden können. Es kann auch sein, dass aus technischen oder organisatorischen Gründen nicht alle Klassen durch einen Assembler bzw. Container verwaltet werden können. Dann wäre man gezwungen, auch indirekte Abhängigkeiten zu setzen, diese würden man durch den Code weiterschleifen. Eine weiteres Problem beim Setzen der indirekten Abhängigkeiten ist aus dem Bild 4.1 ersichtlich. Die Klassen B und C sind beide abhängig von E. In diesem Fall muss geklärt sein, ob B und C das gleiche Exemplar von E gesetzt bekommen. Die Klasse E hat noch eine Abhängigkeit zu G. Diese wird es zweimal gesetzt bekommen, von B und von E. Für diesen Fall muss geregelt sein, nach welcher Semantik dies passiert, also ob G bei E zweimal gesetzt wird oder ob G nur gesetzt wird, wenn E noch kein G hat. Es erweitert nicht nur die Schnittstelle der Klassen, sondern kompliziert zudem noch die Semantik der Anwendung, wenn explizite Abhängigkeiten übergeben werden müssen. Explizite Abhängigkeiten und Tests Wie schon in Abbildung 4.2 gezeigt, besteht keine direkte Verbindung mehr zwischen dem Klienten und dem Anbieter. Das Listing 4.1 deutet an, wieviel einfacher es ist diese Klasse zu testen. Der Test muss die abhängigen Exemplare B und C im Konstruktor übergeben, um ein Exemplar der Klasse A zu erzeugen. Dadurch sind nicht nur die Abhängigkeiten sofort ersichtlich, sondern der Test kann diese Abhängigkeiten auch durch eigene Implementierungen für die Testisolation ersetzen. Programmatisch ist es möglich diese Konfiguration und Zusammenstellung der benötigten Objekte zu verwalten. Ein Problem wird von dieser Lösung noch nicht adressiert. In dieser Lösung gibt es von einer Klasse, die durch diese Lösung verwaltet wird, immer nur ein Exemplar. Das Verhalten entspricht dem eines Singletons. Es wurde im vorigen Kapitel festgestellt, dass manche der Objekte im JCommSy, insbesondere die Commands, abhängig vom verwendeten Kontext neu erzeugt werden müssen. Desweitern ist die Auflösung der Abhängigkeiten nicht trivial, zuerst muss der Assembler alle Objekte instanzieren, die keine Abhängigkeiten haben, anschließend die Objekte, die von diesen abhängen usw. Wie diese Probleme gelöst werden können, zeigt der nächste Abschnitt über Dependency Injection, der eine erweiterte Form dieser Zusammenstellung und Konfiguration anbietet.

41 4.2. DEPENDENCY INJECTION Dependency Injection Das Thema Dependency Injection ist unterteilt in Erzeugung und Initialisierung, Konfiguration und Benutzung. Die Erzeugung und Initialisierung der Objekte beschreibt wie ein Dependency Injection Framework Abhängigkeiten verwaltet und diese den Objekten übergibt. Die Konfiguration gibt die verwalteten Objekte und deren Abhängigkeiten an. Die Benutzung beschreibt, wie die verwalteten Objekte von einem Dependency Injection Framework bezogen werden. Häufig werden die Begriffe Dependency Injection (DI) und Inversion of Control (IoC) in einem Zusammenhang benutzt, doch beschreiben beide unterschiedliche Prinzipien. Diese Unterscheidung soll zuerst geklärt werden, sie ist wichtig für das Verständnis von Dependency Injection. Inversion of Control Das Prinzip Inversion of Control beschreibt eine Änderung des Kontrollflusses. Es ist der wesentliche Unterschied zwischen einem Framwork und einer Bibliothek. Bei einer Bibliothek kommt der Programmfluss aus dem eigenen Code und ruft an der Bibiliothek Funktionen auf, erzeugt Objekte die von der Bibliothek angeboten werden und schickt diesen Objekten Nachrichten. Die Bibliothek wird vom Programm benutzt und der Kontrollfluss kommt vom eigenen Programm. Anders ist es bei einem Framework. Dort kommt der Kontrollfluss vom Framework. Das Framework ruft eine überschriebene Funktionen auf, der Kontrollfluss ist somit umgekehrt. Ein typisches Beispiel sind GUI-Frameworks. Dort wird z.b. für einen Button ein Listener geschrieben und als Callback beim Framework registriert. Der Kontrollfluss kommt vom Framework, dieses ruft den Listener auf, wenn ein Benutzer auf diesen Button drückt. Zusammen mit dem Ausspruch Don t call us, we ll call you! wird das Prinzip Inversion of Control auch Hollywood Principle genannt. Erzeugung und Initialisierung von Objekten Das Prinzip der Inversion of Control (IoC) findet Anwendung bei Dependency Injection. Es bezieht sich auf die Erzeugung und Initialisierung von Objekten. Die Verantwortung Objekte zu erzeugen und zu initialisieren wird somit dem Dependency Injection Framework übergeben. Dependency Injection Frameworks werden in drei Kategegorien unterteilt. Sie unterscheiden sich jeweils wie das Framework die abhängigen Objekte dem Klienten setzt. Sie werden in [Fow04] entweder als Setter Injection, Interface Injection und Constructor Injection, beschrieben. Interface Injection Dependency Injection Frameworks dieser Art werden auch als Typ 1 IoC umschrieben. Hier muss ein Klient ein Interface implementieren, wenn es ein abhängiges Objekt gesetzt bekommen soll. In dem Listing 4.2 wird dies anhand des Bücherservices gezeigt, der ein Repository gesetzt bekommt. Dafür implementiert der Bücherservice das Interface InjectRepositoryC. Diese Schnittstelle definiert nur die Methode: void injectrepository(buecherrepository r)

42 38 KAPITEL 4. LÖSUNGSANSÄTZE 1 public interface InjectRepository { 2 public void injectrepository(buecherrepository r); 3 } 4 5 public class BuecherService implements InjectRepository { 6 private BuecherRepository repository; 7 8 public void injectrepository(buecherrepository r) { 9 this.repository = r; 10 } //.. Listing 4.2: Beispiel für Interface Injection 1 public class BuecherService { 2 3 private BuecherRepository repository; 4 5 public void setrepository(buecherrepository r) { 6 this.repository = r; 7 } //.. Listing 4.3: Beispiel für Setter Injection Mit dieser Methode wird vom Framework das Bücherrepository dem Bücherservice gesetzt. Ein Dependency Injection Framework kann anhand der Schnittstelle leicht über Meta-Objektprotokolle wie Reflection erkennen, welche verwalteteten Objekte ein Bücherrepository gesetzt bekommen müssen. Jedes vom Framework verwaltetete Objekt, das diese Schnittstelle implementiert, wird ein Repository gesetzt bekommen. Setter Injection Wird auch als Typ 2 IoC umschrieben. Hier muss ein Klient kein Interface implementieren, dafür aber eine Methode anbieten zum Setzen des benötigten Objekts. Solche Methoden werden auch Setter gennant. In Listing 4.3 ist der Bücherservice mit einer Setter-Methode für ein Repository abgebildet. Constructor Injection Wenn sämtliche Abhängigkeiten einer Klasse über den Konstruktor übergeben werden, spricht man von Constructor Injection, oder auch Typ 3 IoC. Bei dieser Art der Zusammenstellung muss ein verwaltetes Objekt in der Signatur des Konstruktors alle Abhängigkeiten als Parameter angeben. Ein verwaltetes Objekt kann demnach nur instantiiert werden, wenn alle Abhängigkeiten bei der Erzeugung des Objekts übergeben werden. Das Listing 4.4 zeigt den Bücherservice mit einem Konstruktor der das abhängige Repository als Parameter beinhaltet.

43 4.2. DEPENDENCY INJECTION 39 1 class BuecherService { 2 3 private final BuecherRepository repository; 4 5 public BuecherService (BuecherRepository r) { 6 this.repository = r; 7 } //.. Listing 4.4: Beispiel Constructor Injection Die Methode des Interface Injections, bzw. Typ 1 IoC, hat den Vorteil, dass schon anhand des Typs der Klasse die Abhängigkeiten erkannt werden können. Die entsprechenden Schnittstellen zum Setzen der Abhängigkeiten markieren diesen Typ sehr eindeutig mit seinen Abhängigkeiten. Der Nachteil dieser Methode liegt genau in diesen Schnittstellen. Für jede mögliche Abhängigkeit muss ein zusätzliches Interface geschrieben werden. Zudem wird die Schnittstelle der fachlichen Klasse erweitert um technische Schnittstellen, denn diese Schnittstellen werden nur für die Erzeugung des Objektes benötigt. Aus diesen Gründen bieten aktuelle und die hier vorgestellten Dependency Injection Frameworks die Methode die Interface Injection nicht an. Die Methode ist in den ersten Dependency Injection Frameworks für Java benutzt worden, da auch schon mit frühen Versionen von Java über das Metaobjektprotokoll und Reflection die Schnittstellen einer Klasse leicht erkannt werden konnten. Die Erzeugung der Objekte mit Setter Injection, bzw. Typ 2 IoC, benötigt kein zusätzliches Interface. Dem Framework muss nur über die Konfiguration oder per Konventionen die Methode zum Setzen der Abhängigkeiten bekannt gemacht werden. Ein weiterer Vorteil von Setter Injection im Vergleich zu Constructor Injection ist es, das Objekt ohne seine Abhängigkeiten erzeugen zu können. Wenn ein Objekt sehr viele und aufwendig zu erzeugende Abhängigkeiten besitzt, kann dadurch das Testen erleichtert werden. Ein Test braucht nur die Objekte zu setzen, die von dem Objekt im entsprechenden Test aufgerufen werden. Bei Setter Injection ist es schwerer an der Klasse (bzw. ihrer Schnittstelle) ihre Abhängigkeiten zu erkennen. Um diese ausfindig zu machen, müssen alle Setter-Methoden betrachtet werden. Beim Zugriff innerhalb der Klasse auf die Abhängigkeiten ist nicht eindeutig, ob das abhängige Objekt auch wirklich schon gesetzt wurden. Die Referenz auf das abhängige Objekt kann eventuell noch null sein, wenn sie z.b. nicht konfiguriert wurde und ein Zugriff würde dann einen Fehler verursachen. Ein weiterer Nachteil liegt darin, dass über die Setter-Methode auch nach der Erzeugung und Initialisierung das abhängige Objekt fälschlicherweise überschrieben werden kann. Die Setter-Methode wird in dem Fall nur für das Dependency Injection Framework an der Klasse angeboten und erweitert somit deren Schnittstelle ohne fachliche Motivierung. Bei Constructor Injection (bzw. Typ 3 IoC) müssen alle abhängigen Objekte als Parameter im Konstruktor der Klasse übergeben werden. Die Abhängigkeiten der Klasse sind mit einem Blick sofort am Konstruktor zu erkennenen. Die übergebe-

44 40 KAPITEL 4. LÖSUNGSANSÄTZE nen Objekte können sofort an Klassenvariablen gebunden werden, somit kann jede Methode davon ausgehen, dass sämtliche Abhängigkeiten gesetzt wurden. Es muss nicht wie bei Setter Injection im Zweifel geprüft werden, ob die Referenz wirklich gesetzt ist. Die Referenz kann mit dem Stichwort final als unveränderlich markiert werden, da sie im Konstruktor gesetzt wird. Diese Abhängigkeit kann dann nicht mehr aus Versehen überschrieben werden. Diese Methode ist nachteilig, wenn eine Klasse sehr viele Abhängigkeiten hat. Dann wird der Konstruktor dieser Klasse schnell unübersichtlich 1. Um ein Objekt dieser Klasse für einen Tests zu erzeugen muss jede Abhängigkeit mit übergeben werden, auch wenn diese durch den Test nicht benutzt wird. Scopes - Gültigkeitsbereiche für verwaltete Objekte Die Aufgabe von Dependency Injection Frameworks ist die Erzeugung und Konfiguration von Objekten. Hier liegt einer der großen Vorteil von Dependency Injection gegenüber der in Abschnitt 4.1 beschriebenen Lösung rein programmatisch die Objekte zu konfigurieren. Für die Erzeugung können Dependency Injection Frameworks konfiguriert werden, ob immer dasselbe Objekt oder bei jeder Anfrage ein neues Objekt geliefert werden soll. Wird jedesmal dasselbe Objekt vom Framework geliefert, entspricht das dem Verhalten eines Singletons. Wenn bei jeder Anfrage ein neues Objekt geliefert werden soll, dann ist das Verhalten ähnlich einer Erzeugung des Objekts mit new. Zwischen beiden Varianten gibt es bei manchen Frameworks noch Abstufungen. Dort wird abhängig vom Kontext jeweils ein neues Objekt geliefert, ein verwaltetes Objekt ist dann nur innerhalb eines Bereiches gültig. Als Beispiel kann man sich vorstellen, das ein Objekt nur innerhalb eines HTTP- Requests gültig sein soll. Innerhalb des selben Requests soll immer wieder das gleiche Objekt vom Container geliefert werden. Innerhalb eines anderen Requests ist ein anderes Objekt gültig. In diesem Beispiel ist die Anfrage, bzw. der HTTP-Request, der entscheidende Kontext. Dieser Kontext wird im Zusammenhang mit Dependency Injection auch Scope genannt. Dieser Kontext beschreibt den Gültigkeitsbereich für ein Objekt. Ein weiterer möglicher Gültigkeitsbereich, bzw. Scope für Webanwendungen ist z.b. die aktuelle Session. Die Gültigkeitsbereiche von Scopes sind unterschiedlich groß und schließen zum Teil auch andere Scopes mit ein. Die Benutzung von Scopes führt zu Einschränkungen. Objekte dürfen abhängig sein von Objekten mit dem gleichen oder einem größeren Scope. So darf ein Objekt, das im Kontext einer Session erzeugt wird, abhängig sein von Objekten mit Singleton-Verhalten oder anderen Objekten, die mit dem Scope Session konfiguriert wurden. Das Objekt mit dem Scope Session darf nicht abhängig sein von einem Objekt mit einem kleineren Scope, z.b. einem Objekt mit Request- Scope. 1 Nach meiner Meinung ist das kein Nachteil. Es ist nur ein Zeichen das die Klasse zu viele Abhängigkeiten hat und durch ein Refactoring aufgeteilt werden muss!

45 4.2. DEPENDENCY INJECTION 41 Konfiguration und Benutzung Bei Dependency Injection wird unterschieden zwischen der Konfiguration und der Benutzung. In diesem Abschnitt werden beide Begriff geklärt und abschließend gezeigt, warum diese Trennung die Entwicklung von Software erleichtert. Dependency Injection baut ein Netzwerk von verwalteteten Klassen auf. Die Konfiguration gibt an welche Klassen verwaltet werden sollen und wie das Framework Abhängigkeiten auflöst. Mit der Benutzung eines Dependency Injection Frameworks durch eine Anwendung ist der Zugriff auf die verwalteten Objekte gemeint. Bei der Konfiguration wird dem Dependency Injection Framework angegeben, welche Klassen verwaltet werden sollen. In der Konfiguration werden abhängige Objekte dieses Netzwerks von Objekten einander zugewiesen. Damit Objekte verwaltet werden, müssen sie dem Framework bekannt gemacht werden. Hierfür gibt es die folgenden Möglichkeiten der Konfiguration. Für konkrete Konfigurationen zeigt die spätere Vorstellung der einzelnen Frameworks Beispiele. Die Objekte werden anhand eines Typs registriert, den sie implementieren. So kann man z.b. die konkrete Implementierung des Bücherrepositories anhand der abstrakten Schnittstelle BuecherRepository registrieren. Objekte, die ein Bücherrepository benötigen, kennen nur diese Schnittstelle. Sie werden so konfiguriert, dass sie das Objekt zugewiesen bekommen, das unter dieser Schnittstelle registriert wird. Als Alternative können verwaltete Objekte unter einem symbolischen Namen registriert werden. Auch hier muss angegeben werden, welche Abhängigkeiten das angegebene Objekt benötigt. Hierfür werden die in der Konfiguration angegebenen Namen benutzt. Der Vorteil einer textuellen Konfiguration liegt darin, dass für eine Schnittstelle mehrere unterschiedliche Objekte registriert werden können. Unabhängig ob die Objekte anhand eines Typs oder textuellen Namens verwaltet werden, muss dem Framework zusätzlich angegeben werden, ob das Objekt per Setter Injection oder mit Constructor Injection erzeugt werden soll. Desweiteren muss angegeben werden, ob ein Objekt nur einmal erzeugt werden soll oder nur innerhalb eines bestimmten Kontexts wiederverwendet werden soll und ansonsten immer wieder neu erzeugt wird. Dependency Injection Frameworks unterscheiden auch noch in der Art wie diese Konfiguration geschrieben wird. Auch hier gibt es zwei Ansätze: Die programmatische Konfiguration ist die einfachste Möglichkeit. Hier wird mit Aufrufen an einer Klasse die Konfigration der zu verwalteten Objekte angeben. Der Vorteil dieser Konfiguration ist die Typsicherheit. Es können in diesem Fall nur Klassen registriert werden, die auch im Projekt wirklich vorhanden sind. Werden Klassen registriert, die nicht vorhanden sind, beschwert sich der Compiler.

46 42 KAPITEL 4. LÖSUNGSANSÄTZE 1 // Konfiguration 2 MutablePicoContainer pico = new DefaultPicoContainer(); 3 pico.registercomponentimplementation(buecherservice.class)c ; 4 pico.registercomponentimplementation(c RdbmsBuecherRepository.class); 5 6 //... die Benutzung an anderer Stelle 7 BuecherService service = (BuecherService) pico.c getcomponentinstance(buecherservice.class); 8 // Aufrufe am BuecherService usw... Listing 4.5: Beispiel für die Konfiguration und Benutzung mit PicoContainer Die alternative Konfiguration erfolgt in einer Text-Datei. Das Format dieser Datei kann z.b. XML, oder das in Java typische Property-Format sein. Hier werden die Objekte angegeben, die vom Framework zu erzeugen sind, welche Namen oder Typen sie implementieren und welche Abhängigkeiten sie besitzen. Die Konfiguration ist immer der erste Schritt, wenn Dependency Injection benutzt wird. Die Konfiguration erfolgt meist nur einmal zur Startzeit der Anwendung. Um anschließend auf die konfigurierten Objektnetze zuzugreifen, muss ein Dependency Injection Framework eine Methode anbieten, um verwaltete Objekte benutzen zu können. Die Frameworks bieten je nach Konfiguration eine Methode an, um anhand eines angefragten Namens oder Typs ein Objekt mit seinen Abhängigkeiten zu liefern. Die wichtigsten Konzepte von Dependency Injection sind erklärt worden. Der nächste Abschnitt wird die Ausgestaltung dieser Konzepte anhand konkreter Frameworks zeigen. 4.3 Dependency Injection Frameworks In diesem Abschnitt werden die gängigsten Frameworks für Dependency Injection im Java-Umfeld kurz beschrieben, PicoContainer und das Spring-Framework. Aus historischen Gründen wird auch Apache Avalon vorgestellt. Apache Avalon Apache Avalon ist das erste DI-Framework im Java-Umfeld gewesen. Das Framework wurde geschrieben als Grundlage und Komponentenmodell für das Apache Cocoon-System. Es ist mittlerweil eingestellt worden, siehe [Ava04]. Es wird hier nur erwähnt da es das erste Framework dieser Art ist und das einzige das Typ 1 IoC anbietet.

47 4.3. DEPENDENCY INJECTION FRAMEWORKS 43 PicoContainer PicoContainer ist ein Opensource-Framework, siehe [Pic06]. Das Framework wird unter der BSD-Lizenz bereitgestellt. Die Nutzung ist somit kostenlos und verpflichtet nicht den benutzenden Code auch unter eine Opensource-Lizenz zu stellen. Das Framework bietet eine einfache Lösung für Dependency Injection an. Für die Erzeugung wird Constructor Injection benutzt. Die Konfiguration des Containers erfolgt programmatisch. Das Beispiel mit PicoContainer in Listing 4.5 zeigt eine einfache Konfiguration und die Benutzung eines Objekts mit Bücherservice und Bücherrepository. Das Beispiel geht davon aus, das der Bücherservice wie in Listing 4.4 in seinem Konstruktor einen Parameter für das benötigte Repository anbietet. Beide Klassen werden in Zeile 3 und 4 mit ihrem Typ, dem Class-Objekt, beim Container registriert. Später in Zeile 7 wird der Container nach einem Bücherservice gefragt. Der Container liefert einen Bücherservice der mit dem angegebenen Repository konfiguriert ist. PicoContainer ist ein Framework ausschließlich für Dependency Injection. Der Vorteil von PiocoContainer ist die Einfacheit des Frameworks, es wird keine zusätzliche und eventuell nicht benötigte Funktionalität angeboten. PicoContainer bietet nur Constructor Injection an. Die verwalteteten Objekte verhalten sich wie Singletons, sie werden nur ein einziges mal erzeugt. Neben dem Singleton-Scope werden keine weiteren Scopes vom Framework angeboten, auch über eigene Erweitungen ist es nicht möglich, neue Scopes zu definieren. Spring-Framework Das Spring-Framework, siehe [Spr07a], ist auch ein Opensource-Projekt. Mit der Apache Lizenz kann das Framework ohne Kosten benutzt werden, sie zwingt auch nicht den benutzenden Code als Opensource zu deklarieren. Das Framework ist entstanden aus dem Bedürfnis, die Entwicklung von J2EE-Anwendungen zu vereinfachen. Das Framework integriert viele existierende Technologien anstatt eigene Lösungen anzubieten. Das Framework ist unabhängig von einem eingesetzten Application Server. Die Entwicklung mit Spring wird in[jha + 05] als minimal invasiv beschrieben, denn der Anwendungscode ist (meist) nicht abhängig von Spring APIs. Das Framework ist modular aus unabhängig einsetzbaren Paketen aufgebaut. In der folgenden Liste sind die wichtigsten Pakete aus dem Spring Framework beschrieben: Spring Core Das Core-Paket beitet die Basisinfrastruktur mit Unterstützung für Beans und Dependency Injection. Spring AOP Mit dem AOP-Paket 2 werden mittels Aspekten deklarative Dienste untertützt. Die Aspekte können u.a. bei der Verwaltung von Transaktionen, der Behandlung von Exceptions, für Zugriffs- oder Architekturkontrollen benutzt werden. 2 AOP = Aspect-Oriented Programming

48 44 KAPITEL 4. LÖSUNGSANSÄTZE Spring DAO Das DAO-Paket 3 bietet Abstraktionen für den Zugriff auf Datenbanken. Hier werden viele Hilfsmethoden und abstrakte Klassen für den Umgang mit JDBC angeboten. Spring ORM Für die Unterstützung von Persistenztechnologien wie Hibernate, Java Data Objects (JDO) oder Java Persistence Architecture (JPA) bietet das Paket Spring ORM 4 Techniken zur Integration. Spring Transaction Für die Verwaltung von Transaktionen, unabhängig ob von einer Datenbank, einem Transaktionsserver oder einem Application Server, bietet Spring eine Abstraktion mit dem Paket Spring Transaction. Spring Web Mit dem Paket Spring Web bietet Spring eine Anbindung an bestehende Frontend-Technologien (Struts, JSF, usw.). Spring MVC Das Spring-Framework bietet ein eigenes Web-Framework im Paket Spring MVC an. Neben dem Framework gibt es mehrere Subprojekte wie z.b. Web Flow, Web Services, Security (Acegi Security), LDAP, Rich Client, Extensions (Modules), IDE for Eclipse, BeanDoc, OSGi, JavaConfig,.NET und Batch. Die Möglichkeiten mit Spring neue Technologien mit wenig Integrationsaufwand einzubinden sind groß. Dabei ist man nicht gezwungen, eines dieser Pakte oder Projekte zu benutzen. Die Konfiguration kann bei Spring mit XML oder programmatisch erfolgen, wobei die programmatische Konfiguration sehr umständlich ist. In Listing 4.6 wird gezeigt wie das Beispiel mit dem Bücherservice mit Spring in XML konfiguriert wird. Die Konfiguration geht davon aus, dass ein Setter an der Klasse des Bücherservices existiert, wie in Listing 4.3 gezeigt. Die einzelnen Objekte werden bei Spring Beans genannt. Diese Beans bekommen in der Konfiguration einen symbolischen Namen anhand dessen sie referenziert werden. Das Bücherrepository wird hier buecher- Repository genannt. Dieser Name wird bei der Benutzung verwendet, um eine Referenz auf das verwaltete Objekt zu bekommen. Vorher muss der Container erzeugt werden wie in Listing 4.7 in Zeile 1, in der zweiten Zeile wird an dem Container nach dem Bücherrepository gefragt. Bei Spring wird der Container, der das Objektnetz verwaltet, Application Context oder Bean Factory genannt. Das Spring-Framework bietet eine Unterstützung für Scopes an. Es gibt zwei Scope-Typen, die ohne Erweiterungen benutzt werden können. Der Standard ist das Singleton-Verhalten, hierfür kann die Bean auch bei der Konfiguration explizit mit dem Scope singleton markiert werden. Wird eine Klasse bei der Konfiguration mit dem Scope prototype angemeldet, dann erzeugt jede Anfrage nach einem Objekt an dem Container ein neues Objekt. Spring hat auch noch die Scopes session und request. Für diese gilt jeweils der Gültigkeitsbereich einer Session oder einer HTTP-Anfrage. Des weitern können für Spring weitere Scopes implementiert werden, das Framework hat eine eigene API für diesen Zweck. 3 DAO = Data Access Objects 4 ORM = Objekt-Relationales Mapping

49 4.4. VEREINFACHUNG DER TESTS DURCH MOCK-OBJEKTE 45 1 <?xml version="1.0" encoding="utf-8"?> 2 3 <beans> 4 <bean id="buecherrepository" class="buecherrepository" /> 5 <bean id="buecherservice" class="buecherservice"> 6 <property name="repository" ref="buecherrepository" /> 7 </bean> 8 </beans> Listing 4.6: Beispiel Konfiguration Spring Framework 1 ApplicationContext ctx = new ClassPathXmlApplicationContext(C "context.xml"); 2 BuecherService service = (buecherservice) ctx.getbean("c buecherservice"); 3 // Aufrufe am BuecherService usw... Listing 4.7: Beispiel Spring Framework 4.4 Vereinfachung der Tests durch Mock-Objekte Bisher wurde gezeigt wie die Abhängigkeiten für die Objekte explizit gemacht werden können, indem sie an der Signatur eines Objektes erkennbar sind. Die Abhängigkeiten lassen sich durch die Setter oder besser anhand des Konstruktors ablesen. Die Konfiguration und Erzeugung der Objekte lässt sich mit einem Dependency Injection Framework wie Spring oder PicoContainer erledigen. Es ist noch die Frage zu klären, wie sich die Tests vereinfachen lassen. Hierfür werden in diesem Abschnitt Mock-Objekte vorgestellt. Dummies und Mock-Objekte Um für Objekte oder kleine Gruppen von Objekte Komponenten-Tests zu schreiben, müssen diese von allen anderen Klassen, die sie benötigen, isoliert werden. Werden diese nicht von den abhängigen Klassen getrennt, werden die abhängien Klassen implizit immer mit getestet. Ein Verhalten, wie es im JCommSy (siehe Abschnitt 3.4) über die Tests aufgefallen ist. Dummies 5 sind eine Lösung, um für Komponenten-Test die zu testende Klasse zu isolieren. Eine abhängige Klasse wird dabei nur für den Test rudimentär implementiert. Der Dummy muss die selbe öffentliche Schnittstelle implementieren wie das Objekt, das es ersetzt. Es braucht dabei nicht die Funktionalität des ersetzten Objektes anzubieten, sondern nur ein einfaches Verhalten, das für den Test ausreicht. Auch hat ein Dummy keine weiteren Abhängigkeiten, selbst wenn das Objekt, welches es ersetzt, welche hätte. Für den Test kann jetzt das Objekt erzeugt werden, 5 auch Attrappen genant

50 46 KAPITEL 4. LÖSUNGSANSÄTZE das dabei seine Abhängigkeiten als Dummy-Objekte gesetzt bekommt. Dieser Ansatz ist für abhängige Klassen mit einer kleinen Schnittstelle einfach zu realisieren. Sind abhängige Klassen nicht unter der eigenen Kontrolle und lassen sich somit die Schnittstellen dieser Klassen nicht klein halten, dann wird die Implementation solcher Dummy-Objekte sehr aufwendig. Mock-Objekte bieten noch mehr Funktionalität für das Testen an. Sie implementieren nicht nur die Schnittstelle eines abhängien Objektes, sie haben zusätzliche Funktionalität für das Testen. Einem Mock-Objekt kann vor dem Test sein Verhalten im Test programmiert werden. Das Mock-Objekt wird vor dem eigentlichen Test mit den zu erwarteten Aufrufen programmiert. Zu den Aufrufen, die am Mock-Objekt im Test erwartet werden, wird festgelegt wie das Mock-Objekt darauf reagieren soll. Der eigentliche Test ruft an dem Objekt Methoden auf. Diese Methoden führen zu Aufrufen an dem abhängigen Objekt. Dieses ist im Test das Mock-Objekt. Das Mock- Objekt reagiert, wie es vor dem Test programmiert wurde. Der Test überprüft die Rückgaben des getesteten Objekts. Anschließend wird geprüft, ob das Mock-Objekt vom getestetem Objekt so benutzt wurde, wie es vor dem Test programmiert wurde. Diese Methode des Testens wird auch endoskopisches Testen genannt. Der Name stammt aus dem Artikel [MFC01]. Für die Erstellung von Mock-Objekten gibt es Frameworks wie JMock oder EasyMock. Für diese Arbeit wird EasyMock von Tammo Freese [Fre07] vorgestellt. Das Beispiel in Listing 4.8 zeigt einen Test für den Bücherservice mit einem Mock-Objekt. Mit EasyMock wird ein Mock für das Bücherrepository erstellt. Der Mock soll einen Aufruf an der Methode getbuecherfuerautor erwarten. Dabei bekommt der Mock das Verhalten bei diesem Aufruf programmiert, er muss dann die übergebene Liste zurück geben. Mit der Methode replay wird der Mock in den Wiedergabemodus versetzt. Anschließend startet der eigentliche Test, indem am Service eine Methode aufgerufen und der Rückgabewert überprüft wird. Mit der Methode verify überprüft EasyMock, ob die programmierten Aufrufe auch durch den Test an das Mock gesendet wurden. An dem Beispiel ist zu beachten, dass nur die aufgerufenen Methoden am Mock-Objekt programmiert werden müssen, nicht aber die gesamte Schnittstelle des ersetzten Objektes! Neben den einfachen Funktionen bieten die Frameworks für Mock-Objekte viel mehr Funktionalität. Zum Beispiel kann ein Mock-Objekt auch programmiert werden, um eine Exception zu werfen bei einem Aufruf. Zudem werden Algorithmen angeboten, mit denen die dem Mock-Objekt übergebenen Parameter leichter verglichen werden können. Eine gute Quelle zu dem Thema Testen mit Mock-Objekten ist das Buch von Johannes Link [Lin05] und die Dokumentation zu dem Framework EasyMock [Fre07]. 4.5 Zusammenfassung In diesem Kapitel wurden Lösungen zu den in den vorigen Kapiteln beschriebenen Problemen vorgestellt. Es wurde gezeigt wie Abhängigkeiten einer Klasse über deren Schnittstelle explizit gemacht werden können. Dabei wurde deutlich, wie auf-

51 4.5. ZUSAMMENFASSUNG 47 1 BuecherRepository mock = EasyMock.createMock(C BuecherRepository); 2 BuecherRepository service = new BuecherService(mock); 3 4 List<Buch> erwartet = new ArrayList<Buch>(); 5 6 EasyMock.expect(mock.getBuecherFuerAutor("floyd")).andReturnC (erwartet); 7 8 EasyMock.replay(mock); 9 10 List<Buch> ergebnis = service.buecherdesautors("floyd"); assertequals(ergebnis, erwartet); EasyMock.verify(mock); Listing 4.8: Beispiel EasyMock wendig eine programmatische Zusammenstellung abhängiger Klassen werden kann. Es wurde vorgestellt, wie Dependency Injection Abhängigkeiten verwaltet. Die typischen Merkmale und Unterschiede von Dependency Injection Frameworks sind gezeigt worden. Dabei wurden vorhandene Frameworks vorgestellt. Abschließend wurde gezeigt, wie Dependency Injection und Mock-Objekte die Testbarkeit im Projekt JCommSy vereinfachen können.

52 Kapitel 5 Beschreibung der praktischen Lösung Nach der Beschreibung der Grundlagen und der Analyse des vorhandenen Systems wurde im Abschnitt 4.5 mit den Techniken Dependency Injection und Mock- Objekten eine Lösung vorgeschlagen. Dieses Kapitel beschreibt die praktische Umsetzung der Diplomarbeit. Der erste Teil der Umsetzung ist eine Definition der Zielarchitektur des Systems. Anhand dieser Zielarchitektur wird ein Plan erstellt für die Umstellung, das Refactoring. Bei der Beschreibung der praktische Umstellung des Systems werden auch die Besonderheiten betrachtet, die bei einem Refactoring dieser Größe zu beachten sind. 5.1 Ziele der Umstellung Zuerst wird beschrieben welche Ziele mit dem Refactoring erreicht werden sollen. Anschließend folgt eine Beschreibung der Architektur des JCommSy nach der Umstellung. Konzept In diesem Abschnitt wird das Konzept der Zielarchitektur des JCommSy beschrieben. Dabei wird auf die Unterschiede zur vorhanden Architektur eingegangen. Die Zielarchitektur soll die Testbarkeit des Systems vereinfachen. Es soll einfacher werden, Komponenten-Tests zu schreiben für Komponenten, die abhängige Komponenten besitzen. Der wichtigste Punkt ist die Einführung von Dependency Injection. Hier stellt sich die Frage, welche der Objekte aus dem JCommSy durch den Dependency Injection Container verwaltet werden sollen und welche Objekte unberührt durch die Umstellung bleiben sollen. Es wurde in der Analyse festgestellt, dass besonders die Services und der Zugriff über die Serviceregistry problematisch in Bezug auf das Testen sind. Die Services werden in der Zielarchitektur durch einen Dependency In- 48

53 5.1. ZIELE DER UMSTELLUNG 49 jection Container verwaltet. Nicht betroffen von der Umstellung auf Dependency Injection sollten die Fachwerte und Materialien des Systems sein. An so wenig Stellen wie möglich sollte auf die API des Dependency Injection Frameworks zugegriffen werden. Die Verantwortung für die Konfiguration und Erzeugung der verwalteteten Objekte soll zentral gebündelt werden. Es gibt konzeptionell zwei Stellen, an denen das gewählte Framework benutzt werden muss, die Konfiguration und die Benutzung. Der Container muss beim Starten der Anwendung konfiguriert werden, dafür ist ein Zugriff notwendig. Der zweite Zugriff auf das Framework ist die Benutzung. Bei der Benutzung geht es um den Zugriff auf Objekte, die der Dependency Injection Container erzeugt und verwaltet. Benötigt eine Klasse ein Objekt, das von dem Dependency Injection Container verwaltet wird, dann muss eine Abhängigkeit zu diesem Objekt konfiguriert werden. Diese Abhängigkeit wird in der Konfiguration beschrieben. Im Sourcecode wird im Konstruktor oder im Setter keine Abhängigkeit zu der API des Dependency Injection Frameworks eingeführt. An dieser Stelle wird nur beschrieben, dass ein Objekt des angegebenen Typs benötigt wird. Beim Starten der Anwendung muss mindestens einmal ein Objekt von dem Dependency Injection Container bezogen werden, damit der Kontrollfluss an die verwalteten Objekte übergeben werden kann. Die verwalteten Objekte werden unter einem Typen oder einem Namen beim Framework in der Konfiguration registriert. Mit diesem Namen bzw. Typen kann der Dependency Injection Container nach dem verwalteten Objekt gefragt werden. Dieses Objekt wird inklusive seiner Abhängigkeiten geliefert und der Kontrollfluss kann durch einen Methodenaufruf übergeben werden. Wenn sämtliche Abhängigkeiten in der Konfiguration explizit gemacht wurden, dann ist nur eine Benutzung des Frameworks beim Starten notwendig. Das führt zu expliziten Abhängigkeiten und der Zugriff auf die API des Frameworks auf die Konfiguration und die initiale Benutzung beschränkt. Zielarchitektur Dieser Abschnitt beschreibt die Architektur, die nach der Umstellung erreicht werden soll. Es ist für das JCommSy geplant, Dependency Injection mit textueller Konfiguration zu benutzen. Sämtliche bestehende Services werden dabei durch einen Dependency Injection Container verwaltet. Es werden sämtliche Services umgestellt. Die Services werden im Konstruktor ihre Abhängigkeiten als Parameter darstellen. Die Vorteile von Constructor Injection sind in Kapitel 4.2 beschrieben. Als Framework für Dependency Injection wird das Spring-Framework benutzt. Die Konfiguration erfolgt mit XML-Dateien. Für die Erzeugung der Objekte wird Constructor-Injection benutzt. Die API des Spring-Frameworks wird nur von der Service Factory benutzt. Diese greift auf den Container zu, um Objekte zu beziehen oder neu zu erzeugen. Die Services im JCommSy sollen sich verhalten wie Singletons, es gibt im System jeweils nur ein Exempar von ihnen. Die Component-Commands werden zur Laufzeit zum Aufbau der Seite entsprechend der Anfrage benötigt. Sie müssen pro Anfrage neu erzeugt werden. Den Component-Commands werden bei der Erzeugung durch den Container im Konstruktor die benötigten Services injiziert.

54 50 KAPITEL 5. BESCHREIBUNG DER PRAKTISCHEN LÖSUNG Abbildung 5.1: Zielarchitektur - Sequenzdigramm Abbildung 5.2: Zielarchitektur - Klassendiagramm

55 5.2. PLANUNG Planung Refactoringplan Zuerst muss der Ansatz für das Refactoring analysiert und das Ziel des Refactorings genau beschrieben werden. Das definierte Ziel muss erreichbar und messbar sein. Die Bestimmung eines Ziels mit diesen beiden Eigenschaften ist wichtig, damit genau bestimmt werden kann, ob das Refactoring erledigt ist, oder nicht. Das Vorgehen beschreibt in groben Schritten, wie das System mit kleinen Änderungen in der Struktur auf die neue Architektur angepasst werden soll. Jeder dieser groben Schritte entspricht einem Etappenziel. Zieldefinition Für den Refactoring-Plan muss das vorhande System analysiert werden, wie beschrieben in Kapitel3.2. Für die Umstellung auf Dependency Injection wurde der Kontrollfluss betrachtet. An einer zentralen Stelle muss der Container einmal initialisert werden, damit ihm alle zu verwaltenden Klassen konfiguriert werden. Diese Konfiguration muss zu einem frühen Zeitpunkt geschehen, bevor die Anwendung auf Objekte zugreift, die durch den Container initialisiert werden. Zudem muss bei der Analyse betrachtet werden, wie die Anwendung auf den Container für die Erzeugung von Objekten zugreift. Außerdem soll dieser Zugriff nur an möglichst wenigen und zentralen Stellen im System erfolgen. Das JCommsy ist zurzeit ein webbasiertes System, implementiert mit Servlets. Der Kontrollfluss der Applikation geht immer durch diese Servlets. Diese Servlets greifen mit statischen Methoden auf eine Service-Registry zu, um entsprechend der aktuellen Aufgabe einen Service zu benutzen. Sie erzeugt den angefragten Service, wenn er noch nicht vorhanden ist. Diese Erzeugung erfolgt direkt mit einem Konstruktor und die exakte Typdefinition ist somit der Service-Registry bekannt. Die Service-Registry ist dabei als Singleton implementiert, wie in Kapitel 3.3 beschrieben. Der Zugriff auf die Service-Registry muss ersetzt werden durch Dependency Injection. Anhand der XML-Konfigurationsdateien erzeugt das Spring-Framework einen Applikationskontext. Dieser Applikationskontext ist ein Dependency-Injection-Container, er ist für die konkrete Erzeugung der Objekte verantwortlich. Ein Ziel des Refactorings ist, dass sämtliche in der Service-Registry instanzierten Klassen von einem Applikationkontext durch Spring erzeugt werden. Der Applikationskontext verwaltet sämtliche durch Spring erzeugten Objekte, und löst dabei transitiv die Abhängigkeiten auf. Ein Applikationskontext kann einen anderen Applikationskontext benutzen. Mit dieser Technik kann die Definition der Kontexte vereinfacht und eine simple Schichtenarchitekturen definiert werden. Ein weiteres Ziel des Refactorings ist die Ablösung von Singletons durch die Einführung von Dependency Injection für das JCommsy-System. Eine Analyse hat gezeigt, dass es zwei große Singletons im System gibt, die Service-Registry und den

56 52 KAPITEL 5. BESCHREIBUNG DER PRAKTISCHEN LÖSUNG ServiceManager. Diese Singletons müssen bei der Einführung ersetzt werden. Durch eine hierarchische Aufteilung der verwalteten Objekte mit mehreren Applikationskontexten wird deren Beschreibung übersichtlicher für die weitere Entwicklung. Die Aufteilung in die Applikationskontexte erfolgt anhand der Analyse des Systems. Ein Kontext beschreibt z.b. den Zugriff auf die Datenbank. Dieser Kontext lässt sich dann in Tests für den Zugriff auf eine andere Testdatenbank leicht ersetzen. Ein Applikationskontext beschreibt die im JCommsy vorhandenen fachlichen Services. Ein weiterer Applikationskontext definiert die Component-Commands und deren Abhängigkeiten. Vor der praktischen Arbeit wurde genau beschrieben, wann diese als erledigt erklärt werden kann. Hierfür muss ein messbares Ziel definiert werden. Die beschriebenen Anforderungen führen zusammengefasst zur folgenden Zieldefinition. Das Refactoring gilt als beendet, wenn: die beiden Singleton-Klassen ersetzt wurden durch Dependency Injection und dabei eine simple mehrschichtige Architektur durch Applikationskontexte definiert wurde. Vorgehen Jeder der folgenden Schritte im Refactoring wird abgeschlossen mit der Durchführung aller JUnit-Tests und einem händischen Integrations-Test an der Anwendung ( durchklicken ). Sind diese Tests erfolgreich, wird der Zwischenstand in das Source- Repository eingecheckt. Somit wird in kleinen Schritt gearbeitet, die immer wieder zu einem korrekten und laufenden System führen. 1. Ein zentraler Applikationskontext von Spring muss eingeführt werden. Dieser muss zur Startzeit der Anwendung initialisiert werden. (a) Für die Initialisierung wird das Spring-Servlet oder der Spring-Context- Listener benutzt. Diese werden beim Start der Anwendung einmal ausgeführt und stellen dann in einem zentralen Kontext den Container zur Verfügung. (b) Für den Zugriff aus dem JCommSy-Servlet auf die zur Verfügung gestellten Services muss eine Zugriffsmethode erstellt werden. Diese Methode abstrahiert von der Spring-API und ist der einzige zentrale Zugriff auf alle Services. (c) Sämtliche Einstiegspunkte in den Kontrollfluss müssen identifiziert werden. Wenn an diesen Punkten verwaltete Objekte benutzt werden, so müssen diese die neue Zugriffsmethode für Services nutzen können. Damit wird ein schrittweiser Umstieg auf Dependency Injection ermöglicht. 2. Die Zugriffsmethoden für Services an der ServiceRegistry werden abgelöst. Hierbei wird mit Services angefangen die keine Abhängigkeiten haben, oder

57 5.3. UMSTELLUNG 53 Abhängigkeiten, die schon durch Dependency Injection verwaltet werden. Für jede Zugriffsmethode wird wie folgt vorgegangen: (a) Die Zugriffsmethode für den Service wird an der Service Registry auf deprecated gesetzt. Hiermit sind alle abzulösenden Zugriffe bei der Entwicklung sofort zu erkennen. (b) Falls der benutzte Service noch keine Trennung in Schnittstelle und Implementation hat, wird diese eingeführt. (c) Objekte, die in dem abzulösenden Service benutzt werden, müssen transitiv durch Dependency Injection erzeugt werden. (d) Abhängige Objekte werden im Service mit final markiert und durch den Konstruktor gesetzt. (e) Die Tests, die Zugriffsmethoden benutzen, müssen angepasst werden und eventuell mit EasyMock neu geschrieben werden. (f) Die Zugriffsmethode und das Feld für den Service kann in der ServiceRegistry gelöscht werden. 3. Der vorige Schritt wird für alle Zugriffsmethoden an der Service-Registry wiederholt, bis keine Klasse mehr auf die Service-Registry zugreift. 4. Die Klasse ServiceRegistry kann gelöscht werden. 5. Die Zugriffsmethoden des Service-Manageres werden analog zu der Service- Registry durch Dependency Injection abgelöst. 6. Die Klasse ServiceManager kann gelöscht werden. Dieser Plan ist die Leitlinie für die Umstellung des Systems. Der Plan ist vor der Umstellung erstellt worden. Im nächsten Abschnitt wird gezeigt, welche Schritte genau umgesetzt werden konnten und welche Schritte angepasst werden mussten. 5.3 Umstellung Dieser Abschnitt beschreibt die Erfahrung, die bei der Umstellung des Systems gemacht wurden. Das wichtigste Hilfsmittel bei der Umstellung waren die automatischen Tests, die mit JUnit geschrieben worden waren. Vor jeder kleinen Änderungen wurden diese Tests ausgeführt. Nach jeder kleinen Änderung wurden diese Tests wieder ausgeführt. Dadurch wurden trotz der strukturellen Änderung unerwünschte Seiteneffekte vermieden. Verliefen die Tests auch nach den Änderungen erfolgreich, wurden die veränderten Dateien sofort in der zentralen Versionsverwaltung Subversion (SVN) bekannt gemacht. Das häufige Abgleichen mit dem aktuellen Stand der Entwicklung war besonders wichtig, da Änderungen anderer Entwickler einbezogen werden mussten, die zur gleichen Zeit an JCommSy arbeiteten. Jeder Stand der über SVN bekannt gemacht wurde, hat das System zwar verändert, war aber komplett getestet.

58 54 KAPITEL 5. BESCHREIBUNG DER PRAKTISCHEN LÖSUNG Abbildung 5.3: Vorgehen bei der Umstellung Das JCommSy wurde zu keiner Zeit für eine Umstellung dieser Größe soweit verändert, dass es nicht mehr funktionsfähig war. Das typische Vorgehen lässt sich in Abbildung 5.3 ablesen. Der erste Schritt ist, die nächste Aufgabe aus der Liste auf Seite 52 zu suchen. Im nächster Schritt Testen muss ein neuer Test für die Aufgabe formuliert werden. Sämtliche Tests werden ausgeführt, dabei werden die neu formulierten Tests, die die neue Aufgabe beschreiben, fehlschlagen. Im folgenden Abschnitt Programmieren sind die eigentlichen Tätigkeiten für die Umstellung zusammengefasst. Hier wurden die Methoden für den Zugriff auf die Services geschrieben und die vorhandenen Services auf Constructor Injection umgestellt. Der Schritt der Programmierung wird immer wieder unterbrochen von Testausführungen. Erst wenn die Tests erfolgreich durchlaufen und die Aufgabe durch die neuen und umgeschriebenen Tests überprüft wurde, kann die Aufgabe als erledigt angesehen werden. Es folgt der Schritt Update und es wird der aktuelle Stand auf dem Entwicklungsrechner mit dem aktuellen Stand der Versionsverwaltung abgeglichen. Falls Änderungen von anderen Entwicklern eingespielt wurden, muss das System erst aktualisiert und dann wieder getestet werden. Befindet sich keine neue Version in der Versionsverwaltung, können die Änderungen in die Versionsverwaltung im dem Schritt Einchecken eingespielt werden. Das Vorgehen war durch die vorherige Absicherung durch Tests testgetrieben, wie in [Bec02] beschrieben. Ein weiterer Aspekt ist die Größe der gewählten Aufgabe. Wenn für eine längere Zeit bei der Umstellung der Code nicht kompilierbar oder die Tests nicht erfolgreich waren, kann nicht eingecheckt werden. Das führt zu Problemen, wenn andere Entwickler zeitgleich an dem System arbeiten und dabei an den selben Dateien Änderungen durchführen. Die Größe der Aufgaben lässt sich nicht immer im Vorwege abschätzen. Aufgaben, die vorher als gering und schnell durchgeführt erscheinen, können sich als sehr langwierig herausstellen. Im Laufe der praktischen Arbeit haben sich Zeitboxen als nützlich herausgestellt. Ein Beispiel: Wenn die gewählte Aufgabe nicht in einer halben Stunde zu lösen ist, dann wurden alle Änderungen rückgängig gemacht und ein kleinerer Schritt für die Aufgabe gewählt. Im Sourcecode des JCommSy ist mehrfach Source- und Testcode aufgefallen, der nicht benutzt wurde. Vielfach wurde dort schon für eventuell kommende neue Features programmiert, die aber nicht benutzt wurden. Im Laufe des Refactorings habe

59 5.4. ZUSAMMENFASSUNG 55 ich diesen Code gelöscht und mich an das YAGNI-Prinzip gehalten, siehe Seite 2.2. Der nicht benutzte und gelöschte Sourcecode lässt sich bei Bedarf immer wieder durch die Versionsverwaltung beschaffen. Aufwand Das JCommSy wurde in acht Wochen auf Dependency Injection umgestellt. Mit der Versionsverwaltung Subversion können Zahlen ermittelt werden, die die Größe des Refactorings verdeutlichen. Bei der Umstellung wurden insgesamt 928 Dateien verändert. Pro Woche wurden durchschnittlich 128 Dateien, maximal 477 Dateien angepasst. Über die Service Registry konnte vor der Umstellung auf 18 Services zugegriffen werden. Nach der Umstellung werden mit dem Spring-Framework 24 Services und 33 Commands verwaltet. Insgesamt gab es vor dem Refactoring 903 Tests bei einer Abdeckung von 78%. Nach der Umstellung sind 798 Tests übrig geblieben, die insgesamt 76% Sourcecodes abdecken. 5.4 Zusammenfassung Das Kapitel hat die praktische Umsetzung der Diplomarbeit beschrieben. Für die Umsetzung wurde eine Definition der Zielarchitektur des Systems erstellt. Anhand der Zielarchitektur und der Unterschied zur bestehenden Architektur wurde ein Refactoringplan erstellt. Mit diesem Refactoringplan wurde die Umstellung durchgeführt. Bei der Umstellung wurde testgetrieben vorgegangen. Es hat sich gezeigt das ein Refactoring dieser Größe nur in sehr kleinen Schritten durchgeführt werden kann.

60 Kapitel 6 Ergebnis In diesem Kapitel wird die praktische Arbeit analysiert. Anhand der Vorgehensweise und der Messergebnisse werden die vorgestellten Lösungsansätze bewertet. Diese Retrospektive soll zudem Verbesserung bei der Vorgehensweise für ein Refactoring dieser Art vorstellen. 6.1 Bewertung der Vorgehensweise Die Umstellung des System wurde durch einen Refactoringplan vorbereitet. Bei der Umstellung konnte der Plan eingehalten werden. Nicht vorhersehbar war die Größe der einzelnen Aufgaben. Die Benutzung von festen Zeitabschnitten, in denen eine Aufgabe zu erledigt werden musste, war sehr hilfreich für die Erledigung. Dieses Vorgehen führte zu kleinen Schritten beim Umbau. Das war besser, als wenn eine zu große Aufgabe zu lange ohne Ergebnis gearbeitet bearbeteit worden wäre. Nur durch Analyse des Sourcecodes waren die Abhängigkeiten der Objekte ersichtlich, die mit Dependency Injection verwaltet werden sollten ersichtlich. Hierfür wurde kein spezielles Werkzeug verwendet. Es wurden nur die Mittel einer integrierten Entwicklungsumgebung (IDE) wie z.b. Eclipse benutzt. Dabei kann die Entwicklungsumgebung anzeigen, an welchen Stellen in einem System eine Klasse oder eine Schnittstelle benutzt wird. Mit einer ausführlicheren Analyse vor dem Umbau hätte man einen Graphen der Abhängigkeiten verwalteter Objekte erstellen können. Dieser Graph hätte zudem noch zeigen können in welchem Sichtbarkeitsbereich bzw. Scope diese Objekte jeweils gültig sind. Diese Übersicht der Abhängigkeiten sämtlicher verwalteten Objekte sind erst mit der XML-Konfiguration explizit gegeben. Das XML-Format eignet sich nur bedingt für die Analyse der Abhängigkeiten, zumindest bietet sie keine gute Übersicht. Abhilfe schafft hier die Erweiterung der Eclipse Entwicklungsumgebung, die Spring IDE, siehe [Spr07b]. In der Abbildung 6.1 ist ein Ausschnitt einer Ansicht dieser IDE dargestellt. Dieser Ausschnitt zeigt die verwalteteten Objekte und deren Abhängigkeiten. Für die Sichtbarkeit der Objekte, die nicht als Singleton verwaltet werden, wird ein extra Symbol angezeigt. Die Commands, die bei jedem Request erzeugt werden, sind in der Ansicht mit einem roten Sternchen markiert. 56

61 Abbildung 6.1: Spring IDE mit einem Ausschnitt der Abhängigkeiten im JCommSy 6.1. BEWERTUNG DER VORGEHENSWEISE 57

Klassenentwurf. Wie schreiben wir Klassen, die leicht zu verstehen, wartbar und wiederverwendbar sind? Objektorientierte Programmierung mit Java

Klassenentwurf. Wie schreiben wir Klassen, die leicht zu verstehen, wartbar und wiederverwendbar sind? Objektorientierte Programmierung mit Java Objektorientierte Programmierung mit Java Eine praxisnahe Einführung mit BlueJ Klassenentwurf Wie schreiben wir Klassen, die leicht zu verstehen, wartbar und wiederverwendbar sind? 1.0 Zentrale Konzepte

Mehr

Objektorientierte Programmierung

Objektorientierte Programmierung Objektorientierte Programmierung 1 Geschichte Dahl, Nygaard: Simula 67 (Algol 60 + Objektorientierung) Kay et al.: Smalltalk (erste rein-objektorientierte Sprache) Object Pascal, Objective C, C++ (wiederum

Mehr

Daniel Warneke warneke@upb.de 08.05.2006. Ein Vortrag im Rahmen des Proseminars Software Pioneers

Daniel Warneke warneke@upb.de 08.05.2006. Ein Vortrag im Rahmen des Proseminars Software Pioneers Design Patterns Daniel Warneke warneke@upb.de 08.05.2006 Ein Vortrag im Rahmen des Proseminars Software Pioneers Design Patterns 1/23 Übersicht Einleitung / Motivation Design Patterns Beispiele Rolle des

Mehr

Prinzipien Objektorientierter Programmierung

Prinzipien Objektorientierter Programmierung Prinzipien Objektorientierter Programmierung Valerian Wintner Inhaltsverzeichnis 1 Vorwort 1 2 Kapselung 1 3 Polymorphie 2 3.1 Dynamische Polymorphie...................... 2 3.2 Statische Polymorphie........................

Mehr

Objektorientierte Programmierung für Anfänger am Beispiel PHP

Objektorientierte Programmierung für Anfänger am Beispiel PHP Objektorientierte Programmierung für Anfänger am Beispiel PHP Johannes Mittendorfer http://jmittendorfer.hostingsociety.com 19. August 2012 Abstract Dieses Dokument soll die Vorteile der objektorientierten

Mehr

Diplomarbeit. Konzeption und Implementierung einer automatisierten Testumgebung. Thomas Wehrspann. 10. Dezember 2008

Diplomarbeit. Konzeption und Implementierung einer automatisierten Testumgebung. Thomas Wehrspann. 10. Dezember 2008 Konzeption und Implementierung einer automatisierten Testumgebung, 10. Dezember 2008 1 Gliederung Einleitung Softwaretests Beispiel Konzeption Zusammenfassung 2 Einleitung Komplexität von Softwaresystemen

Mehr

SDD System Design Document

SDD System Design Document SDD Software Konstruktion WS01/02 Gruppe 4 1. Einleitung Das vorliegende Dokument richtet sich vor allem an die Entwickler, aber auch an den Kunden, der das enstehende System verwenden wird. Es soll einen

Mehr

Prozessbewertung und -verbesserung nach ITIL im Kontext des betrieblichen Informationsmanagements. von Stephanie Wilke am 14.08.08

Prozessbewertung und -verbesserung nach ITIL im Kontext des betrieblichen Informationsmanagements. von Stephanie Wilke am 14.08.08 Prozessbewertung und -verbesserung nach ITIL im Kontext des betrieblichen Informationsmanagements von Stephanie Wilke am 14.08.08 Überblick Einleitung Was ist ITIL? Gegenüberstellung der Prozesse Neuer

Mehr

Komponententest. Testen von Software Systemen. Übung 02 SS 2009 Version: 1.0 09.06.2009

Komponententest. Testen von Software Systemen. Übung 02 SS 2009 Version: 1.0 09.06.2009 Testen von Software Systemen Übung 02 SS 2009 Version: 1.0 09.06.2009 Komponententest Kunde: Dr. Reinhold Plösch Dr. Johannes Sametinger Kundenreferenz: 259.019 Team 19 Mitarbeiter: Christian Märzinger

Mehr

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren Lineargleichungssysteme: Additions-/ Subtraktionsverfahren W. Kippels 22. Februar 2014 Inhaltsverzeichnis 1 Einleitung 2 2 Lineargleichungssysteme zweiten Grades 2 3 Lineargleichungssysteme höheren als

Mehr

Fassade. Objektbasiertes Strukturmuster. C. Restorff & M. Rohlfing

Fassade. Objektbasiertes Strukturmuster. C. Restorff & M. Rohlfing Fassade Objektbasiertes Strukturmuster C. Restorff & M. Rohlfing Übersicht Motivation Anwendbarkeit Struktur Teilnehmer Interaktion Konsequenz Implementierung Beispiel Bekannte Verwendung Verwandte Muster

Mehr

Session Beans & Servlet Integration. Ralf Gitzel ralf_gitzel@hotmail.de

Session Beans & Servlet Integration. Ralf Gitzel ralf_gitzel@hotmail.de s & Servlet Integration Ralf Gitzel ralf_gitzel@hotmail.de 1 Themenübersicht Ralf Gitzel ralf_gitzel@hotmail.de 2 Übersicht Motivation Das Interface Stateful und Stateless s Programmierung einer Stateful

Mehr

SEP 114. Design by Contract

SEP 114. Design by Contract Design by Contract SEP 114 Design by Contract Teile das zu entwickelnde Programm in kleine Einheiten (Klassen, Methoden), die unabhängig voneinander entwickelt und überprüft werden können. Einheiten mit

Mehr

Software-Entwurfsmuster

Software-Entwurfsmuster Software-Entwurfsmuster Prinzip von Entwurfsmustern und einige elementare Beispiele Malte Spiess malte@mathematik.uni-ulm.de Seminar Bildanalyse und Simulation mit Java im WS 2003/2004 Universität Ulm

Mehr

Autorisierung. Sicherheit und Zugriffskontrolle & Erstellen einer Berechtigungskomponente

Autorisierung. Sicherheit und Zugriffskontrolle & Erstellen einer Berechtigungskomponente Autorisierung Sicherheit und Zugriffskontrolle & Erstellen einer Berechtigungskomponente Dokumentation zum Referat von Matthias Warnicke und Joachim Schröder Modul: Komponenten basierte Softwareentwickelung

Mehr

Design Pattern - Strukturmuster. CAS SWE - OOAD Marco Hunziker Klaus Imfeld Frédéric Bächler Marcel Lüthi

Design Pattern - Strukturmuster. CAS SWE - OOAD Marco Hunziker Klaus Imfeld Frédéric Bächler Marcel Lüthi Design Pattern - Strukturmuster CAS SWE - OOAD Marco Hunziker Klaus Imfeld Frédéric Bächler Marcel Lüthi Agenda Einleitung Strukturmuster Fassade Model View Controller Vergleich 2 Einleitung Strukturmuster

Mehr

Objektorientierte Programmierung. Kapitel 12: Interfaces

Objektorientierte Programmierung. Kapitel 12: Interfaces 12. Interfaces 1/14 Objektorientierte Programmierung Kapitel 12: Interfaces Stefan Brass Martin-Luther-Universität Halle-Wittenberg Wintersemester 2012/13 http://www.informatik.uni-halle.de/ brass/oop12/

Mehr

Übungsklausur vom 7. Dez. 2007

Übungsklausur vom 7. Dez. 2007 Übungsklausur vom 7. Dez. 2007 Ein Lösungsmuster Teilbereiche der Softwaretechnik Software Anforderungen Software Entwurf Software Konstruktion Software Test Software Wartung Software Konfigurationsmanagement

Mehr

Software Engineering Klassendiagramme Assoziationen

Software Engineering Klassendiagramme Assoziationen Software Engineering Klassendiagramme Assoziationen Prof. Adrian A. Müller, PMP, PSM 1, CSM Fachbereich Informatik und Mikrosystemtechnik 1 Lesen von Multiplizitäten (1) Multiplizitäten werden folgendermaßen

Mehr

Hilfedatei der Oden$-Börse Stand Juni 2014

Hilfedatei der Oden$-Börse Stand Juni 2014 Hilfedatei der Oden$-Börse Stand Juni 2014 Inhalt 1. Einleitung... 2 2. Die Anmeldung... 2 2.1 Die Erstregistrierung... 3 2.2 Die Mitgliedsnummer anfordern... 4 3. Die Funktionen für Nutzer... 5 3.1 Arbeiten

Mehr

Agile Vorgehensmodelle in der Softwareentwicklung: Scrum

Agile Vorgehensmodelle in der Softwareentwicklung: Scrum C A R L V O N O S S I E T Z K Y Agile Vorgehensmodelle in der Softwareentwicklung: Scrum Johannes Diemke Vortrag im Rahmen der Projektgruppe Oldenburger Robot Soccer Team im Wintersemester 2009/2010 Was

Mehr

Testplan. Hochschule Luzern Technik & Architektur. Software Komponenten FS13. Gruppe 03 Horw, 16.04.2013

Testplan. Hochschule Luzern Technik & Architektur. Software Komponenten FS13. Gruppe 03 Horw, 16.04.2013 Software Komponenten FS13 Gruppe 03 Horw, 16.04.2013 Bontekoe Christian Estermann Michael Moor Simon Rohrer Felix Autoren Bontekoe Christian Studiengang Informatiker (Berufsbegleitend) Estermann Michael

Mehr

Guide DynDNS und Portforwarding

Guide DynDNS und Portforwarding Guide DynDNS und Portforwarding Allgemein Um Geräte im lokalen Netzwerk von überall aus über das Internet erreichen zu können, kommt man um die Themen Dynamik DNS (kurz DynDNS) und Portweiterleitung(auch

Mehr

Fragebogen ISONORM 9241/110-S

Fragebogen ISONORM 9241/110-S Fragebogen ISONORM 9241/110-S Beurteilung von Software auf Grundlage der Internationalen Ergonomie-Norm DIN EN ISO 9241-110 von Prof. Dr. Jochen Prümper www.seikumu.de Fragebogen ISONORM 9241/110-S Seite

Mehr

Klausur Softwaretechnik 3 22. Feb. 2008

Klausur Softwaretechnik 3 22. Feb. 2008 Klausur Softwaretechnik 3 22. Feb. 2008 Hinweise Bevor Sie mit der Bearbeitung der Aufgaben beginnen, müssen Sie auf allen Blättern Ihren Namen und Ihre Matrikelnummer eintragen. Prüfen Sie Ihre Klausur

Mehr

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen Binäre Bäume 1. Allgemeines Binäre Bäume werden grundsätzlich verwendet, um Zahlen der Größe nach, oder Wörter dem Alphabet nach zu sortieren. Dem einfacheren Verständnis zu Liebe werde ich mich hier besonders

Mehr

Einleitung: Frontend Backend

Einleitung: Frontend Backend Die Internetseite des LSW Deutschland e.v. hat ein neues Gesicht bekommen. Ab dem 01.01.2012 ist sie in Form eines Content Management Systems (CMS) im Netz. Einleitung: Die Grundlage für die Neuprogrammierung

Mehr

Übungen zur Softwaretechnik

Übungen zur Softwaretechnik Technische Universität München Fakultät für Informatik Lehrstuhl IV: Software & Systems Engineering Markus Pister, Dr. Bernhard Rumpe WS 2002/2003 Lösungsblatt 9 17. Dezember 2002 www4.in.tum.de/~rumpe/se

Mehr

Klausur WS 2006/07 Programmiersprache Java Objektorientierte Programmierung II 15. März 2007

Klausur WS 2006/07 Programmiersprache Java Objektorientierte Programmierung II 15. März 2007 Fachhochschule Bonn-Rhein-Sieg University of Applied Sciences Fachbereich Informatik Prof. Dr. Peter Becker Klausur WS 2006/07 Programmiersprache Java Objektorientierte Programmierung II 15. März 2007

Mehr

4. Jeder Knoten hat höchstens zwei Kinder, ein linkes und ein rechtes.

4. Jeder Knoten hat höchstens zwei Kinder, ein linkes und ein rechtes. Binäre Bäume Definition: Ein binärer Baum T besteht aus einer Menge von Knoten, die durch eine Vater-Kind-Beziehung wie folgt strukturiert ist: 1. Es gibt genau einen hervorgehobenen Knoten r T, die Wurzel

Mehr

Software Engineering. Zur Architektur der Applikation Data Repository. Franz-Josef Elmer, Universität Basel, HS 2015

Software Engineering. Zur Architektur der Applikation Data Repository. Franz-Josef Elmer, Universität Basel, HS 2015 Software Engineering Zur Architektur der Applikation Data Repository Franz-Josef Elmer, Universität Basel, HS 2015 Software Engineering: Mit acht bewährten Praktiken zu gutem Code 2 Schichtarchitektur

Mehr

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {... PIWIN I Kap. 8 Objektorientierte Programmierung - Vererbung 31 Schlüsselwort: final Verhindert, dass eine Methode überschrieben wird public final int holekontostand() {... Erben von einer Klasse verbieten:

Mehr

Kapitel 3 Frames Seite 1

Kapitel 3 Frames Seite 1 Kapitel 3 Frames Seite 1 3 Frames 3.1 Allgemeines Mit Frames teilt man eine HTML-Seite in mehrere Bereiche ein. Eine Seite, die mit Frames aufgeteilt ist, besteht aus mehreren Einzelseiten, die sich den

Mehr

Software Engineering. Sommersemester 2012, Dr. Andreas Metzger

Software Engineering. Sommersemester 2012, Dr. Andreas Metzger Software Engineering (Übungsblatt 2) Sommersemester 2012, Dr. Andreas Metzger Übungsblatt-Themen: Prinzip, Technik, Methode und Werkzeug; Arten von Wartung; Modularität (Kohäsion/ Kopplung); Inkrementelle

Mehr

Grundbegriffe der Informatik

Grundbegriffe der Informatik Grundbegriffe der Informatik Einheit 15: Reguläre Ausdrücke und rechtslineare Grammatiken Thomas Worsch Universität Karlsruhe, Fakultät für Informatik Wintersemester 2008/2009 1/25 Was kann man mit endlichen

Mehr

Das System sollte den Benutzer immer auf dem Laufenden halten, indem es angemessenes Feedback in einer angemessenen Zeit liefert.

Das System sollte den Benutzer immer auf dem Laufenden halten, indem es angemessenes Feedback in einer angemessenen Zeit liefert. Usability Heuristiken Karima Tefifha Proseminar: "Software Engineering Kernkonzepte: Usability" 28.06.2012 Prof. Dr. Kurt Schneider Leibniz Universität Hannover Die ProSeminar-Ausarbeitung beschäftigt

Mehr

OP-LOG www.op-log.de

OP-LOG www.op-log.de Verwendung von Microsoft SQL Server, Seite 1/18 OP-LOG www.op-log.de Anleitung: Verwendung von Microsoft SQL Server 2005 Stand Mai 2010 1 Ich-lese-keine-Anleitungen 'Verwendung von Microsoft SQL Server

Mehr

Java Enterprise Architekturen Willkommen in der Realität

Java Enterprise Architekturen Willkommen in der Realität Java Enterprise Architekturen Willkommen in der Realität Ralf Degner (Ralf.Degner@tk-online.de), Dr. Frank Griffel (Dr.Frank.Griffel@tk-online.de) Techniker Krankenkasse Häufig werden Mehrschichtarchitekturen

Mehr

Einführung in die Java- Programmierung

Einführung in die Java- Programmierung Einführung in die Java- Programmierung Dr. Volker Riediger Tassilo Horn riediger horn@uni-koblenz.de WiSe 2012/13 1 Wichtig... Mittags keine Pommes... Praktikum A 230 C 207 (Madeleine + Esma) F 112 F 113

Mehr

Softwarequalität: Einführung. 15. April 2015

Softwarequalität: Einführung. 15. April 2015 Softwarequalität: Einführung 15. April 2015 Überblick Warum ist Softwarequalität wichtig? Was ist Softwarequalität? Wie erreicht man Softwarequalität? Taentzer Softwarequalität 2015 8 Berühmte Software-Fehler

Mehr

StuPro-Seminar Dokumentation in der Software-Wartung. StuPro-Seminar Probleme und Schwierigkeiten in der Software-Wartung.

StuPro-Seminar Dokumentation in der Software-Wartung. StuPro-Seminar Probleme und Schwierigkeiten in der Software-Wartung. StuPro-Seminar Dokumentation in der Software-Wartung StuPro-Seminar Probleme und Schwierigkeiten in der Software-Wartung Folie 1/xx Software-Wartung: theoretisch Ausgangslage eigentlich simpel: fertige

Mehr

SANDBOXIE konfigurieren

SANDBOXIE konfigurieren SANDBOXIE konfigurieren für Webbrowser und E-Mail-Programme Dies ist eine kurze Anleitung für die grundlegenden folgender Programme: Webbrowser: Internet Explorer, Mozilla Firefox und Opera E-Mail-Programme:

Mehr

MCRServlet Table of contents

MCRServlet Table of contents Table of contents 1 Das Zusammenspiel der Servlets mit dem MCRServlet... 2 1 Das Zusammenspiel der Servlets mit dem MCRServlet Als übergeordnetes Servlet mit einigen grundlegenden Funktionalitäten dient

Mehr

Content Management System mit INTREXX 2002.

Content Management System mit INTREXX 2002. Content Management System mit INTREXX 2002. Welche Vorteile hat ein CM-System mit INTREXX? Sie haben bereits INTREXX im Einsatz? Dann liegt es auf der Hand, dass Sie ein CM-System zur Pflege Ihrer Webseite,

Mehr

Qualitätssicherung. Was ist Qualität?

Qualitätssicherung. Was ist Qualität? Ein Überblick Methoden und Werkzeuge zur Softwareproduktion Was ist Qualität? "Als Qualität eines Gegenstandes bezeichnen wir die Gesamtheit seiner charakteristischen Eigenschaften" Hesse et al. 2 Was

Mehr

SEMINAR Modifikation für die Nutzung des Community Builders

SEMINAR Modifikation für die Nutzung des Community Builders 20.04.2010 SEMINAR Modifikation für die Nutzung des Community Builders Step by Step Anleitung ecktion SEMINAR Modifikation für die Nutzung des Community Builders Step by Step Anleitung Bevor Sie loslegen

Mehr

Qt-Projekte mit Visual Studio 2005

Qt-Projekte mit Visual Studio 2005 Qt-Projekte mit Visual Studio 2005 Benötigte Programme: Visual Studio 2005 Vollversion, Microsoft Qt 4 Open Source s. Qt 4-Installationsanleitung Tabelle 1: Benötigte Programme für die Qt-Programmierung

Mehr

Typisierung des Replikationsplan Wirries, Denis Datenbankspezialist

Typisierung des Replikationsplan Wirries, Denis Datenbankspezialist Typisierung des Replikationsplan Wirries, Denis Datenbankspezialist Feintypisierung - Überblick Ergebnisse Ergebnisse aus aus anderen anderen Arbeitsergebnissen Arbeitsergebnissen Replikationsplan Replikationsplan

Mehr

Softwaretechnik (Allgemeine Informatik) Überblick

Softwaretechnik (Allgemeine Informatik) Überblick Softwaretechnik (Allgemeine Informatik) Überblick 1 Einführung und Überblick 2 Abstraktion 3 Objektorientiertes Vorgehensmodell 4 Methoden der Anforderungs- und Problembereichsanalyse 5 UML-Diagramme 6

Mehr

Sehr geehrte Faktor-IPS Anwender,

Sehr geehrte Faktor-IPS Anwender, März 2014 Faktor-IPS 3.11 Das neue Release Faktor-IPS 3.11 steht Ihnen zum Download zur Verfügung. Wir informieren Sie über die neusten Feautres. Lesen Sie mehr Sehr geehrte Faktor-IPS Anwender, Auf faktorzehn.org

Mehr

Lastenheft. Inhaltsverzeichnis. Gruppe: swp09-5. Projektleiterin: Anne Vogler am: 28. April 2009. 1 Zielbestimmungen 2. 2 Produkteinsatz 2

Lastenheft. Inhaltsverzeichnis. Gruppe: swp09-5. Projektleiterin: Anne Vogler am: 28. April 2009. 1 Zielbestimmungen 2. 2 Produkteinsatz 2 Lastenheft Inhaltsverzeichnis 1 Zielbestimmungen 2 2 Produkteinsatz 2 3 Produktübersicht 3 4 Produktfunktionen 4 4.1 Muss-Funktionen................................. 4 4.1.1 Benutzerfunktionen...........................

Mehr

Beschreibung und Bedienungsanleitung. Inhaltsverzeichnis: Abbildungsverzeichnis: Werkzeug für verschlüsselte bpks. Dipl.-Ing.

Beschreibung und Bedienungsanleitung. Inhaltsverzeichnis: Abbildungsverzeichnis: Werkzeug für verschlüsselte bpks. Dipl.-Ing. www.egiz.gv.at E-Mail: post@egiz.gv.at Telefon: ++43 (316) 873 5514 Fax: ++43 (316) 873 5520 Inffeldgasse 16a / 8010 Graz / Austria Beschreibung und Bedienungsanleitung Werkzeug für verschlüsselte bpks

Mehr

Fachbericht zum Thema: Anforderungen an ein Datenbanksystem

Fachbericht zum Thema: Anforderungen an ein Datenbanksystem Fachbericht zum Thema: Anforderungen an ein Datenbanksystem von André Franken 1 Inhaltsverzeichnis 1 Inhaltsverzeichnis 1 2 Einführung 2 2.1 Gründe für den Einsatz von DB-Systemen 2 2.2 Definition: Datenbank

Mehr

Die Lernumgebung des Projekts Informationskompetenz

Die Lernumgebung des Projekts Informationskompetenz Beitrag für Bibliothek aktuell Die Lernumgebung des Projekts Informationskompetenz Von Sandra Merten Im Rahmen des Projekts Informationskompetenz wurde ein Musterkurs entwickelt, der den Lehrenden als

Mehr

1 Mathematische Grundlagen

1 Mathematische Grundlagen Mathematische Grundlagen - 1-1 Mathematische Grundlagen Der Begriff der Menge ist einer der grundlegenden Begriffe in der Mathematik. Mengen dienen dazu, Dinge oder Objekte zu einer Einheit zusammenzufassen.

Mehr

etutor Benutzerhandbuch XQuery Benutzerhandbuch Georg Nitsche

etutor Benutzerhandbuch XQuery Benutzerhandbuch Georg Nitsche etutor Benutzerhandbuch Benutzerhandbuch XQuery Georg Nitsche Version 1.0 Stand März 2006 Versionsverlauf: Version Autor Datum Änderungen 1.0 gn 06.03.2006 Fertigstellung der ersten Version Inhaltsverzeichnis:

Mehr

Task: Nmap Skripte ausführen

Task: Nmap Skripte ausführen Task: Nmap Skripte ausführen Inhalt Einfache Netzwerkscans mit NSE Ausführen des Scans Anpassung der Parameter Einleitung Copyright 2009-2015 Greenbone Networks GmbH Herkunft und aktuellste Version dieses

Mehr

Updatehinweise für die Version forma 5.5.5

Updatehinweise für die Version forma 5.5.5 Updatehinweise für die Version forma 5.5.5 Seit der Version forma 5.5.0 aus 2012 gibt es nur noch eine Office-Version und keine StandAlone-Version mehr. Wenn Sie noch mit der alten Version forma 5.0.x

Mehr

PHP - Projekt Personalverwaltung. Erstellt von James Schüpbach

PHP - Projekt Personalverwaltung. Erstellt von James Schüpbach - Projekt Personalverwaltung Erstellt von Inhaltsverzeichnis 1Planung...3 1.1Datenbankstruktur...3 1.2Klassenkonzept...4 2Realisierung...5 2.1Verwendete Techniken...5 2.2Vorgehensweise...5 2.3Probleme...6

Mehr

Abamsoft Finos im Zusammenspiel mit shop to date von DATA BECKER

Abamsoft Finos im Zusammenspiel mit shop to date von DATA BECKER Abamsoft Finos im Zusammenspiel mit shop to date von DATA BECKER Abamsoft Finos in Verbindung mit der Webshopanbindung wurde speziell auf die Shop-Software shop to date von DATA BECKER abgestimmt. Mit

Mehr

Suche schlecht beschriftete Bilder mit Eigenen Abfragen

Suche schlecht beschriftete Bilder mit Eigenen Abfragen Suche schlecht beschriftete Bilder mit Eigenen Abfragen Ist die Bilderdatenbank über einen längeren Zeitraum in Benutzung, so steigt die Wahrscheinlichkeit für schlecht beschriftete Bilder 1. Insbesondere

Mehr

IAWWeb PDFManager. - Kurzanleitung -

IAWWeb PDFManager. - Kurzanleitung - IAWWeb PDFManager - Kurzanleitung - 1. Einleitung Dieses Dokument beschreibt kurz die grundlegenden Funktionen des PDFManager. Der PDF Manager dient zur Pflege des Dokumentenbestandes. Er kann über die

Mehr

infach Geld FBV Ihr Weg zum finanzellen Erfolg Florian Mock

infach Geld FBV Ihr Weg zum finanzellen Erfolg Florian Mock infach Ihr Weg zum finanzellen Erfolg Geld Florian Mock FBV Die Grundlagen für finanziellen Erfolg Denn Sie müssten anschließend wieder vom Gehaltskonto Rückzahlungen in Höhe der Entnahmen vornehmen, um

Mehr

Plugins. Stefan Salich (sallo@gmx.de) Stand 2008-11-21

Plugins. Stefan Salich (sallo@gmx.de) Stand 2008-11-21 Plugins Stefan Salich (sallo@gmx.de) Stand 2008-11-21 Inhaltsverzeichnis 0 Einleitung...3 0.1 Sinn und Zweck...3 0.2 Änderungsübersicht...3 0.3 Abkürzungsverzeichnis...3 1 Einfügen eines Plugins...4 1.1

Mehr

Projektmanagement. Einleitung. Beginn. Was ist Projektmanagement? In dieser Dokumentation erfahren Sie Folgendes:

Projektmanagement. Einleitung. Beginn. Was ist Projektmanagement? In dieser Dokumentation erfahren Sie Folgendes: Projektmanagement Link http://promana.edulearning.at/projektleitung.html Einleitung Was ist Projektmanagement? In dieser Dokumentation erfahren Sie Folgendes: Definition des Begriffs Projekt" Kriterien

Mehr

Bedienungsanleitung. Matthias Haasler. Version 0.4. für die Arbeit mit der Gemeinde-Homepage der Paulus-Kirchengemeinde Tempelhof

Bedienungsanleitung. Matthias Haasler. Version 0.4. für die Arbeit mit der Gemeinde-Homepage der Paulus-Kirchengemeinde Tempelhof Bedienungsanleitung für die Arbeit mit der Gemeinde-Homepage der Paulus-Kirchengemeinde Tempelhof Matthias Haasler Version 0.4 Webadministrator, email: webadmin@rundkirche.de Inhaltsverzeichnis 1 Einführung

Mehr

Speicher in der Cloud

Speicher in der Cloud Speicher in der Cloud Kostenbremse, Sicherheitsrisiko oder Basis für die unternehmensweite Kollaboration? von Cornelius Höchel-Winter 2013 ComConsult Research GmbH, Aachen 3 SYNCHRONISATION TEUFELSZEUG

Mehr

FUTURE NETWORK 20.11.2013 REQUIREMENTS ENGINEERING

FUTURE NETWORK 20.11.2013 REQUIREMENTS ENGINEERING 18/11/13 Requirements Engineering 21 November 2013 DIE GRUNDFRAGEN Wie erhält der Kunde den größten Nutzen? Wie kann der Kunde am besten spezifizieren, was er haben will? Welchen Detailierungsgrad braucht

Mehr

Konfiguration VLAN's. Konfiguration VLAN's IACBOX.COM. Version 2.0.1 Deutsch 01.07.2014

Konfiguration VLAN's. Konfiguration VLAN's IACBOX.COM. Version 2.0.1 Deutsch 01.07.2014 Konfiguration VLAN's Version 2.0.1 Deutsch 01.07.2014 In diesem HOWTO wird die Konfiguration der VLAN's für das Surf-LAN der IAC-BOX beschrieben. Konfiguration VLAN's TITEL Inhaltsverzeichnis Inhaltsverzeichnis...

Mehr

! " # $ " % & Nicki Wruck worldwidewruck 08.02.2006

!  # $  % & Nicki Wruck worldwidewruck 08.02.2006 !"# $ " %& Nicki Wruck worldwidewruck 08.02.2006 Wer kennt die Problematik nicht? Die.pst Datei von Outlook wird unübersichtlich groß, das Starten und Beenden dauert immer länger. Hat man dann noch die.pst

Mehr

SWT II Projekt. Chat - Anwendung. Pflichtenheft 2000 SWT

SWT II Projekt. Chat - Anwendung. Pflichtenheft 2000 SWT SWT II Projekt Chat - Anwendung Pflichtenheft 2000 SWT i Versionen Datum Version Beschreibung Autor 3.11.2000 1.0 erste Version Dietmar Matthes ii Inhaltsverzeichnis 1. ZWECK... 1 1.1. RAHMEN... 1 1.2.

Mehr

Universal Dashboard auf ewon Alarmübersicht auf ewon eigener HTML Seite.

Universal Dashboard auf ewon Alarmübersicht auf ewon eigener HTML Seite. ewon - Technical Note Nr. 003 Version 1.2 Universal Dashboard auf ewon Alarmübersicht auf ewon eigener HTML Seite. Übersicht 1. Thema 2. Benötigte Komponenten 3. Downloaden der Seiten und aufspielen auf

Mehr

Anleitungen zum KMG-Email-Konto

Anleitungen zum KMG-Email-Konto In dieser Anleitung erfahren Sie, wie Sie mit einem Browser (Firefox etc.) auf das Email-Konto zugreifen; Ihr Kennwort ändern; eine Weiterleitung zu einer privaten Email-Adresse einrichten; Ihr Email-Konto

Mehr

mysql - Clients MySQL - Abfragen eine serverbasierenden Datenbank

mysql - Clients MySQL - Abfragen eine serverbasierenden Datenbank mysql - Clients MySQL - Abfragen eine serverbasierenden Datenbank In den ersten beiden Abschnitten (rbanken1.pdf und rbanken2.pdf) haben wir uns mit am Ende mysql beschäftigt und kennengelernt, wie man

Mehr

Gruppe: swp09-6 26.04.2009 Gruppenleiter: U. Seiler Aufgabenstellung 3. Lastenheft

Gruppe: swp09-6 26.04.2009 Gruppenleiter: U. Seiler Aufgabenstellung 3. Lastenheft Lastenheft Synchronisation von RDF Modellen im PKM Kontext als Plugin für OntoWiki Inhaltsverzeichnis 1. Zielbestimmung 2. Produkteinsatz 3. Produktübersicht 4. Produktfunktionen 4.1. Muss-Bedingungen

Mehr

Anleitung mtan (SMS-Authentisierung) mit SSLVPN.TG.CH

Anleitung mtan (SMS-Authentisierung) mit SSLVPN.TG.CH Amt für Informatik Anleitung mtan (SMS-Authentisierung) mit SSLVPN.TG.CH Anleitung vom 12. September 2009 Version: 1.0 Ersteller: Ressort Sicherheit Zielgruppe: Benutzer von SSLVPN.TG.CH Kurzbeschreib:

Mehr

Übung 6: Feinentwurf. Prof. Dr. Dr. h.c. Manfred Broy Dr. Herbert Ehler, Martin Feilkas 6. Juli 2006 Bernd Spanfelner, Sebastian Winter

Übung 6: Feinentwurf. Prof. Dr. Dr. h.c. Manfred Broy Dr. Herbert Ehler, Martin Feilkas 6. Juli 2006 Bernd Spanfelner, Sebastian Winter Prof. Dr. Dr. h.c. Manfred Broy Sommersemester Dr. Herbert Ehler, Martin Feilkas 6. Juli 2006 Bernd Spanfelner, Sebastian Winter Einführung in die Softwaretechnik Übung 6: Feinentwurf Aufgabe 17: Entwurfsmuster

Mehr

Anlegen eines DLRG Accounts

Anlegen eines DLRG Accounts Anlegen eines DLRG Accounts Seite 1 von 6 Auf der Startseite des Internet Service Centers (https:\\dlrg.de) führt der Link DLRG-Account anlegen zu einer Eingabemaske, mit der sich jedes DLRG-Mitglied genau

Mehr

Online Banking System

Online Banking System Online Banking System Pflichtenheft im Rahmen des WI-Praktikum bei Thomas M. Lange Fachhochschule Giessen-Friedberg Fachbereich MNI Studiengang Informatik Erstellt von: Eugen Riske Yueksel Korkmaz Alper

Mehr

Lernerfolge sichern - Ein wichtiger Beitrag zu mehr Motivation

Lernerfolge sichern - Ein wichtiger Beitrag zu mehr Motivation Lernerfolge sichern - Ein wichtiger Beitrag zu mehr Motivation Einführung Mit welchen Erwartungen gehen Jugendliche eigentlich in ihre Ausbildung? Wir haben zu dieser Frage einmal die Meinungen von Auszubildenden

Mehr

sm@rt-tan plus Flickerfeld bewegt sich nicht

sm@rt-tan plus Flickerfeld bewegt sich nicht Technischer Hintergrund Um die Verwendung des Verfahrens Sm@rt-TAN plus des neuen sicheren TAN- Verfahrens so komfortabel wie möglich zu gestalten, wurde eine Möglichkeit geschaffen, die Angaben einer

Mehr

SharePoint Demonstration

SharePoint Demonstration SharePoint Demonstration Was zeigt die Demonstration? Diese Demonstration soll den modernen Zugriff auf Daten und Informationen veranschaulichen und zeigen welche Vorteile sich dadurch in der Zusammenarbeit

Mehr

Web-Kürzel. Krishna Tateneni Yves Arrouye Deutsche Übersetzung: Stefan Winter

Web-Kürzel. Krishna Tateneni Yves Arrouye Deutsche Übersetzung: Stefan Winter Krishna Tateneni Yves Arrouye Deutsche Übersetzung: Stefan Winter 2 Inhaltsverzeichnis 1 Web-Kürzel 4 1.1 Einführung.......................................... 4 1.2 Web-Kürzel.........................................

Mehr

Vermeiden Sie es sich bei einer deutlich erfahreneren Person "dranzuhängen", Sie sind persönlich verantwortlich für Ihren Lernerfolg.

Vermeiden Sie es sich bei einer deutlich erfahreneren Person dranzuhängen, Sie sind persönlich verantwortlich für Ihren Lernerfolg. 1 2 3 4 Vermeiden Sie es sich bei einer deutlich erfahreneren Person "dranzuhängen", Sie sind persönlich verantwortlich für Ihren Lernerfolg. Gerade beim Einstig in der Programmierung muss kontinuierlich

Mehr

Softwaretests in Visual Studio 2010 Ultimate Vergleich mit Java-Testwerkzeugen. Alexander Schunk Marcel Teuber Henry Trobisch

Softwaretests in Visual Studio 2010 Ultimate Vergleich mit Java-Testwerkzeugen. Alexander Schunk Marcel Teuber Henry Trobisch Softwaretests in Visual Studio 2010 Ultimate Vergleich mit Java-Testwerkzeugen Alexander Schunk Henry Trobisch Inhalt 1. Vergleich der Unit-Tests... 2 2. Vergleich der Codeabdeckungs-Tests... 2 3. Vergleich

Mehr

Workshop Java Webentwicklung Tapestry. Ulrich Stärk

Workshop Java Webentwicklung Tapestry. Ulrich Stärk Workshop Java Webentwicklung Tapestry Ulrich Stärk Webanwendungen Antwort im Browser des Benutzers sichtbar Anfrage geht ein Antwort rendern Anfrage an passenden Code weiterleiten 2 Servlets Servlet wird

Mehr

Softwareentwicklungspraktikum Sommersemester 2007. Feinentwurf

Softwareentwicklungspraktikum Sommersemester 2007. Feinentwurf Softwareentwicklungspraktikum Sommersemester 2007 Feinentwurf Auftraggeber Technische Universität Braunschweig

Mehr

Some Software Engineering Principles

Some Software Engineering Principles David L. Parnas: Some Software Engineering Principles Marco Oppel 30.06.2004 Seminar Software-Architektur Institut für Informatik Humboldt Universität zu Berlin 1 Problemstellung Software Engineering Multi-Personen

Mehr

DB2 Kurzeinführung (Windows)

DB2 Kurzeinführung (Windows) DB2 Kurzeinführung (Windows) Michaelsen c 25. Mai 2010 1 1 Komponenten von DB2 DB2 bietet zahlreiche graphische Oberflächen für die Verwaltung der verschiedenen Komponenten und Anwendungen. Die wichtigsten

Mehr

Drei-Schichten-Architektur. Informatik B - Objektorientierte Programmierung in Java. Vorlesung 16: 3-Schichten-Architektur 1 Fachkonzept - GUI

Drei-Schichten-Architektur. Informatik B - Objektorientierte Programmierung in Java. Vorlesung 16: 3-Schichten-Architektur 1 Fachkonzept - GUI Universität Osnabrück Drei-Schichten-Architektur 3 - Objektorientierte Programmierung in Java Vorlesung 6: 3-Schichten-Architektur Fachkonzept - GUI SS 2005 Prof. Dr. F.M. Thiesing, FH Dortmund Ein großer

Mehr

Informationssystemanalyse Problemstellung 2 1. Trotz aller Methoden, Techniken usw. zeigen Untersuchungen sehr negative Ergebnisse:

Informationssystemanalyse Problemstellung 2 1. Trotz aller Methoden, Techniken usw. zeigen Untersuchungen sehr negative Ergebnisse: Informationssystemanalyse Problemstellung 2 1 Problemstellung Trotz aller Methoden, Techniken usw. zeigen Untersuchungen sehr negative Ergebnisse: große Software-Systeme werden im Schnitt ein Jahr zu spät

Mehr

Datenbank-Verschlüsselung mit DbDefence und Webanwendungen.

Datenbank-Verschlüsselung mit DbDefence und Webanwendungen. Datenbank-Verschlüsselung mit DbDefence und Webanwendungen. In diesem Artikel werden wir Ihnen zeigen, wie Sie eine Datenbank verschlüsseln können, um den Zugriff einzuschränken, aber trotzdem noch eine

Mehr

Es sollte die MS-DOS Eingabeaufforderung starten. Geben Sie nun den Befehl javac ein.

Es sollte die MS-DOS Eingabeaufforderung starten. Geben Sie nun den Befehl javac ein. Schritt 1: Installation des Javacompilers JDK. Der erste Start mit Eclipse Bevor Sie den Java-Compiler installieren sollten Sie sich vergewissern, ob er eventuell schon installiert ist. Gehen sie wie folgt

Mehr

Das Leitbild vom Verein WIR

Das Leitbild vom Verein WIR Das Leitbild vom Verein WIR Dieses Zeichen ist ein Gütesiegel. Texte mit diesem Gütesiegel sind leicht verständlich. Leicht Lesen gibt es in drei Stufen. B1: leicht verständlich A2: noch leichter verständlich

Mehr

Beispiel Shop-Eintrag Ladenlokal & Online-Shop im Verzeichnis www.wir-lieben-shops.de 1

Beispiel Shop-Eintrag Ladenlokal & Online-Shop im Verzeichnis www.wir-lieben-shops.de 1 Beispiel Shop-Eintrag Ladenlokal & Online-Shop. Als Händler haben Sie beim Shop-Verzeichnis wir-lieben-shops.de die Möglichkeit einen oder mehrere Shop- Einträge zu erstellen. Es gibt 3 verschiedene Typen

Mehr

Meet the Germans. Lerntipp zur Schulung der Fertigkeit des Sprechens. Lerntipp und Redemittel zur Präsentation oder einen Vortrag halten

Meet the Germans. Lerntipp zur Schulung der Fertigkeit des Sprechens. Lerntipp und Redemittel zur Präsentation oder einen Vortrag halten Meet the Germans Lerntipp zur Schulung der Fertigkeit des Sprechens Lerntipp und Redemittel zur Präsentation oder einen Vortrag halten Handreichungen für die Kursleitung Seite 2, Meet the Germans 2. Lerntipp

Mehr

Objektbasierte Entwicklung

Objektbasierte Entwicklung Embedded Software Objektbasierte Entwicklung Objektorientierung in C? Prof. Dr. Nikolaus Wulff Objektbasiert entwickeln Ohne C++ wird meist C im alten Stil programmiert. => Ein endlose while-schleife mit

Mehr

Datensicherung. Beschreibung der Datensicherung

Datensicherung. Beschreibung der Datensicherung Datensicherung Mit dem Datensicherungsprogramm können Sie Ihre persönlichen Daten problemlos Sichern. Es ist möglich eine komplette Datensicherung durchzuführen, aber auch nur die neuen und geänderten

Mehr

Albert HAYR Linux, IT and Open Source Expert and Solution Architect. Open Source professionell einsetzen

Albert HAYR Linux, IT and Open Source Expert and Solution Architect. Open Source professionell einsetzen Open Source professionell einsetzen 1 Mein Background Ich bin überzeugt von Open Source. Ich verwende fast nur Open Source privat und beruflich. Ich arbeite seit mehr als 10 Jahren mit Linux und Open Source.

Mehr