+ All Categories
Home > Documents > Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung...

Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung...

Date post: 30-Jul-2020
Category:
Upload: others
View: 0 times
Download: 0 times
Share this document with a friend
75
Institut für Informatik Fachgebiet Softwaretechnik Warburger Str. 100 33098 Paderborn Analyse, Redesign und Refactoring einer Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner Roonstr. 12 32105 Bad Salzuflen vorgelegt bei Prof. Dr. Wilhelm Schäfer und Prof. Dr. Gitta Domik Paderborn, Februar 2008
Transcript
Page 1: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Institut für InformatikFachgebiet Softwaretechnik

Warburger Str. 10033098 Paderborn

Analyse, Redesign und Refactoring einer Computergrafik-Anwendung

Bachelorarbeitzur Erlangung des Grades

Bachelor of Sciencefür den Studiengang Informatik

von

Jan-Hendrik GöllnerRoonstr. 12

32105 Bad Salzuflen

vorgelegt beiProf. Dr. Wilhelm Schäfer

undProf. Dr. Gitta Domik

Paderborn, Februar 2008

Page 2: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner
Page 3: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Erklärung

Ich versichere, dass ich die Arbeit ohne fremde Hilfe und ohne Benutzung anderer als der angegebenen Quellen angefertigt habe und dass die Arbeit in gleicher oder ähnlicher Form noch keiner anderen Prüfungsbehörde vorgelegen hat und von dieser als Teil einer Prüfungsleistung angenommen worden ist. Alle Ausführungen, die wörtlich oder sinngemäß übernommen worden sind, sind als solche gekennzeichnet.

___________________ _____________________Ort, Datum Unterschrift

Page 4: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner
Page 5: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Inhalt

1 Einleitung..............................................................................................................1

1.1 Problemstellung.............................................................................................2

1.2 Lösungsansatz................................................................................................2

1.3 Struktur der Arbeit.........................................................................................3

2 Grundlagen............................................................................................................5

2.1 Volume Studio...............................................................................................5

2.2 Entwurfsmuster..............................................................................................8

2.3 Designmängel................................................................................................9

2.4 Refactoring..................................................................................................10

3 Analyse von Software zur Rückgewinnung ihres Designs..................................11

3.1 Erkennen von Komponenten und Abhängigkeiten......................................11

3.2 Erarbeiten von Komponenten aus dem Quellcode......................................13

3.2.1 Werkzeuge............................................................................................143.2.2 Erarbeiten der Klassenstruktur............................................................17

3.2.3 Zuordnen von Klassen zu Komponenten.............................................21

3.3 Analyse von Volume Studio........................................................................22

3.3.1 Erkennen von Komponenten und Abhängigkeiten..............................223.3.2 Erarbeiten der Komponenten aus dem Quellcode...............................24

3.3.2.1 Klassenstruktur.............................................................................243.3.2.2 Komponenten...............................................................................26

3.3.3 Gesamtbild...........................................................................................32

3.4 Zusammenfassung.......................................................................................33

4 Behebung von Designmängeln...........................................................................35

4.1 Beseitigung ungewollter Abhängigkeiten....................................................35

4.1.1 Verlagern und Umkehren von Abhängigkeiten....................................354.1.2 Anwendung des Observer Patterns......................................................36

4.2 Verfeinerung groben Designs......................................................................37

4.3 Zusammenfassung.......................................................................................42

5 Entwurf einer neuen Architektur.........................................................................43

5.1 Architekturanforderungen............................................................................43

5.2 Ansätze für Redesignverfahren....................................................................45

5.3 Redesign von Volume Studio......................................................................46

5.3.1 Komponenten.......................................................................................47

Page 6: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

5.3.2 Gesamtbild...........................................................................................57

5.4 Das Pluginsystem........................................................................................585.4.1 Konzept................................................................................................58

5.4.1.1 Der Pluginmanager......................................................................595.4.1.2 Die Pluginschnittstelle.................................................................61

5.4.2 Implementierungsdetails......................................................................615.4.2.1 Identifizierung von Plugins und Schnittstellen............................615.4.2.2 Benutzeroberfläche des Pluginmanagers.....................................62

5.5 Zusammenfassung.......................................................................................63

6 Zusammenfassung und Ausblick.........................................................................64

Verwandte Arbeiten...............................................................................................65

Literaturverzeichnis...............................................................................................66

Anhang..................................................................................................................69

Page 7: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

1 Einleitung

1 Einleitung

Aufgrund hoher Entwicklungskosten wird Software heute häufig weiter statt neu entwickelt. Hohe Erweiterbarkeit ist daher eine Designanforderung vieler Softwareprojekte. Die Weiterentwicklung von Anwendungen bringt aber auch oft die Notwendigkeit mit sich, bestehenden Quellcode zu ändern. Mit dem Quellcode ändert sich nicht selten auch die Struktur der Software und die Dokumentation des Programms hält nur bei den disziplinierteren Entwicklern mit diesen Änderungen Schritt. Häufig wird die Dokumentation aus Zeitmangel nur im Mindestmaß oder gar nicht durchgeführt.

Software, die längere Zeit in Entwicklung ist, mehrmals erweitert wurde, struk-turelle Änderungen erfahren hat, und ohne dokumentiertes Design daherkommt, bedeutet ein Problem. Einerseits sind Entwickler, die das Projekt nicht haben „aufwachsen“ sehen, mit der Einarbeitung in selbiges dadurch stärker ausgelastet als erwünscht und verstehen oft doch nur Teile des Programms. Andererseits sind selbst erfahrene Projektmitglieder häufig nicht mehr in der Lage, die Designideen von vor einigen Jahren klar nachvollziehen zu können. Sollte es darauf hinauslaufen, dass keiner der Beteiligten mehr die Struktur der entwickelten – und weiter zu entwickelnden – Software durchschaut, kann dies das vorzeitige Ende des Projekts bedeuten, denn wenn das Verständnis für das Programm bei den Entwicklern mit zunehmender Zahl von Änderungen sinkt, wird die Entwicklung ins Stocken geraten und schließlich zum Stillstand kommen. Hinzu kommt, dass Programmteile, dessen Nutzen niemand versteht, auch oft nicht entfernt werden, aus Angst, es könnte etwas anderes nicht mehr funktionieren. So sammelt sich überflüssiger oder überflüssig komplexer Quellcode in der Anwendung und die Software wird zunehmend undurchschaubarer.

Bevor dies eintritt ist es ratsam gegenzusteuern. In dieser Arbeit wird eine durch Studenten der Universität Paderborn im Rahmen wissenschaftlicher Arbei-ten entstandene Anwendung vorgestellt, dessen weitgehend unkontrolliert ge-wachsene Struktur für die Entwickler zunehmend zum Problem wird. Die bishe-rigen Erweiterungen wurden meist getätigt, ohne das Gesamtsystem im Auge zu behalten. Wichtigste Qualität der Anwendung war bisher, dass sie schlicht funktioniert. Inzwischen ist sie jedoch in einem Stadium angelangt, in dem eine große Zahl von Abhängigkeiten und Seiteneffekten innerhalb der Programmstruk-tur die Weiterentwicklung empfindlich stören.

Eine Restrukturierung ist nötig um die Erweiterbarkeit der Software zu ge-währleisten. Da alle Dokumentation des Programms in den Köpfen der Entwickler steckt, statt auf entsprechenden Dokumenten verfügbar zu sein, ist jedoch zu-nächst eine Analyse der Software nötig, um ihr Design zurück zu gewinnen.

Ist das Design bekannt, kann darin nach Mängeln gesucht werden. Im Rahmen eines Redesigns der Anwendung werden die schwerwiegendsten Designmängel beseitigt und eine neue Architektur etabliert, die ein Pluginkonzept umsetzt, dass die Erweiterbarkeit in Zukunft sicherstellen soll.

1

Page 8: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Einleitung

1.1 Problemstellung

Insbesondere im akademischen Umfeld entstandene Software startet ihren Weg ins Leben häufig mit Prototypcharakter, also ohne große Planung der Architektur und nur mit dem Ziel, die Umsetzbarkeit einer Idee zu zeigen. Im Idealfall wird der Prototyp, nachdem der Mehrwert seiner Funktionalität erwiesen ist, nochmals als von Grund auf neu gestaltete Software umgesetzt. Es kommt aber auch vor, dass die Entwicklung schlicht direkt mit dem Prototypen fortgeführt, der Prototyp also für den produktiven Einsatz weiterentwickelt wird. Volume Studio ist so ein Programm.

Volume Studio ist eine monolithisch gewachsene Software, die einen ernst-haften Nutzen in ihrem Anwendungsbereich – der Medizin – anstrebt. Viele der Funktionen werden von Studenten der Universität Paderborn im Rahmen von Studien- oder sonstigen Arbeiten erstellt. Das bedeutet eine gewisse Fluktuation von Entwicklern und eine eher schubweise Entwicklung.

An einigen Stellen im Quellcode finden sich Merkmale, die auf eine „Quick and Dirty“ Programmierung hindeuten. Dieser Umstand zieht sich durch die gesamte Codebasis und macht auch vor der Architektur der Anwendung nicht halt. Inzwischen hat die Software einen Umfang erreicht, bei dem das undurchdachte Design zum gefährlichen Problem wird. Erweiterungen werden zunehmend schwieriger und Änderungen ziehen ungewollte Seiteneffekte mit sich, welche die Entwicklung ausbremsen.

1.2 Lösungsansatz

Um diesen Zustand zu ändern, ist die monolithische Struktur der Anwendung aufzubrechen und zu modularisieren. Bevor dies geschehen kann, muss die Soft-ware analysiert werden. Das jetzige Design muss bekannt sein, damit es in ein anderes überführt werden kann. Außerdem sind Designmängel aufzudecken, die der Designqualität schaden und es müssen Wege entwickelt werden, diese zu be-heben.

Da eine Architektur bestehend aus funktionalen Komponenten angestrebt wird, ist auch jeweils die Funktionalität zu ermitteln, die eine Komponente ausmacht. Während des Redesigns der Anwendung wird die Architektur dann derart ausge-arbeitet, dass sie die Erweiterbarkeit der Software durch ein Pluginsystem ermöglicht.

Das Pluginsystem erlaubt, dass in Zukunft funktionale Erweiterungen der Anwendung als Plugins entwickelt werden können, idealerweise ohne den Code der übrigen Komponenten ändern zu müssen. Dazu sind geeignete Schnittstellen zu definieren, die es Komponenten ermöglichen, miteinander zu interagieren, ohne die konkrete Implementierung ihres Gegenübers zu kennen. Dies soll sicher stellen, dass der Aufwand zur Erweiterung der Anwendung um eine Funktionalität nicht wie bisher mit der Größe der Software wächst.

2

Page 9: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

1.3 Struktur der Arbeit

1.3 Struktur der Arbeit

Kapitel zwei geht zunächst auf einige Grundlagen ein, die im Verlauf dieser Arbeit hilfreich sein werden. In Kapitel drei wird ein Verfahren erarbeitet, nach dem die zu Grunde liegende Software bezüglich ihrer Struktur analysiert werden kann. Dabei wird der Problembereich beschrieben, Methoden und Werkzeuge, welche zur Lösung beitragen könnten, vorgestellt und schließlich die konkrete Analyse von Volume Studio durchgeführt. Die Analyse wird auch diverse Designmängel zum Vorschein bringen. Das vierte Kapitel diskutiert daher die Beseitigung einiger ausgewählter Designmängel. Dieses Wissen hilft im darauffolgenden fünften Kapitel, das Redesign durchzuführen. Volume Studio erhält eine neue modulare Architektur, die ein Pluginkonzept umsetzt und dadurch die Erweiterbarkeit der Anwendung sicherstellt.

3

Page 10: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Einleitung

4

Page 11: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

2 Grundlagen

2 Grundlagen

In diesem Kapitel soll zunächst Volume Studio vorgestellt werden, die Anwendung, mittels derer die Theorie praktisch umgesetzt wird. Außerdem werden einige Grundlagen zu Entwurfsmustern, Designmängeln und der Begriff Refactoring erläutert.

2.1 Volume Studio

Die Anwendung, die wie in der Einleitung geschildert analysiert und mit einer neuen Architektur versehen werden soll, heißt Volume Studio und ist ein im Fach-bereich Computergrafik entstandenes Programm zur Visualisierung von CT, PET und MRT-Daten1. Es wurde in der Programmiersprache C++ entwickelt.

Kernfunktion ist die dreidimensionale Darstellung dieser Daten durch Volume Rendering Techniken. Ein Volumen ist in diesem Fall ein dreidimensionales Gitter, bei dem jeder Knotenpunkt des Gitters eine Farbe und Transparenz besitzt. Die einzelnen Punkte des Gitters nennt man Voxel (kurz für „volumetric pixel“). Man kann sich ein solches Volumen auch als eine dreidimensionale Textur vor-stellen. Der Vorteil dieser Technik ist, dass der Aufwand zur Darstellung eines Objektes nicht mehr von der Komplexität des Objektes abhängt, sondern lediglich von der Größe des Voxelgitters (also der Auflösung der dreidimensionalen Textur) Näheres zu Volume Rendering ist zu finden in [AMH02, S. 342ff] und [WE02].

1 Hinter den Abkürzungen verbergen sich Computertomographie, Positronenemissionstomo-graphie und Magnetresonanztomographie, Methoden zur Gewinnung medizinischer Daten.

5

Abbildung 2.1: Ein von Volume Studio (Revision 84) gezeichnetes Volumen.

Page 12: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Grundlagen

Die Art und Weise, wie ein Volumen in Volume Studio dargestellt wird, lässt sich auf verschiedene Weisen verändern. Es können Querschnitte gebildet oder Bereiche des Volumens bestimmt werden, die sich unterschiedlich einfärben oder auch ein- oder ausblenden lassen. Neben Volumen, kann Volume Studio auch poly-gonale Objekte (Meshes) darstellen, allerdings nicht mit den gerade genannten Möglichkeiten, welche die Volumendarstellung bietet.

Bevor im nächsten Kapitel mit der Analyse des Programms begonnen wird, möchte ich das Problem, welches überhaupt zu dieser Arbeit geführt hat, noch an einem Beispiel erläutern. Wollte man Volume Studio erweitern, musste man bisher zumeist an mehreren Stellen im Quellcode Veränderungen vornehmen. Je nach Umfang und Art der Erweiterung musste man den vorhandenen Code der Anwendung mehr oder weniger gut kennen. Die Tendenz geht dabei eher zu mehr, denn mit jeder Erweiterung wird die Codebasis komplexer und es müssen mehr und mehr Seiteneffekte berücksichtigt werden.

Ein Beispiel für eine Recht umfangreiche Erweiterung ist die Einführung von sogenannten CrossSections (im SVN Repository als Revision 52 zu finden). Dies sind Querschnitte durch das dargestellte Volumen entlang der drei Koordinaten-achsen, die es ermöglichen, scheibchenweise in das Volumen hinein zu sehen.

Um diese Querschnitte technisch umzusetzen, musste der Code an zahlreichen Stellen erweitert werden. Ein tiefer Eingriff in den für das Rendering der Volumen zuständigen Programmteil war nötig, damit dieser nur die im Querschnitt darzu-stellenden Hälften des Volumens zeichnet. Der Benutzeroberfläche wurde ein wei-teres Fenster hinzugefügt, mit dem die Querschnitte verschoben und andere Ein-stellungen vorgenommen werden können (siehe Abbildung 2.2). Zwei weitere Änderungen waren dafür nötig, einerseits um dieses Fenster beim Programmstart zu Erzeugen und andererseits um es dem Menü des Hauptfensters hinzuzufügen. Eine dritte Änderung betraf einen anderen Teil von Volume Studio. Zum Zeitpunkt der Einführung der CrossSections gab es bereits Funktionalität zur Segmentierung von Volumen.

Durch verschiedene Segmentierungsalgorithmen lassen sich Gewebearten her-ausfiltern und unabhängig von einander färben oder schlicht ein- oder ausblenden. Der Benutzer kann sich so zum Beispiel ausschließlich knöchernes Gewebe anzeigen lassen. Werden auf diese Weise Teile des Volumens ausgeblendet, sollten

6

Abbildung 2.2: Querschnitte des Volumens.

Page 13: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

2.1 Volume Studio

sie auch in den Querschnitten nicht mehr vorkommen, so dass vom Programmteil der Segmentierung aus die Querschnitte dazu gebracht werden müssen, sich zu erneuern, um korrekte Ergebnisse darzustellen. Derjenige Entwickler, der die CrossSections implementiert hat, musste also auch den Code für die Segmentierung entsprechend kennen, um ihn schließlich zu modifizieren.

Die Abbildung 2.3 zeigt das obige Volumen erneut sowie einige Querschnitte. Die in der vorhergehenden Abbildung blau dargestellte Luft wurde durch einen Segmentierungsalgorithmus herausgefiltert und vom Benutzer ausgeblendet.

Dieses Beispiel soll einerseits verdeutlichen, dass ohne profunde Kenntnisse des Programms neue Funktionalität nicht immer ohne Weiteres hinzugefügt werden kann. Andererseits sollte aber auch ersichtlich sein, dass genau das das Problem ist, welches Volume Studio zur Zeit hat. Die Erweiterung der Anwendung wird zunehmend schwieriger. Jedes Mal, wenn in bestehendem Code Änderungen

7

Abbildung 2.3: Volumen (oben rechts) und Querschnitte (unten), wobei die umge-bende Luft ausgeblendet wurde.

Page 14: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Grundlagen

vorgenommen werden, um neuen einzubinden, müssen sich schlimmstenfalls alle am Projekt arbeitenden Entwickler mit diesen Änderungen vertraut machen, weil sie potentiell ihre eigene Arbeit beeinflussen könnten. Mit steigender Zahl solcher Veränderungen wird der ursprüngliche Zweck eines Codefragments (oder einer Funktion/einer Klasse) zunehmend verwässert und die Arbeit am Projekt schwie-riger. Neue Mitarbeiter, die vielleicht nur Funktion X oder Y implementieren sollen, müssen weite Teile der aktuellen Quellen für sich verständlich aufbereiten, um überhaupt arbeiten zu können.

Das neu zu entwickelnde Design von Volume Studio soll dieses Problem lösen, indem es eine klare Modularisierung vorsieht, welche die Komponenten des Pro-gramms entkoppelt und letztlich austauschbar macht. Entwickler einzelner Modu-le sollen nur noch die für sie relevanten Schnittstellen kennen müssen und nicht mehr einen Großteil des Programms.

2.2 Entwurfsmuster

Entwurfsmuster (englisch Design Patterns) stellen bewährte Konzepte zur Lö-sung bestimmter wiederkehrender Entwurfsprobleme dar. Bekannt geworden sind sie vor Allem durch das gleichnamige Werk von Gamma et al. [GHJV96]. Für diese Arbeit relevante Beispiele sind die Entwurfsmuster Beobachter (Observer) und Zuständigkeitskette (Chain of Responsibility), die etwas detaillierter auch in [GHJV96] beschrieben sind.

Ersteres beschreibt, wie Objekte (die Beobachter) über den Zustand anderer Objekte auf dem Laufenden gehalten werden können, indem jene sie über Zu-standsänderungen informieren. Durch Verwendung von Schnittstellen, welche die eigentliche Identität der Beobachter verbergen, kann das beobachtete Objekt sol-che Zustandsänderungen bekannt geben, ohne nähere Details über seine Kom-munikationspartner wissen zu müssen. Weiterhin sieht das Muster vor, dass sich Beobachter dynamisch bei ihrem Zielobjekt an- und abmelden können.

Eine Zuständigkeitskette wiederum bezeichnet eine Reihe von Objekten, die für die Lösung eines Problems aus einer gegebenen Problemmenge gedacht sind. Die Objekte behandeln verschiedene konkrete Probleme aus dieser Menge. Sie sind in einer Kette organisiert, in der jedes Objekt entweder das gegebene Problem löst, oder es – falls es nicht dafür zuständig ist – an das nächste Objekt weitergibt. Hierdurch kann die Menge der lösbaren Probleme erweitert werden, indem schlicht ein weiteres Objekt der Kette hinzugefügt wird. Ein mögliches

8

Abbildung 2.4: Das Beobachter Muster.

Page 15: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

2.2 Entwurfsmuster

Einsatzgebiet für eine Zuständigkeitskette ist beispielsweise die Behandlung verschiedener Dateitypen in einer Anwendung. Um einen neuen Dateitypen zu unterstützen, ist es ausreichend, ein entsprechendes Glied an die Kette anzuhängen, ohne dass bestehende Glieder geändert werden müssen.

Beim Entwurf des neuen Designs für Volume Studio werden an geeigneten Stellen derartige Entwurfsmuster angewendet. Außer ihrer bewährten Funktion bergen sie noch den Vorteil, vielen Softwareentwicklern bekannt zu sein, so dass Designdetails leicht von ihnen nachvollzogen werden können, wenn ein geläu-figes Muster erkannt wird.

2.3 Designmängel

Ein erfahrener Softwareentwickler erkennt viele Designmängel, wenn er sie vor sich sieht (außer natürlich im eigenen Code...). Inzwischen haben sie auch Namen. Weit verbreitet sind so genannte Bad Smells [Fow99] und Anti-Patterns [BMMM98].

Bad Smells sind Codeabschnitte, die im übertragenen Sinne bereits beim bloßen Hinsehen nach schlechtem Design riechen. Beispiele wären unüber-schaubar lange Funktionsrümpfe, Mammutklassen oder Codeabschnitte mit extensiver Nutzung bedingter logischer Ausdrücke. Bekannt wurde der Begriff durch das Buch Martin Fowlers über Refactoring [Fow99], ein Thema, auf das im nächsten Abschnitt eingegangen wird.

Anti-Patterns sind das Gegenstück zu Entwurfsmustern, also Negativmuster für häufig vorkommende falsche Problemlösungen. Ein Beispiel wäre das Vorhanden-sein einer Gottklasse, also einer Klasse, die nahezu die gesamte Funktionalität der Anwendung enthält. Anti-Patterns beschäftigen sich meist mit Problemen auf Design- oder Architekturebene, während Bad Smells eher Mängel in der Imple-mentierung beschreiben. Eine Einführung in das Thema Anti-Patterns ist das gleichnamige Buch von Brown, Malveau, McCormick III und Mowbray [BMMM98]. Ein Anti-Pattern beschreibt generisch einen schlechten Zustand und wie man ihn beheben kann.

Diese Arbeit wird sich nicht all zu sehr mit den verschiedenen Anti-Pattern, wie sie heißen und wo sie vorkommen, befassen. Wohl aber wird während der kommenden Analyse an geeigneter Stelle darauf hinweisen, wenn ein nennens-werten Designmangel entdeckt wurde.

9

Abbildung 2.5: Eine Zuständigkeitskette.

Page 16: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Grundlagen

2.4 Refactoring

Als Refactoring bezeichnet man Änderungen am Quellcode, die nur die innere Struktur eines Programms betreffen, nicht seine Funktionalität. Beispiele sind das Extrahieren einer Methode aus einer größeren Methode oder das Bewegen von Code in eine andere Klasse. Martin Fowler schrieb ein Buch über Refactoring, dass auch einen Katalog vieler einzelner Refactorings enthält [Fow99]. Diesen gibt es in aktualisierter und erweiterter Form auch im Internet auf der von Fowler betreuten Seite www.refactoring.com.

Interessant ist an Refactorings, dass sie sich in kleinste Schritte zerlegen lassen, die häufig automatisierbar sind. Das bedeutet, es ist möglich Werkzeuge zu entwerfen, denen man nur noch sagen muss, was für ein Refactoring sie durchfüh-ren sollen, aber nicht wie. Leider ist das Angebot an Refactoringwerkzeugen zu-mindest für die Programmiersprache C++ recht überschaubar und diejenigen, die es gibt, sind meist Plugins für bestimmte Entwicklungsumgebungen.

Unter anderem wären da Refactor!2 und Visual Assist X3 für Microsoft Visual Studio, die ich in Ermangelung dieser Entwicklungsumgebung nicht testen konnte (zur kostenlosen Express Version sind die Plugins nicht kompatibel). Für Emacs/XEmacs gibt es Xrefactory4, dass allerdings nur eine kleine handvoll Refactorings unterstützt. Das an der Hochschule Rapperswil (Schweiz) ent-standene Refactoringplugin5 für eclipse fiel wiederum dadurch auf, dass es sehr langsam ist, da es bei jeder Benutzung den Code neu einliest und letztlich immer mit einer Fehlermeldung aufgab. In dieser Arbeit wurde schließlich auf solche Werkzeuge verzichtet und Änderungen manuell vorgenommen.

2 http://www.devexpress.com/Products/NET/IDETools/Refactor/3 http://www.wholetomato.com/4 http://www.xref-tech.com/5 http://www.ifs.hsr.ch/Projects/Projects/C_Refactorings

10

Page 17: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

3 Analyse von Software zur Rückgewinnung ihres Designs

3 Analyse von Software zur Rückgewinnung ihres Designs

Das endgültige Ziel ist, für Volume Studio eine modulare Architektur zu entwi-ckeln und dadurch die Erweiterbarkeit des Programms zu erhöhen. Erweiterungen sollen realisierbar sein, ohne alle Teile der Software anpassen zu müssen. Die Mo-dule der zu entwerfenden Architektur sollen also jeweils eine Funktionalität (oder mehrere eng verwandte Funktionalitäten) der Anwendung kapseln.

Damit ein Redesign überhaupt durchgeführt werden kann, ist zunächst ein Reverse Engineering des Programms notwendig, um das momentane Design der Anwendung in Erfahrung zu bringen. Eine gängige Definition des Begriffs Reverse Engineering in diesem Zusammenhang ist die von Chikofski und Cross: „Reverse engineering is the process of analyzing a subject system to (i) identify the system's components and their interrelationships and (ii) create representa-tions of the system in another form or at a higher level of abstraction“ [CC90].

In diesem Kapitel werden also die im bisherigen Design vorhandenen Komponenten identifiziert. Nachdem diese bekannt sind, geht es daran herauszu-finden, wie sie miteinander interagieren. Nötige und unnötige Abhängigkeiten sollen erkannt werden, denn je mehr Abhängigkeiten es im System gibt, desto schwieriger ist seine Handhabung für die damit arbeitenden Entwickler. Außerdem sind Designmängel aufzudecken, welche die Erweiterbarkeit von Volume Studio einschränken oder die Weiterentwicklung erschweren.

3.1 Erkennen von Komponenten und Abhängigkeiten

Es gibt einige Quellen, um die in einer Software vorhandenen Komponenten zu erfahren. Im Idealfall existieren hierzu entsprechende Designdokumente oder die Entwickler des Programms können selbst dazu Auskunft geben. Ist man ge-zwungen ohne diese Hilfen auszukommen, sprich es steht nur der Quellcode zur Verfügung, muss man sich die in der Anwendung vorhandenen Komponenten selbst aus diesem erarbeiten. In allem Fällen ist zunächst zu unterscheiden zwi-schen programmeigenen und externen Komponenten, wie beispielsweise Pro-grammbibliotheken von Drittanbietern. Diese Abhängigkeiten sind in der Regel am einfachsten zu erfahren.

Im Falle von C/C++ lässt sich durch einen Blick ins Makefile in Erfahrung bringen, welche Bibliotheken statisch oder dynamisch beim Programmstart einge-bunden werden6. Etwas schwieriger wird es, wenn die Anwendung Objekte dyna-misch zur Laufzeit lädt. Hierfür kann man nach Funktionsaufrufen zu suchen, die diesen Job erledigen7.

6 In der Linuxwelt können auch mit dem Tool ldd die dynamischen Abhängigkeiten einer aus-führbaren Datei erfragt werden.

7 Gängige Funktionen zum Laden von Bibliotheken während der Laufzeit sind beispielsweise LoadLibrary unter Windows, dlopen unter Unix oder, falls wie in Volume Studio Qt genutzt wird, das Objekt QLibrary.

11

Page 18: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Analyse von Software zur Rückgewinnung ihres Designs

Nun zu den programmeigenen Komponenten. Diese können sich außer durch ihre Kapselung in eigenständigen Bibliotheken durch verschiedene Namensberei-che im Quellcode oder eine bestimmte Ordnerstruktur des Repositorys bemerkbar machen. Manche Entwicklungsumgebungen – zum Beispiel Microsoft Visual Studio – bieten außerdem eine eigenständige Projektverwaltung unabhängig von der tatsächlichen Verzeichnisstruktur an. Daher macht es Sinn im Repository auch nach Projektdateien für eine solche Entwicklungsumgebung Ausschau zu halten.

Nach der Erkennung der vorhandenen Komponenten, sind die Interaktionen zwischen ihnen zu betrachten. Strukturschwächen in einem Programm lassen sich häufig auf schlecht gewählte Kommunikationswege zurück führen. So kennen Komponenten andere Komponenten, die sie nicht kennen sollen, zum Beispiel weil sie Funktionalität besitzen, die eigentlich der anderen gebührt. Um solche Mängel finden und beurteilen zu können, muss auch die Funktionalität der Komponenten bekannt sein, die dabei als Black Box wahrgenommen werden können. Das heißt es ist bekannt welchen Input sie verlangen und welche Art von Ergebnissen sie daraufhin produzieren, aber die genaue Art und Weise, wie sie dies tun, ist nicht von Bedeutung.

Zusammengefasst sind also folgende Schritte durchzuführen:• Identifiziere die Komponenten.• Ermittle ihre Funktion.• Finde heraus, welche anderen Komponenten ihr bekannt sind.

Wenn eine Komponente keine eindeutige Schnittstelle oder keine eindeutige Funktion hat, ist sie ein Kandidat für ein Redesign. Als eindeutige Schnittstelle wird hier eine Menge von Klassen und Methoden verstanden, die genau die Funktionalität bereitstellt, welche die Komponente der Öffentlichkeit zugänglich machen will. Alle übrigen Klassen, die der Umsetzung dieser Funktionalität dienen, sollen nichtöffentlicher Natur sein.

Die Durchführung des Redesigns einer Komponente verlangt in der Regel die Offenlegung ihres internen Designs. Hierfür kann man die obigen Schritte für die enthaltenen Unterkomponenten bzw. Klassen durchführen. Im Falle von Klassen ist es manchmal einfacher, zuerst die Relationen zwischen ihnen zu ermitteln, be-vor man nach ihrer konkreten Funktion sucht, denn häufig wird eine Programm-funktionalität durch einen Verbund von Klassen realisiert. Es fällt dann leichter die Funktion einer Klasse korrekt zu benennen, wenn man weiß, in welchem Kon-text sie benutzt wird.

Es ist dringend anzuraten, während des gesamten Verlaufs der Analyse etwaige Auffälligkeiten zu notieren. Wenn man bei der Durchführung eines Schrittes der Analyse Probleme hat (etwa bei der Identifizierung von Komponenten oder der Benennung ihrer Aufgabe), muss das nicht am eigenen Unvermögen liegen, son-dern kann auch in der Unvollkommenheit der zu untersuchenden Software be-gründet sein, die es ja später zu beseitigen gilt.

12

Page 19: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

3.2 Erarbeiten von Komponenten aus dem Quellcode

3.2 Erarbeiten von Komponenten aus dem Quellcode

Den im vorhergegangenen Abschnitt als programmeigen bezeichneten Komponenten gilt das Hauptinteresse während der Analyse, da diese den Aus-gangspunkt für die neue Architektur bilden werden. Was aber, wenn die Anwendung keine solchen enthält, also wenn ihre momentane Architektur keine Modularisierung aufweist? In dem Fall müssen für das Redesign der Software die Komponenten erst noch gebildet werden.

Dieses Bilden von Komponente erscheint zu diesem Zeitpunkt sehr konstruktiv, dafür, dass es immer noch um die Analyse des Programms und noch nicht um das Redesign geht. Dennoch ist es als Teil der Analyse anzusehen, da zu diesem Zeit-punkt noch keine Änderungen am Quellcode vorgenommen werden und während dieser Arbeit auch grundlegender Funktionalitäten der Software festgestellt werden. Die so gefundenen Komponenten werden als Grundlage für die Erstel-lung der neuen Architektur dienen.

Das Feststellen grundlegender Funktionalitäten der Anwendung, die jeweils in Komponenten isoliert werden können, lässt sich in einer Computergrafik-Anwendung wie Volume Studio am besten bewerkstelligen, wenn man das Pro-gramm schlicht ausführt und alle durch die Benutzeroberfläche offerierten Möglichkeiten testet. Nachdem entschieden wurde, welche Funktionalitäten wel-che Komponenten bilden sollen, werden die Klassen im Quellcode der Anwendung bezüglich ihres Aufgabenbereichs betrachtet und einer dieser Komponenten zugeordnet.

Es ist auch möglich andersherum vorzugehen und zuerst die Klassenstruktur zu ermitteln, bevor Komponenten benannt werden. Hat man bereits ein Klassendia-gramm, sieht man darin eventuell Klassen, die aus der Menge herausstechen – etwa durch ihren Namen oder die Zahl ihrer Beziehungen zu anderen Klassen – und als charakteristisch für eine der zu bildenden Komponenten angesehen werden können. Auch kann es Sinn machen, sich nicht von vornherein auf eine Zahl von Komponenten festzulegen. So kann man zunächst nur eine Komponente benennen, ihr Klassen zuteilen und dann die Restmenge der Klassen betrachten. Zuletzt werden eventuell einige Klassen übrig bleiben, die sich nicht eindeutig zu ordnen lassen. In diesem Fall wurde ein Mangel im Design der Anwendung ent-deckt – oder es liegt ein Fehler bei der bisherigen Analyse vor.

Alternativ können Komponenten statt nach im Programm vorhandenen Funktionalitäten auch auf Basis rein struktureller Informationen gebildet werden. Es gibt Möglichkeiten durch Clusteringverfahren eine Modularisierung zu finden. Diese Verfahren versuchen in der Regel die Klassen bzw. Funktionen einer Soft-ware derart in Untermengen aufzuteilen, dass möglichst wenige Verbindungen zwischen diesen Mengen bestehen. Dieses Vorgehen kann auch auf großen Soft-wareprojekten angewandt werden, ohne dass der Durchführende die Anwendung im Detail kennen muss. Der Nachteil ist, dass durch die Nichtbeachtung der funktionalen Zusammenhänge Funktionalitäten über mehrere Module hinweg im-plementiert sein können, was nicht immer erwünscht ist. Mehr über Clusteringver-fahren findet sich in [MB07] und [Jer99].

Egal ob man sich entscheidet, Komponenten basierend auf Funktionen der Anwendung oder dessen Struktur zu bilden, in beidem Fällen muss auf

13

Page 20: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Analyse von Software zur Rückgewinnung ihres Designs

Klassenebene gearbeitet werden. Die Klassen und deren Beziehungen müssen be-kannt sein, so dass nach Zuordnung der Klassen zu den Komponenten – sei es ma-nuell oder durch ein Clusteringverfahren – auch die Beziehungen zwischen den Komponenten sichtbar sind. Um die Klassenstruktur der zu analysierende Softwa-re zu erhalten, ist es angebracht die Nutzung von Werkzeugen zu erwägen, die diese Arbeit erleichtern.

3.2.1 Werkzeuge

Der Begriff Reverse Engineering wird seit etwa 20 Jahren für den Vorgang benutzt Informationen über Programmeigenschaften aus Quellcode zu gewinnen und es gibt inzwischen einige Anwendungen in diesem Bereich, die auf verschie-denste Weisen arbeiten. In [CdiP07] werden die Fortschritte des Reverse Enginee-ring erläutert und die Anwendungen in drei Kategorien aufgeteilt: Programm-analyse, Designrückgewinnung und Softwarevisualisierung. Ich möchte mich dar-an anlehnen, wähle jedoch eine etwas andere Einteilung. Nach der Beschreibung der Arten von Reverse Engineering Werkzeugen soll feststehen, welche Werk-zeuge der in diesem Kapitel durchgeführten Analyse dienlich sind und welche nicht.

Fact Extractors

Bei Fact Extractors handelt es sich um Werkzeuge, die Fakten aus Code ge-winnen, in der Regel durch automatisierte Parser. Art und Menge dieser Fakten hängen in erster Linie von den Fähigkeiten des Parsers ab. Fakten können sein: Vorhandene Klassen und deren Beziehungen, aber auch Metriken wie die Anzahl der Codezeilen pro Klasse oder pro Methode. Solche Metriken erlauben das auf-spüren von Designmängeln. Wenn etwa eine Klasse gemessen an den anderen übermäßig viel Code besitzt, kann das als Hinweis auf eine mangelhafte Parti-tionierung des von ihr behandelten Funktionsbereichs hindeuten.

Wie viel der Benutzer mit den gewonnenen Fakten anfangen kann, hängt neben deren Menge auch von der Art ab, in der sie ihm präsentiert werden. In der Regel sind weitere Werkzeuge nötig, um die Ausgaben eines Fact Extractors aufzuberei-ten und beispielsweise als Diagramm darzustellen.

Nennenswerte Fact Extractors bzw. Toolkits, die solche beinhalten, wären unter anderen Columbus/CAN8 (siehe auch [FMBKT] und [FBTG]), SWAG Kit9 – ent-standen an der Universität Waterloo (Kanada) – und Rigi10 – entstanden an der Universität Victoria (Kanada).

Softwarevisualisierer

Eine weitere Art von Werkzeugen sind Softwarevisualisierer. Dieser recht weit gefasste Begriff beschreibt Werkzeuge, welche die statische und/oder die dyna-mische Struktur von Software graphisch darstellen, mit dem Ziel das Verständnis für die Funktionsweise eines Programms oder Programmteils zu erhöhen.

8 http://www.frontendart.com/products_col.php9 http://www.swag.uwaterloo.ca/index.html10 http://www.rigi.csc.uvic.ca/index.html

14

Page 21: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

3.2.1 Werkzeuge

In [BaDe04] wird eine Methode vorgestellt, große Softwarestrukturen hier-archisch und dreidimensional darzustellen. Der Benutzer kann sich zwischen den Komponenten bewegen und in sie hinein sehen. Dies soll helfen die statische Struktur einer Anwendung zu verstehen.

Die Möglichkeit die Dynamik eines Programms zu erfassen, indem zur Lauf-zeit Aufrufgraphen erstellt werden, soll wiederum den Entwickler unterstützen, eine bestimmte Funktionalität in großen Softwaresystemen zu lokalisieren, indem diese schlicht ausgeführt wird, während der Softwarevisualisierer die beteiligten Funktionsaufrüfe verfolgt und graphisch darstellt. Diese Technik ist erläutert in [BD06], [BD07] sowie [GLW06].

Version History Miners

Für die letzte nennenswerte Art von Werkzeugen gibt es bisher keine gängige Bezeichnung. Die von ihnen erfüllten Aufgaben werden beschrieben mit „Softwa-re Repository Mining“ (in [YR06]), „Release History Mining“ (in [FG06]) oder, wie ich zuletzt in den Fluren der Universität hörte, „Software Process Mining“. All diese Begriffe benennen einen sehr ähnlichen Prozess: das Gewinnen von In-formationen aus der Entstehungsgeschichte einer Software.

Viele Werkzeuge dieses Gebiets bedienen sich der Tatsache, das heute die meisten Softwareentwicklungsprozesse von Versionsmanagementsystemen wie CVS11 oder Subversion12 unterstützt werden. Die Evolution der zu untersuchenden Software kann dadurch oft bis zum Tag Eins ihrer Entstehung zurückverfolgt werden.

Diese Rückverfolgung ermöglicht das Feststellen stark zusammenhängender Codefragmente, etwa weil gewisse Teile des Codes immer gemeinsam geändert wurden oder weil der selbe Entwickler für sie verantwortlich ist. Es ist aber auch möglich die Entwicklung der Architektur der Software zu verfolgen – interessant, wenn etwa die Dokumentation über die Architektur nicht mit der Implementierung Schritt gehalten hat.

Weiterhin lassen sich einige Designschwächen aufdecken, wenn beispielsweise der Code einer Klasse in nahezu jeder neuen Version geändert wird, oder wenn eine Klasse kurz nach ihrer Einführung bereits wieder gelöscht wird. All dies kann auf Probleme beim Design der Software hindeuten. Näheres zu Werkzeugen, die solche und ähnliche Aufgaben erfüllen, ist zu finden in [FG06], [YR06] und [ZWDZ04].

Zurück zum gegebenen Problem. Die Struktur der vorliegenden Software soll verständlich gemacht werden und zwar auf Klassenebene. Am Ende soll für jede Klasse bekannt sein, mit welchen anderen Klassen sie in Beziehung steht, so dass, nachdem bekannt ist welcher Komponenten eine Klasse angehört, auf die Bezie-hungen zwischen den Komponenten rückgeschlossen werden kann. Im Idealfall erwartete ich daher von dem Werkzeug der Wahl, dass es aus dem vorhandenen Volume Studio Quellcode ein UML Klassendiagramm erstellt. Solch ein Dia-

11 http://www.nongnu.org/cvs/12 http://subversion.tigris.org/

15

Page 22: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Analyse von Software zur Rückgewinnung ihres Designs

gramm kann auch als Basis für das Redesign verwendet werden. Natürlich könn-ten andere in meiner Position andere Hilfsmittel bevorzugen. Es gilt nun ein Werkzeug zu finden, dass ein Klassendiagramm oder die Daten, die für dessen Er-stellung benötigt werden, liefern kann.

Softwarevisualisierer sind eher dazu gedacht, das Verständnis des Nutzers für das betrachtete Programm zu erhöhen. Das ist hilfreich, aber bei kleinen Pro-grammen wie Volume Studio kann man dieses Verständnis auch ohne solche Hilfs-mittel erlangen. Werkzeuge, welche die Evolution einer Software als Grundlage betrachten, dürften auch nicht groß helfen, da das Projekt noch recht jung ist, also keine lange Entwicklungsgeschichte aufweist. Die Werkzeuge der ersten Katego-rie scheinen am geeignetsten und ich habe daher die drei genannten getestet.

Columbus/CAN lieferte die besten Ergebnisse. Die erzeugten XMI Dateien (un-terstützt wird XMI 1.0 und XMI 1.1) konnten leider nicht erfolgreich in ein UML Modellierungswerkzeug importiert werden. Die getesteten Programme lieferten allesamt Fehlermeldungen beim lesen der Dateien. In [FBTG] wird über den XMI Export von Columbus erwähnt, dass diese Funktionalität noch unvollständig ist. Scheinbar ist diese Information in der getesteten Version 3.5 noch aktuell.

Der Fact Extractor von SWAG Kit weigerte sich beharrlich den Volume Studio Code zu lesen. Auch mit einem kleinen C++ Testprogramm kam er nicht zurecht, sondern nur mit dem Beispiel-C-Code von der SWAG Kit Internetseite. Im Fall von Rigi habe ich es lediglich geschafft einige bunte Quadrate auf den Schirm zu bekommen aber nichts, womit sich arbeiten ließe.

Bei der WCRE 2001 in Stuttgart wurde ein Vergleich verschiedener Reverse Engineering Werkzeuge vorgenommen, in dem auch die von mir getesteten in Er-scheinung getreten sind. Danach ergab sich, dass „[...] the general consensus was that many of our tools are not yet at the stage where they could be transferred to industry, and that some of them could only be effectively used by expert reverse engineers.“ [SSW03, S. 4]. Scheinbar ist auch das noch aktuell, denn ich bin sicher, dass bessere Ergebnisse möglich gewesen wären, wenn ich gewusst hätte, wie man die genannten Werkzeuge richtig bedient. Eine längere Einarbeitungszeit mit viel Ausprobieren und ungewissem Ausgang war nicht in meinem Interesse.

Außer den im akademischen Umfeld entstandenen habe ich noch einige weite-re, teils kommerzielle, teils freie Programme getestet, nämlich UML Modellierungswerkzeuge, die von sich behaupten Diagramme aus C++ Quellcode generieren zu können13. In der Tat lieferten die meisten getesteten Werkzeuge Ergebnisse, in der Art eines UML Klassendiagramms. Jedoch konnte keines den Anspruch, sämtliche Beziehungen zwischen Klassen zu finden, erfüllen. Meist waren die Programme zwar in der Lage Vererbungsbeziehungen und einige Asso-ziationen zu entdecken, aber eben nicht alle und die für mich wichtige Informati-on, welche Klasse nun von welcher anderen benutzt wird konnte keines in Gänze liefern.

Die meisten Details lieferte IBMs Rational Rose14, getestet in der Version 7.0.0 für UNIX/Linux. Dieses Programm der gehobenen Preisklasse fand viele Assozia-tionen zwischen den Klassen (aber nicht alle), aus denen sich bereits ein recht um-

13 Diese Anwendungen tun das in der Regel durch Parsen des Quellcodes, besitzen also Werk-zeuge, die zu den Fact Extractors gezählt werden können.

14 http://www-306.ibm.com/software/awdtools/developer/rose/index.html

16

Page 23: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

3.2.1 Werkzeuge

fangreiches Diagramm erstellen lies. Rose stellte aber auch viele Klassen dar, die für die Designrückgewinnung nicht von Belang sind, etwa Spezialisierungen ver-schiedener Templateklassen oder auch Klassen, die nur lokal in .cpp Dateien de-klariert waren. Ohne massive manuelle Nachbearbeitung ließen sich also auch hier keine befriedigenden Ergebnisse erzielen.

Im Großen und Ganzen war also kein Werkzeug in der Lage die Aufgabe des Reverse Engineering zu meiner Zufriedenheit zu erfüllen. Zwar waren einige in Teilen dazu fähig, aber die verbleibende Arbeit, der Aufwand sich ausreichend in die Werkzeuge einzuarbeiten, sowie die Frage, ob die automatisch generierten Ergebnisse auch tatsächlich korrekt sind, ließen mich zu dem Schluss kommen, die restliche Analyse besser manuell vorzunehmen.

3.2.2 Erarbeiten der Klassenstruktur

Im Folgenden werden die im Code vorhandenen Klassen untersucht, ihre Auf-gaben sowie ihre Beziehungen erarbeitet, um sie letztlich Komponenten zuordnen zu können, die als Grundlage für die neue, modulare Architektur der Anwendung dienen werden.

Identifizieren von Klassen

Um die Klassen aus dem Quellcode in Komponenten zu gruppieren, muss zu-nächst bekannt sein, welche Klassen überhaupt vorhanden sind. Sie lassen sich leicht aus den Headerdateien namentlich heraus lesen, ebenso wie deren Basis-klassen, falls vorhanden. Diese Information reicht bereits aus um eine Vererbungs-hierarchie aufzustellen, die für sich allein jedoch noch nicht viel über die Pro-grammstruktur aussagt. Man kann beim Auslesen der Klassen auch gleich eine weitere Klassifizierung vornehmen und so eine zusätzliche Information gewinnen:

• Besitzt die Klasse ausschließlich rein virtuelle Methoden15 und keine Attribute? Dann stellt sie mit größter Wahrscheinlichkeit ein Interface dar.

• Sind einige Methoden implementiert, oder besitzt sie Attribute, aber auch mindestens eine (eventuell geerbte) rein virtuelle Methode? Dann ist sie abstrakt aber kein Interface, also als Basisklasse für andere zu sehen.

• Trifft nichts davon zu? Dann handelt es sich wohl um eine „normale“, instanziierbare Klasse.

In einigen Programmiersprachen (zum Beispiel Java) kann diese Klassifi-zierung bereits durch Schlüsselworte im Quellcode vorgenommen werden. In C++ ist sie jedoch Auslegungssache, so dass man auch auf Klassen treffen kann, die Attribute oder implementierte Methoden besitzen, obwohl sie eigentlich Interfaces darstellen sollen.

15 Rein virtuelle Methoden unterscheiden sich von „gewöhnlichen“ virtuellen Methoden dadurch, dass für sie keine Implementierung bereit steht, weshalb Klassen mit rein virtuellen Methoden nicht instanziierbar sind.

17

Page 24: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Analyse von Software zur Rückgewinnung ihres Designs

Feststellen von Beziehungen zwischen Klassen

Um sinnvolle Komponenten bilden zu können, reicht es nicht, die einzutei-lenden Klassen nur namentlich zu kennen. Darüber hinaus sind die Beziehungen zwischen den Klassen von Bedeutung, da letztendlich auch die Beziehungen der Komponenten sich aus ihnen ergeben. Die für diese Arbeit relevanten Beziehungs-arten werden im Folgenden erläutert und anschließend ein erstes Klassendia-gramm erstellt. Dabei wird sich an der UML Terminologie orientiert (nachzulesen beispielsweise im aktuellen Standard [OMG07]).

Generalisierung und Realisierung

Eine Relationsart zwischen Klassen wurde bereits im vorhergehenden Ab-schnitt herausgearbeitet, nämlich die Generalisierung, also die Vererbungsbezie-hung. Ein Spezialfall dessen ist nach der Identifizierung der Interfaces im Systems ebenfalls benennbar: die Realisierung. Davon spricht man, wenn eine Klasse sämtliche Methoden eines Interfaces implementiert.

Außer durch Vererbung, kann eine Klasse noch auf weitere Arten mit einer anderen in Beziehung stehen. Hinweise findet man in der Liste der Attribute der Klasse, in den Signaturen ihrer Methoden sowie in deren Implementierungen.

Assoziation

Eine Assoziation beschreibt im Modell die Verknüpfung zwischen Instanzen der beteiligten Klassen. Ist ein Objekt mit einem anderen assoziiert, kann man entlang der Assoziation navigieren und so beispielsweise Methoden anderer Objekte aufrufen. Eine Assoziation kann uni- oder bidirektional sein und sich dabei auch auf mehrere Objekte eines Typs beziehen.

Aggregation und Komposition

Eine spezielle Assoziation ist die Aggregation. Eine Aggregation wird benutzt, um auszudrücken, dass das aggregierte Objekt ein Bestandteil der aggregierenden Klasse ist. Ein weiterer Spezialfall hiervon ist die Komposition, die sich dadurch auszeichnet, dass das aggregierte Objekt genau einen Besitzer hat, der exklusiv für seine Erzeugung und Zerstörung verantwortlich ist.

Ein Beispiel: Einer Fakultät gehören mehrere Professoren an, das heißt die Professoren werden von der Fakultät aggregiert. Eine bloße Assoziation wäre zu schwach, denn ohne die Professoren wäre die Fakultät ziemlich nutzlos und eine Komposition ist zu stark, denn schließlich hören die Professoren nicht auf zu exis-tieren, wenn die Fakultät schließt. Die Professoren selbst sind wiederum unterein-ander assoziiert (beispielsweise weil sie die Telefonnummern ihrer Kollegen kennen).

In der Praxis ist es selten wichtig, ob man nun eine einfache Aggregation oder eine Komposition vor sich hat. Häufig möchte man jedoch wissen, wer denn nun der eigentliche Besitzer eines Objektes ist, also wer für dessen Erzeugung und Zerstörung zuständig ist. Gerade in Sprachen ohne automatische Speicherver-waltung ist dieses Wissen nur vorteilhaft. In Volume Studio werden so einige

18

Page 25: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

3.2.2 Erarbeiten der Klassenstruktur

Zeiger herum gereicht und auch von verschiedenen Klassen und Objekten als Attribut gehalten, so dass man schon in die Versuchung kommen kann, nach den passenden new und delete Aufrufen zu fahnden. Geordnete Besitzverhältnisse können durchaus als eine Designqualität angesehen werden.

Benutzungsabhängigkeit16

Aus den Signaturen der Methoden einer Klasse wiederum lassen sich einige weitere Benutzungsabhängigkeiten ablesen, das heißt die Klasse kennt eine andere Klasse, benutzt sie bzw. eine ihrer Methoden und ist dadurch von ihr abhängig. Eine solche Relation ist eher schwach, wird sie doch teilweise von anderen Re-lationsarten impliziert, hat aber dafür große Auswirkungen, wie noch zu sehen sein wird. Sie ist zumindest in Volume Studio die am häufigsten anzutreffende Re-lation. Außer in den Signaturen der Methoden kann sie auch in deren Implementa-tionen vorzufinden sein. Wie kann in einer Methode ein Typ benutzt werden, der weder als Attribut der Klasse noch als Aufrufparameter vorhanden ist? Folgende Möglichkeiten kommen in den Sinn:

• Der Typ wird innerhalb der Methode instanziiert, so wie dies auch bei den fundamentalen Typen an der Tagesordnung ist, und beispielsweise als temporäre Variable benutzt oder als Parameter bei einem weiteren Funktionsaufruf.

• Eine durch die Methode aufgerufene Funktion liefert ein Objekt dieses Typs als Rückgabewert. Dies ähnelt im Grunde dem vorherigen Fall, ist aber nicht immer ersichtlich, insbesondere wenn das Objekt nicht einer Va-riablen zugewiesen wird (also direkt weiterverwendet wird – offensichtlich besteht keine Abhängigkeit, wenn jener Rückgabewert nicht auch von der Methode ausgewertet wird).

• Es findet eine Typumwandlung eines gegebenen Objektes in den Zielty-pen statt. Dabei handelt es sich in aller Regel um Downcasts17.

• Es werden statische Methoden oder Attribute der Klasse dieses Typs benutzt.

Friend

Eine besondere Abhängigkeit stellt die friend Beziehung dar. Sie betrifft das Freundschaftskonzept in C++, dass es Klassen ermöglicht anderen Klassen seine privaten Eigenschaften zugänglich zu machen. Diejenige Klasse, die eine andere Klasse als Freund bezeichnet, muss diese natürlich namentlich kennen.

16 In der UML gibt es verschiedene Arten von Abhängigkeiten (Dependencies), die im Modell durch Bezeichner unterschieden werden können. Hier wird aber nur diese eine genutzt.

17 Die Umwandlung eines generellen in einen abgeleiteten Typen. Diese kann Fehlschlagen, wenn es sich beim Zielobjekt nicht auch tatsächlich um eine Instanz dieses abgeleiteten Typen oder eine weitere Spezialisierung davon handelt.

19

Page 26: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Analyse von Software zur Rückgewinnung ihres Designs

Create

Nennenswert ist zu guter Letzt die create Assoziation. Sie drückt aus, welche Objekte welche Anderen erstellen. Wenn man sämtliche Objekterstellungen findet, kann aus all den create Beziehungen ein Graph erzeugt werden, der genau dar-stellt, wer welche Klassen instanziiert. Der Aufwand hierfür ist allerdings nicht unerheblich und sollte gegen den erwarteten Nutzen aufgewogen werden.

Bei der Analyse von Volume Studio wurden create Relationen daher nur spo-radisch aufgenommen, nämlich dann, wenn die erstellende Klasse die Objekte nicht selbst direkt weiterverwendete, sie also lediglich zurück gab, in einen Con-tainer einordnete oder Ähnliches. Dadurch sollen Factory Muster erkannt werden können. Auf eine umfassende Suche nach allen Objekterstellungen wurde verzich-tet.

Damit sind nun alle Relationsarten bekannt, die herausgearbeitet werden sollen. Es sei an dieser Stelle angemerkt, dass dies nicht die einzig wahre Menge an Relationen darstellt, die für das Erstellen eines UML Modells aus C++ Quell-code in Frage kommt. Je nach Projekt und Zielsetzung können mehr oder weniger Beziehungsarten ausreichen. Beispielsweise könnte man Aggregationen und Kompositionen auch als Assoziationen darstellen, wenn eine Unterscheidung zwi-schen den Dreien nicht notwendig erscheint.

Generalisierung: B erbt A

Realisierung:

B implementiert das Interface A

Aggregation: A enthält B als Attribut

Komposition: A enthält B exklusiv als Attribut

Assoziation: A assoziiert n Instanzen von B und jede

dieser n Instanzen von B wiederum diese eine von A.

Abhängigkeit: B benutzt A

Friend: B ist Freund von A

Create: A erstellt B

20

Page 27: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

3.2.2 Erarbeiten der Klassenstruktur

Um nun tatsächlich die genannten Relationen zu finden, kann man den Quell-code Zeile für Zeile durch gehen. In den Headerdateien vielleicht noch prak-tikabel, aber spätestens, wenn es darum geht die Methodenrümpfe auf deren Objektnutzung zu durchleuchten, ist man geneigt, einen besseren Weg zu finden. Die meisten IDEs18 verfügen heute über eine Funktion, die es ermöglicht in allen Quellcodedateien des Projekts nach einer Zeichenkette zu suchen und sämtliche Fundstellen aufzulisten. Alternativ gibt es auch Programme wie grep19, die diese Aufgabe auch außerhalb bestimmter Entwicklungsumgebungen erfüllen. Damit lässt sich nun nacheinander nach allen Vorkommen der Klassennamen aller zuvor identifizierten Klassen suchen. In C++ muss dabei auch auf Typumbenennungen via typedef geachtet werden.

Jede dieser Suchaktionen kann Hunderte Treffer liefern. Meist reicht es jedoch, nur einige wenige davon pro Datei zu betrachten, um eine Relation einordnen zu können, so dass alle weiteren Vorkommen innerhalb dieser Datei redundant sind. Der Arbeitsaufwand reduziert sich dem entsprechend. Als Ergebnis erhält man die Beziehungen zwischen sämtlichen Klassen, so dass sich nun ein Klassendia-gramm erstellen lässt.

3.2.3 Zuordnen von Klassen zu Komponenten

Da funktionale Komponenten gebildet werden sollen, indem alle vorhandenen Klassen je nach Funktion einer solchen Komponenten zugeteilt werden, ist es not-wendig die Funktionalität der Klassen zu kennen. Im Idealfall ergibt sich diese aus ihren Namen oder denen ihrer Methoden. Leider tritt dieser Idealfall nicht immer ein. Der Zeitaufwand, den ein Mensch benötigt, um sich in den Quellcode eines Programms oder Programmteils einzuarbeiten und seine Funktion zu begreifen, hängt neben Umfang und Struktur des Codes von der Qualität der vergebenen Be-zeichner für Klassen, Methoden, Variablen, etc. ab, sowie der Kommentare und der Dokumentation. Rückwirkend kann man hier leider wenig bewirken.

Martin Fowler erwähnt in seinem Buch über Refactoring [Fow99, S. 56], dass der Vorgang des Refactorings ihm hilft, unvertrauten Code zu verstehen. Nun ist dies bereits ein sehr konstruktiver Prozess und es gibt auch Gründe sich davor zu scheuen bereits Änderungen am Code vorzunehmen, bevor man ihn in seiner Gän-ze begriffen hat. Wenn ohnehin noch ein größeres Redesign ansteht, wird man eventuell später feststellen, dass der Teil, in den man so viel Zeit investiert hat, um ihn verständlicher zu gestalten, im neuen Design komplett überflüssig wird. Ge-rade ein Refactoringneuling wird auch Schwierigkeiten haben den Zeitaufwand zu beurteilen, den er mit dem Refactoring verbringen wird, bis er das gesamte Pro-gramm verstanden hat. Daher wird dieser Weg hier nicht gegangen und zu diesem Zeitpunkt noch keine Änderung am Code vorgenommen.

Um ein Grundverständnis für die Art und Weise, wie eine Anwendung funktioniert und was sie überhaupt tut, zu erlangen, bietet es sich an, sie schlicht auszuführen und einige Zeit zu testen. Mit Hilfe eines Debuggers oder eines

18 Integrated Development Environment, ein Programmpaket zur Softwareentwicklung gebündelt unter einer gemeinsamen Benutzeroberfläche.

19 http://www.gnu.org/software/grep/grep.html

21

Page 28: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Analyse von Software zur Rückgewinnung ihres Designs

anderen Werkzeugs zur Softwarevisualisierung (siehe 3.2.1) kann man außerdem schauen, wo eine bestimmte Funktionalität im Code realisiert ist.

Wurde eine charakteristische Funktionalität der Anwendung erkannt und auch mindestens eine Klasse X, die an deren Umsetzung beteiligt ist, hat man einen Einstiegspunkt, um auch alle anderen für diese Funktionalität relevanten Klassen zu finden. Im vorhergehenden Abschnitt haben wurden die Beziehungen zwischen allen Klassen festgestellt. Nun nimmt man die Klasse X und sucht diejenigen Klassen, die mit dieser in Relation stehen. Diese Klassen werden betrachtet und für jede einzelne entschieden, ob sie zu der Funktionalität, mit der man sich zur Zeit beschäftigt, etwas charakteristisches beiträgt. Ist das der Fall, untersucht man auch deren Relationen und die Klassen, die daran beteiligt sind. Module aus zu-sammenhängenden Klassen lassen sich so finden. Am Ende sollten alle Klassen in solche funktionalen Komponenten aufgeteilt sein und dabei niemals in mehreren gleichzeitig vorkommen.

So viel zum Idealfall. Wir erinnern uns, dass hier der Ist-Zustand der (unbefrie-digend umgesetzten) Software als Grundlage für ein späteres Redesign aufgenom-men wird. Sind bisher keine Designdetails negativ aufgefallen, sollte dies spätes-tens in diesem letzten Schritt der Analyse der Fall sein. Andernfalls muss die Frage gestellt werden, warum wir das alles hier überhaupt machen. Es kann zum Beispiel vorkommen, dass eine Klasse mehrere Funktionalitäten realisiert und sich somit nicht eindeutig einem Modul zuordnen lässt. Oder das eine Funktionalität über mehrere Komponenten, die nicht direkt in Beziehung stehen, verteilt ist. Mit der gerade beschriebenen Analysemethode wird man hier Proble-me bekommen, die spätestens am Ende, wenn nur noch wenige Klassen ohne Zu-ordnung sind, oder wenn geprüft wird, ob alle Klassen zugeteilt sind und welche Komponenten sich ergeben haben, auffallen sollten.

3.3 Analyse von Volume Studio

Im folgenden wird nun die momentane Architektur von Volume Studio her-ausgearbeitet, wie es in den vorhergegangenen Abschnitten vorgeschlagen wurde. Zunächst werden die externen und programmeigenen Komponenten benannt und anschließend die Klassenstruktur des Programms erarbeitet. Sind Komponenten und Klassen sowie deren Interaktionen bekannt, kann die Designqualität der Soft-ware beurteilt werden. Während der Durchführung der Analyse aufgedeckte Designmängel sind festzuhalten, so dass letztlich ein ausreichend umfassendes Bild von Volume Studio entsteht, dass ein Redesign der Anwendung und die Be-seitigung verschiedener Designmängel ermöglicht. Die Analyse betrifft die Re-vision 69 des Programms.

3.3.1 Erkennen von Komponenten und Abhängigkeiten

Die externe Abhängigkeiten lassen sich wie folgt zusammenfassen:

22

Page 29: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

3.3.1 Erkennen von Komponenten und Abhängigkeiten

• Qt 4.3.*20 für die Benutzeroberfläche und zur Abstrahierung von Auf-rufen an das Betriebssystem

• OpenSG 1.8.021 für die Visualisierung der Volumen in Echtzeit.

• ITK 3.2.022 enthält Algorithmen für die Bildbearbeitung – speziell im medzinischen Bereich – und wird für die Segmentierung der Volumenda-ten genutzt.

• Die OpenGL23 Bibliotheken GL und GLU.

• Einige kleinere Hilfsbibliotheken wie z.B. png, die hauptsächlich von Qt benutzt werden und sich von Plattform zu Plattform unterscheiden können. Sie werden von Volume Studio nicht direkt angesprochen und sind daher für unsere Zwecke nicht von Bedeutung.

Nun zu den programmeigenen Komponenten. Einziger Anhaltspunkt, der auf das Vorhandensein verschiedener Komponenten hindeutet, ist die im Repository zu findende Projektdatei für die scheinbar von den meisten Beteiligten benutzte Entwicklungsumgebung Visual Studio. In dieser sind die Quelldateien des Projekts in verschiedene nicht physisch im Repository zu findende Verzeichnisse unterteilt: In „Volume“, „Shader“, „Helper“ und „Texture“ findet man den Code für das Rendern von Volumen, in „Segmentation“ und „CrossSections“ liegt der Code für die Segmentierung bzw. die Querschnitte, um nur einige zu nennen.

Auf den ersten Blick scheinen die Quellen nach Funktionalität geordnet worden zu sein. Es gibt jedoch auch ein Verzeichnis „GUI“, in dem diverse Fens-ter und Dialoge der Anwendung zu finden sind. Einige Komponenten haben ihre Benutzeroberflächen hier abgelegt, andere wiederum nicht. Schaut man sich die Komponenten näher an, stellt man zudem fest, dass sie eigentlich nur eine lose Ansammlung von Quelldateien sind und es keine offizielle Schnittstelle gibt, mit der die Funktionalität der Komponenten angesprochen werden könnte. Will ein anderer Programmteil auf diese zugreifen, muss er die zuständige Klasse in-nerhalb der Komponenten in der Regel direkt ansprechen. Ist dies nicht möglich, müssen sich Entwickler selbst die notwendigen Bedingungen dazu schaffen. Das kann dann so aussehen, dass die fremde Komponente eine Funktion der eigenen aufruft, wenn die andere Richtung nicht praktikabel erscheint. So ruft nach erfolg-ter Segmentierung die Segmentierungskomponente die Komponente CrossSections zum Update auf, obwohl sie sonst nichts mit ihr zu tun hat. Auf diese Weise werden Abhängigkeiten zwischen den Komponenten eingeführt, die vermieden werden könnten.

Zusammenfassend lässt sich daher sagen: Es sind zwar in der Projektdatei Komponenten vorhanden, Der Quellcode selbst ist jedoch nicht konsequent auf seine Komponente beschränkt. Teilweise wurde auch in fremde Komponenten

20 http://trolltech.com/products/qt21 http://www.opensg.org22 http://www.itk.org23 http://www.opengl.org

23

Page 30: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Analyse von Software zur Rückgewinnung ihres Designs

Code eingeschleust, der eigentlich nur der eigenen dient. Der Mangel an klar er-kennbaren Komponentenschnittstellen macht die Unvollkommenheit der „vor-handenen“ Modularisierung perfekt.

Da die Komponenten also im Grunde nur theoretisch und nur in der Microsoft Visual Studio Projektdatei vorhanden sind, ist es Sinnvoll die Komponenten noch-mals manuell herauszuarbeiten, auch als Basis für den Neuentwurf der Architek-tur.

3.3.2 Erarbeiten der Komponenten aus dem Quellcode

Zur Erarbeitung der Komponenten aus dem Quellcode wird die Klassenstruktur in Erfahrung gebracht, bevor anschließend funktionale Komponenten durch Zutei-lung der Klassen zu den Komponenten, an deren Funktionalität sie beteiligt sind, gebildet werden.

3.3.2.1 Klassenstruktur

Volume Studio besteht in der diesem Kapitel zu Grunde liegenden Revision 69 aus rund 55 Klassen (nicht öffentliche und ungenutzte Klassen, sowie als struct Deklarierte Typen nicht mitgezählt). Die Beziehungen dieser Klassen wurden wie einige Abschnitte zuvor beschrieben herausgearbeitet und ein erstes Klassendia-gramm erstellt (Abbildung 3.1).

In diesem Diagramm, dass alle ermittelten Klassen beinhaltet, wurde auf die Darstellung, der zuvor als Benutzungsabhängigkeiten bezeichneten Relationen, der Übersicht halber weitgehend verzichtet. Diese mit anzuzeigen würde die An-zahl der Relationen im Diagramm vervielfachen. Der Vollständigkeit halber ist das vollständige Klassendiagramm im Anhang zu finden (Abbildung A.1, Seite 69). Beiden Diagrammen gemeinsam ist jedoch, dass einige Klassen stark frequentiert werden, während Andere eher am Rande existieren.

In einem nächsten Schritt wird, um tatsächlich Komponenten zu bilden, das Diagramm in mehrere Teile partitioniert. Stark zusammenhängende Klassen werden in ein und derselben Komponente also in derselben Teilmenge Platz finden. Hier wird auch wieder mit den Benutzungsabhängigkeiten gearbeitet.

24

Page 31: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

25

Abbildung 3.1: Klassendiagramm von Volumestudio (Revision 69).Zur besseren Übersicht wurde auf die Darstellung von Benutzungsabhängigkeiten

weitgehend verzichtet.

Page 32: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Analyse von Software zur Rückgewinnung ihres Designs

3.3.2.2 Komponenten

Inzwischen sind alle Klassen der Anwendung sowie ihre Beziehungen bekannt. Nun können diese betrachtet und ihre Zugehörigkeit zu einer Komponente be-stimmt werden. Bevor dies geschehen kann, muss die Komponente bekannt sein. Es macht daher Sinn nun die Anwendung zu betrachten und nach grundlegenden Funktionalitäten zu suchen, die eine Komponente bilden können, zum Beispiel durch Ausführen des Programms.

Es ist allerdings nicht zwingend notwendig bereits jetzt festzulegen, welche Komponenten insgesamt herausgebildet werden sollen. Alternativ kann die Analy-se Schritt für Schritt vorgehen und dabei jeweils in der Restmenge der Klassen nach einer Funktionalität, die als Komponente verstanden werden kann, suchen. Dies ist ein näher am Quellcode orientiertes Vorgehen, dass auch angewandt werden kann, wenn eine Funktionalität des Programms zur Zeit nicht ausführbar oder unvollständig ist. Gerade bei Programmen für spezielle Anwendungsbereiche – wie der Medizin – kann es auch vorkommen, dass sich eine Funktionalität dem Softwaretechniker nicht sofort erschließt, so dass er zwar weiß, dass die Funktionalität vorhanden ist, sie aber schwer inhaltlich beschreiben kann. Hier ist er gut beraten, sich verstärkt an der Klassenstruktur zu orientieren. Für Volume Studio wird die Analyse schrittweise fortfahren.

Mit einer Komponenten muss jedoch begonnen werden. Betrachtet man das obige Klassendiagramm, finden sich auf einer Seite diverse Klassen mit dem Prä-fix DVR, das steht für „Direct Volume Rendering“. Diese Klassen sind mit dem Zeichnen der Volumen beschäftigt. Das ist eine Kernfunktionalität von Volume Studio und die Analyse wird mit dieser beginnen, wenn es nun darum geht Komponenten zu bilden. Eine oder mehrere der DVR* Klassen werden als Start-punkt herangezogen, ihren Relationen folgend andere Klassen betrachtet und be-urteilt, ob ihr Aufgabenbereich ebenfalls in dieser Komponente liegt.

Auf eine detaillierte Beschreibung der Aufgaben sämtlicher Klassen soll ver-zichtet werden. Das Ziel ist es, ein Bild von Volume Studio zu erlangen, dass ge-nau genug ist, um das Entwerfen einer neuen Architektur zu ermöglichen. Es muss also nicht jedes Designdetail bekannt sein. Allerdings wird auf einige Probleme sowie Schwachstellen im bisherigen Design hingewiesen, die während der Bil-dung der Komponenten auffallen.

Visualization

Die Komponente Visualization ist für das Rendern der Volumen und die Verwaltung von Texturen und Shadern verantwortlich. Ausgangspunkt für ihre Er-arbeitung aus dem Quellcode waren die Klassen TextureManager und DVRVolume, von denen ausgehend weitere Klassen als Bestandteil dieser Komponente identifiziert werden konnten.

26

Page 33: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Auffällig sind die verschiedenen DVR*Base Klassen und die gewöhnungsbe-dürftige Art und Weise, in der von ihnen abgeleitet worden ist: Die Basisklassen sind alle von ihren Spezialisierungen als friend deklariert worden. Das ist ein Vorgehen, was aus der OpenSG Bibliothek, auf die diese Komponente aufbaut, übernommen wurde. Tatsächlich sind einige der Klassen in dieser Komponente komplett aus dem OpenSG Quellcode kopiert worden. Volume Studio erweitert die Standard DVRVolume Klasse und den TextureManager von OpenSG. Leider ist OpenSG an dieser Stelle sehr restriktiv aufgebaut: Der TextureManager ist im Ori-ginal privates Attribut von DVRVolume und nicht überladbar. Dass die Klasse keinen virtuellen Destruktor besitzt, zeigt weiterhin, dass die OpenSG Entwickler Änderungen an ihr durch den Nutzer nicht vorgesehen hatten. Der Autor dieses Teils von Volume Studio hat sich also damit beholfen, die Klassen DVRVolume und TextureManager und ihre relevanten Abhängigkeiten zu kopieren und seine Änderungen in diesen Code zu hacken.

Interessant ist auch der CarveMapper. Er hat mehr Beziehungen zu Klassen außerhalb als innerhalb der Komponente, seine Funktionalität gehört jedoch am ehesten hierher (er beherbergt einen Algorithmus für das Clipping des Volumens). Eventuell sollte ihm beim Redesign ein eigenes Modul spendiert werden.

27

Abbildung 3.2: Die Komponente Visualization (grau) und ange-bundene Klassen anderer Komponenten (weiß).

Page 34: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Analyse von Software zur Rückgewinnung ihres Designs

Tissue

Eine weitere charakteristische Funktionalität von Volume Studio betrifft die Unterscheidung von Gewebearten anhand ihrer Dichte. So wird durch eine soge-nannte Transferfunktion einem Voxel des Volumens eine Farbe zugeordnet. Die vom Programm getroffene Farbwahl kann dabei vom Benutzer durch Erstellung von Filtern geändert werden. Mit Hilfe eines trainierbaren neuralen Netzwerks kann das Programm auch selbstständig Filtereinstellungen treffen, die dann noch vom Anwender angepasst werden können. Mit dieser Funktionalität beschäftigte Programmteile werden in der Komponenten Tissue isoliert.

In der Benutzeroberfläche von Volume Studio finden sich zwei Fenster, welche dem Benutzer die Funktionen der Komponente zugänglich machen. Eines, mit dem die Filter erstellt werden können und ein weiteres, in dem Gewebearten mit samt ihren Filter- und Farbeinstellungen gruppiert werden können. Diese beiden Fenster finden sich als Klassen mit den Namen Transfer2dWindow und TissueMa-nager im Quellcode wieder. Diese waren Ausgangspunkt für die Erstellung dieser Komponenten.

28

Abbildung 3.3: Die Komponente Tissue (grau) und angebundene Klassen anderer Komponenten (weiß).

Page 35: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Problematisch in dieser Komponenten ist in erster Linie die Nutzung der ver-schiedenen Filter. Es gibt zwar ein einheitliches Interface (IFilterWidget), trotz-dem findet an manchen Stellen im Code eine Fallunterscheidung statt, die nach dem genauen Typen des Filters fragt (im Diagramm ausgedrückt, durch die Abhängigkeiten von den konkreten Interfaceimplementierungen). Außerdem hat dieses Interface bereits Attribute und ist somit formal eigentlich keins. Ein In-terface sollte seinen Implementierungen nicht vorschreiben, welche Attribute sie zu benutzen haben und diese Attribute sollten auch nicht öffentlich sein, da sonst eine einfache Änderung wie das Verwenden eines anderen Datentyps weitrei-chende Folgen für Nutzer des Interfaces haben kann.

Segmentation

In Abschnitt 2.1 wurde bereits die Segmentierung von Volumen erwähnt. Sie wird in der Komponente Segmentation gekapselt werden. Segmentation erlaubt das Ausschneiden von Teilen des Volumens zur genaueren Betrachtung. Dazu benutzt es verschiedene Segmentierungsalgorithmen, die vom Benutzer konfigu-riert werden können.

Als Segmentierungsalgorithmus ist in dieser Version von Volume Studio nur ConnectedThreshold anwählbar. Weitere Algorithmen würden ebenso wie dieser von der Klasse SegmentationAlgorithm abgeleitet sein, die wohl als gemeinsame Basisklasse dienen soll, aber keinerlei Methoden besitzt, sondern eher den kleins-ten gemeinsamen Nenner darstellt um die konkreten Algorithmen im Programm umherzureichen. Sie werden von SegmentationWindow erstellt und in VolumeInfo verwaltet. Wo sie zerstört werden konnte ich nicht herausfinden.

29

Abbildung 3.4: Die Komponente Segmentation (grau) und ange-bundene Klassen anderer Komponenten (weiß).

Page 36: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Analyse von Software zur Rückgewinnung ihres Designs

Core

Zu guter Letzt wurden alle übrigen Klassen einer Komponenten Core zugeteilt. Das wäre in erste Linie das Hauptfenster und einige Klassen, die zum Datenaus-tausch zwischen den Komponenten genutzt werden. Es sind aber auch Klassen vorhanden, die schlicht nicht mit absoluter Sicherheit einer der anderen Komponenten zugeordnet werden können oder die kleinere Funktionalitäten dar-stellen, die nicht als grundlegend anzusehen sind und daher zumindest zu diesem Zeitpunkt keine eigene Komponente erhalten sollen. Während des Entwurfs der neuen Architektur wird entschieden, wie im Einzelfall mit diesen verfahren werden soll.

Die KeyHandler Derivate wandeln Tastatureingaben innerhalb des Fensters, in dem das Volumen gerendert wird (GLVolumeWidget) in Aktionen um. Die Klassen VolumeInfo und MeshInfo halten Informationen über Darstellungsmodi für ein bestimmtes Volumen bzw. Mesh, die von anderen Klassen und Komponenten abgerufen werden können, und sind gleichzeitig für das Laden sol-cher Objekte aus Dateien zuständig.

Zu den spezielleren Funktionalitäten dieser Komponente gehört zum einen die Klasse AnimationKeyHandler. Als KeyHandler Implementierung reagiert sie auf Tastatureingaben des Nutzers. Sie beherbergt aber auch Code zum Laden und Speichern von Storyboards. Storyboards sind Sequenzen von Aktionen die in einem XML Format gespeichert werden und beispielsweise zu

30

Abbildung 3.5: Die Komponente Core. Beziehungen zu externen Klassen wurden des Umfangs wegen außen vor gelassen, sind aber in

den drei vorhergehenden Diagrammen ersichtlich.

Page 37: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Präsentationszwecken abgespielt werden können. Aktionen können Kamerabewe-gungen aber auch das Laden eines Volumens oder das Vornehmen verschiedener Einstellungen sein. Da AnimationKeyHandler alle Aktionen, die aus dem Story-board gelesen werden, selbst vornimmt, sind die speicher- und ausführbaren Ak-tionen durch die Kenntnisse und Fähigkeiten dieser Klasse beschränkt. Um eine neue Funktionalität als Storyboardaktion verfügbar zu machen oder um eine be-stehende aus dem Programm zu entfernen, muss AnimationKeyHandler erweitert bzw. geändert werden. Für das später zu implementierende Pluginsystem eine ziemlich unpraktische Vorstellung, bedeutet dies doch, dass die Klasse sämtliche Plugins, deren Funktionen in einem Storyboard abrufbar sein sollen, kennen muss.

Auch die Art und Weise wie die KeyHandler von GLVolumeWidget benutzt werden, sollte überdacht werden, denn momentan erlaubt das System eigentlich nur einen einzigen KeyHandler. Bisherige Implementierungen werden durch Vererbung weitergereicht, so dass weitere KeyHandler neu hinzukommender Mo-dule gar nicht ohne weiteres eingesetzt werden können.

Eine weitere nennenswerte Funktionalität offenbart sich dem Benutzer durch die Klasse CrossSectionWindow. Von hier aus lassen sich Querschnitte durch das Volumen entlang einer der drei Achsen des Koordinatensystems vornehmen. Eigentlich würde dies eine eigenständige Funktionalität darstellen, könnte man meinen, der eine eigene Komponente gebühren sollte. Versucht man jedoch, diese herauszuarbeiten, dann stellt man fest, dass die Relationen zu externen Klassen zahlreich sind. In Abbildung 3.6 ist ersichtlich, wie die Komponente CrossSection aussehen würde.

Die Klassen CrossSection und damit indirekt CrossSectionPlane werden von Klassen aus Visualization aggregiert, Marker Instanzen sind in VolumeInfo abge-legt und überhaupt unterhält CrossSection in großer Zahl Beziehungen zu den anderen Modulen.

Während also vom Standpunkt der reinen Funktionalität eine Komponente CrossSection denkbar wäre, sprechen die strukturellen Informationen in Volume Studio eher dagegen, weshalb ich sie nicht herausgearbeitet habe. Freilich heißt

31

Abbildung 3.6: Die nicht eingeführte Komponente CrossSection (grau) und angebundene Klassen anderer Komponenten (weiß).

Page 38: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Analyse von Software zur Rückgewinnung ihres Designs

das nicht, dass beim Redesign eine solche Komponente nicht eingeführt werden könnte, aber im momentanen Design ist sie nur mit viel Phantasie erkennbar.

Wie man an diesem Beispiel sieht, ist die Modularisierung eines Softwaredesigns, dass nichtmodularisiert umgesetzt wurde, an manchen Stellen eine reine Auslegungssache. Vielleicht würde jemand Anderes, der diese Aufgabe erfüllt zu anderen Ergebnissen kommen, als ich das hier tue. Wichtig ist aber bei all dem weniger, ob alle Entscheidungen bei der Analyse hundertprozentig akkurat getroffen wurden, sondern ob sie das spätere Redesign hundertprozentig unter-stützen.

3.3.3 Gesamtbild

Nach der Herausarbeitung der vier Komponenten nun ein Blick auf das Ge-samtbild.

Mit nur vier Komponenten sieht dieses Diagramm recht übersichtlich aus. Schaut man genauer hin, stellt man jedoch fest, das beispielsweise die Core Komponente von allen anderen abhängig ist. Würde man also eine beliebige Komponente entfernen, wäre Volume Studio bereits nicht mehr funktionsfähig. Nun erscheint es nicht verwunderlich, wenn eine Abhängigkeit zwischen Core und Visualization besteht, ist das Zeichnen der Volumen doch eine Kernaufgabe des Programms. Doch zumindest die Abhängigkeit dieser beiden Komponenten von Segmentation erscheint fragwürdig. Die Segmentierung von Volumen sollte eine optionale Fähigkeit von Volume Studio sein und keine, von der das Funktionieren des Systems abhängt.

Bei der Betrachtung der Klassendiagramme der einzelnen Komponenten wird außerdem deutlich, dass andere Komponenten auf eine Funktionalität zugreifen, indem sie sich die sie implementierende Klasse direkt heraus picken. Schnitt-stellen, welche die Funktionalität einer Komponenten explizit und wohl sortiert anbieten, gibt es im System nicht. Dies schränkt die Austauschbarkeit der Komponenten enorm ein und kann daher klar als Designmangel aufgefasst werden. Als Diagramm aller Klassen und Abhängigkeiten, das auch die enge Ver-zahnung der Komponenten darstellt, sei erneut auf die Abbildung A.1 im Anhang verwiesen.

32

Abbildung 3.7: Komponenten von Volume Studio (Revision 69).

Page 39: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

3.3.3 Gesamtbild

Einen weiteren Mangel stellt der oftmals unklar eingegrenzte Aufgabenbereich verschiedener Klassen dar24. Solche Klassen, die mehrere Funktionen in sich vereinen, neigen dazu, schwer erweiterbar und schwer zu Ersetzen zu sein. Für das Redesign sollte eine Teilung einiger Klassen in Erwägung gezogen werden.

3.4 Zusammenfassung

In diesem Kapitel wurde ein tiefgreifendes Verständnis dafür vermittelt, wie die Architektur einer Software offengelegt werden kann, um sie einem Redesign un-terziehen zu können. Es wurde erläutert, wie vorhandene Komponenten entdeckt, wie die Klassenstruktur einer Software offengelegt und wie Komponenten ge-bildet werden können. Letzteres insbesondere in einer Software, die noch keine Modularisierung aufweist. An einigen Stellen sind dabei Quellen für Design-mängel aufgefallen.

Was Volume Studio anbelangt, so ist seine Funktionalität nun ebenso bekannt, wie die Klassen, die sie umsetzen. Alle vorhandenen Klassen wurden auf diesem Wissen aufbauend lose in Komponenten gruppiert. „Lose“ bedeutet hier, dass sie inhaltlich und strukturell noch nicht der Weisheit letzter Schluss sind, sondern vorläufiger Natur, da sie lediglich dem momentanen, fehlerbehafteten Design von Volume Studio entstammen. Auch weisen die Komponenten keine sauberen Schnittstellen auf, so dass ihr Innenleben offen liegen muss, damit das System funktioniert. Dies führt zu einer engen Verzahnung der Komponenten. Beim Re-design wird es darum gehen sie umzugestalten, um eine modulare Architektur zu schaffen, bei der die Module austauschbar sind und das Gesamtsystem leicht zu erweitern oder zu ändern ist. Dazu werden einige der Designmängel, die während der Analyse aufgefallen sind, zu beseitigen sein.

24 Siehe beispielsweise die Beschreibung der Core Komponente und dort insbesondere der Klassen MeshInfo, VolumeInfo und AnimationKeyHandler.

33

Page 40: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Analyse von Software zur Rückgewinnung ihres Designs

34

Page 41: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

4 Behebung von Designmängeln

4 Behebung von Designmängeln

Bevor das Redesign von Volume Studio beginnen kann, zunächst einige Ge-danken darüber, wie einige Probleme, die dabei auftreten werden, gelöst werden können. Die Analyse hat mehrere Designmängel zum Vorschein gebracht, die in der neuen Architektur nicht mehr vorkommen sollen, insbesondere das Vor-handensein unnötiger Anhängigkeiten und die Konzentrierung mehrerer Funktionen auf wenige Klassen. In diesem Kapitel wird die Behebung dieser Mängel thematisiert.

4.1 Beseitigung ungewollter Abhängigkeiten

Die Analyse hat festgestellt, dass es in Volume Studio eine Vielzahl von Abhängigkeiten zwischen den herausgearbeiteten Komponenten sowie Klassen gibt. Beim Erstellen der neuen Architektur werden Mittel gebraucht, um unge-wollte Abhängigkeiten aus dem System zu entfernen.

Die zuvor als Benutzungsabhängigkeit bezeichnete Relation spielt nun eine wichtige Rolle. In den Diagrammen des letzten Kapitels ist es meist genau diese Beziehungsart, die Abhängigkeiten zu Klassen außerhalb der Komponenten aus-drückt. Diese gilt es nun so weit wie möglich zu beseitigen. Dazu gibt es mehrere Möglichkeiten, die je nach Situation anwendbar sind. Einige ausgewählte Si-tuationen werden im Folgenden durchgespielt und Lösungen präsentiert.

4.1.1 Verlagern und Umkehren von Abhängigkeiten

Angenommen eine Klasse benutzt eine Methode einer fremden Klasse, um einen Wert zu erfragen, den sie für ihre Berechnungen benötigt. Ultimativ ist es unmöglich, die Abhängigkeit zwischen der Klasse, die den Wert definiert und der, die den Wert verwendet, zu beseitigen, denn irgendwie muss diese Klasse ja auf den Wert zugreifen können. Möglich ist es jedoch, die Abhängigkeit zu verlagern, so dass sie kein Problem mehr darstellt.

void ThisClass::foo() {...int valueX2 = instanceOfOtherClass->value() * 2;...

}

Hier wird das fremde Objekt wie zuvor beschrieben benutzt, um einen Wert zu erfragen. Der Methodenaufruf kann unterbunden und damit die Abhängigkeit zur fremden Klasse entfernt werden, indem jener Wert in die Parameterliste der Me-thode aufgenommen wird.

35

Page 42: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Behebung von Designmängeln

void ThisClass::foo(int value) {...int valueX2 = value * 2;...

}

Nun ist der Aufrufer derjenige, der den benötigten Wert von der fremden Klasse erfragen muss. Die Abhängigkeit wurde also aus der einen Klasse in eine andere verlagert. Dies stellt nicht immer eine Verbesserung dar, aber häufig stand der Aufrufer selbst schon vorher mit jener Klasse in Beziehung oder ist gar jene Klasse selbst, so dass die Zahl der Abhängigkeiten letztlich erfolgreich reduziert werden konnte.

Ist das Weiterreichen der Abhängigkeit an eine aufrufende Klasse nicht prak-tikabel, weil sie für mindestens einen Aufrufer nicht wünschenswert ist, gibt es noch die Möglichkeit, die Abhängigkeit umzukehren. Dabei propagiert die fremde Klasse ihren Wert von sich aus an diejenigen Klassen bzw. Objekte, die ihn benutzen. Dies muss bei jeder Änderung des fraglichen Wertes geschehen und führt meist dazu, dass der Wert mehrfach im System gespeichert ist. Falls alle Objekte vom Typ ThisClass den Wert vom selben Quellobjekt verwenden, kann dieser als Klassenattribut von ThisClass angelegt werden. Die den Wert bereit-stellende Klasse muss in diesem Fall keine konkreten Objekte von ThisClass kennen, sondern nur dessen Deklaration. Ist auch dies problematisch, kann eine dritte Klasse als Brücke dienen.

4.1.2 Anwendung des Observer Patterns

Eine weitere Möglichkeit ungewollte Abhängigkeiten zu entfernen, besteht in der Anwendung des Observer Patterns. Dieses bietet sich insbesondere dann an, wenn mehrere Klassen auf den selben Daten arbeiten und über Veränderungen auf dem Laufenden gehalten werden müssen. In Volume Studio kann die Darstellungs-weise der Volumen geändert werden, woraufhin alle Klassen, deren Funktionalität von dieser abhängen, neue Berechnungen durchzuführen haben. An einigen Stellen im Volume Studio Quellcode finden sich daher Aufrufe von „update“-Me-thoden fremder Objekte.

void ThisClass::foo() {

...

volume->changeSetting(newSetting);instanceOfOtherClass->update();

}

Kommt dies in mehreren Komponente vor, sind diese plötzlich durch ihre gegenseitigen Abhängigkeiten derart verknüpft, dass sie nur gemeinsam funktionieren und einzelne Komponenten nicht entfernt werden können. Um sol-che Mängel zu beheben, bietet es sich an das Observer Pattern zu nutzen (siehe Kapitel 2.2 oder [GHJV96]). Objekte registrieren sich bei anderen Objekten, die

36

Page 43: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

4.1.2 Anwendung des Observer Patterns

für sie relevante Veränderungen herbeiführen, als Beobachter und werden dann im Falle einer Änderung benachrichtigt. In der Regel müssen Beobachter dazu lediglich ein kleines Interface implementieren, um durch das benachrichtigende Objekt ansprechbar zu sein, ohne dass dieses wissen muss, welchen Typ das beobachtende Objekt hat.

Die Abhängigkeit der Klasse, welche die Änderungen herbeiführt zu den-jenigen, die benachrichtigt werden müssen, wird dadurch beseitigt. Doch Vorsicht! Die Beobachter müssen sich als solche beim Zielobjekt registrieren, um Nachrich-ten zu erhalten. Die Abhängigkeit wurde also nicht tatsächlich entfernt, sondern lediglich umgekehrt.

Betrachten wir das Beispiel erneut. Eine Instanz der Klasse ThisClass benach-richtigt seine Beobachter, wenn es etwas am Volumen geändert hat. Der Fehler liegt darin, dass es die Beobachter im Grunde gar nicht interessiert, wer etwas am Volumen geändert hat, sondern nur, dass etwas geändert wurde. Das Observer Pattern wurde auf die falschen Klassen angewandt. Tatsächlich ist es das Volumen selbst, dass beobachtbar sein muss.

void Volume::changeSetting(Setting newSetting) {

...

mSetting = newSetting;notifyObservers();

}

Das Volumen benachrichtigt also seine Beobachter, wenn es seine Einstel-lungen ändert. In der Praxis könnten Beobachter noch darüber informiert werden wollen, welche Einstellung geändert wurde und welches Volumen sie eigentlich gerade benachrichtigt hat. Diese Informationen können als Parameter in die Be-nachrichtigungsmethode einfließen. Was die Abhängigkeiten angeht, so kennen die Beobachter nun nur noch das Volumen, also nur noch das Objekt, an dem sie tatsächlich interessiert sind.

4.2 Verfeinerung groben Designs

Volume Studio soll ein Design erhalten, dass „besser“ ist, als das bisherige, undzwar insbesondere in den Punkten Erweiterbarkeit, Änderbarkeit und Wart-barkeit. Während der Analyse wurden einige Mängel entdeckt, die diese Eigen-schaften negativ beeinflusst haben. Neben überflüssigen Abhängigkeiten wirkt noch eine schlechte Aufteilung von Funktionalitäten auf Klassen den gewünschten Designqualitäten entgegen, das heißt Klassen vereinen mehrere Funktionen in sich. Dies hat zur Folge, dass diese Funktionen eng verknüpft sind. Änderungen an einer Funktionalität können so leicht ungewünschte Nebeneffekte bei einer anderen hervorrufen. Hinzu kommt, dass Klassen, die mehrere Aufgaben erle-digen für Entwickler schwerer zu begreifen sind.

Im folgenden möchte ich darauf eingehen, wie eine feinere Granularität in der Klassenstruktur zu hochwertigerem Softwaredesign führen kann, und dies an

37

Page 44: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Behebung von Designmängeln

einem Beispiel verdeutlichen. Der Bereich aus Volume Studio, der dazu herange-zogen werden soll, betrifft das Laden eines polygonalen Meshes aus einer Datei. Zunächst wird der bisherige Mechanismus dargestellt, dann der von mir über-arbeitete, und es folgen Erklärungen der Verbesserungen.

Die Klasse MeshListModel ist im Grunde eine Liste von MeshInfo Objekten. Diese enthalten die für OpenSG relevanten Knoten für die Visualisierung sowie Methoden, um diese Knoten zu erstellen. Aktuell ist Volume Studio in der Lage Meshes aus zwei Dateiformaten zu lesen, .tri und .pts. Jedem Format ist eine eigene Methode zum Auslesen gewidmet. Je nachdem, ob man die Methode addPts() oder addTri() von MeshListModel aufruft, wird die entsprechende Me-thode von MeshInfo zur Initialisierung benutzt.

Das folgende Sequenzdiagramm zeigt, wie der Nutzer die Funktion zum Laden eines Meshes aufruft, woraufhin ein Mesh aus einer *.pts Datei geladen wird.

Die Aktionen konzentrieren sich wie erwartet auf die Klassen MeshListModel und MeshInfo. Die Klasse VolumeMainWindow beschreibt das entsprechende Fenster der Benutzeroberfläche, über dass die Funktion zum Laden eines Meshes zur Verfügung gestellt wird. Zu beachten ist, dass diese Klasse auch für die Unter-

38

Abbildung 4.1: Die Mesh-Klassen vor dem Redesign.

Abbildung 4.2: Sequenz zum Laden eines Meshes aus einer *.pts Datei im alten Programmdesign.

Page 45: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

4.2 Verfeinerung groben Designs

scheidung der Dateitypen zuständig ist, und die entsprechende Methode von MeshListModel auf Basis dessen aufruft. Weitere Beteiligte sind die Klasse GLVolumeWidget (das Fenster, in das gezeichnet wird), welches die Wurzel des OpenSG Szenegraph liefert, an die das neue Mesh angehängt wird. Betrachten wir nun den gleichen Teil Volume Studios in neuem Programmdesign.

Der Code aus den Klassen MeshListModel und MeshInfo wurde hier auf meh-rere Klassen verteilt, wobei die Funktionalität von MeshListModel – das Erstellen und Zerstören von Meshes sowie das Verwalten in einer Liste – nun größtenteils in MeshManagerImpl wiederzufinden ist. Die Funktionen der MeshInfo Klasse zum Laden der Meshes wurden hingegen ausgelagert. Auf den ersten Blick bläht dies das System ziemlich auf, zumal die alte Version auch nicht aus übermäßig viel Code bestand (ca. 500 physische Codezeilen). Im Grunde wurden vier Funktionen aus dem vorherigen Design extrahiert:

• Das Laden eines Meshes aus einer Datei.• Die Haltung von Meshdaten.• Das Zeichnen eines Meshes.• Das Verwalten einer Anzahl von Meshes im System.

Die konsequente Nutzung von Interfaces führt dazu, dass die Implementierung einer Funktion geändert werden kann, und solange die Interfaces intakt bleiben, bleibwn auch die anderen Funktionen unbeeinflusst. Auch zu dieser Klassenstruk-tur folgt nun ein Sequenzdiagramm an, dass die selben Aktionen abbildet wie das vorherige25.

25 Während meiner Arbeit an Volume Studio wurde die Benutzeroberfläche umgestaltet, so dass das VolumeMainWindow im Diagramm nun SurfacesWindow heißt.

39

Abbildung 4.3: Die Mesh-Klassen nach dem Redesign.

Page 46: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Behebung von Designmängeln

Es fällt auf, dass die Unterscheidung der Dateiformate nicht mehr im Dia-gramm vorkommt. Diese wird jetzt implizit durch die MeshFileHandler vorge-nommen. Jeder MeshFileHandler prüft selbst, ob die Datei, dessen Pfad er erhal-ten hat, das passende Format hat. Weiterhin fällt auf, dass das Auslesen der Mesh-daten aus der Datei und das Erstellen der relevanten OpenSG Objekte aufgespal-ten wurde. Die entsprechenden Aufrufe von OpenSG Funktionen sollen so in wenigen Klassen isoliert werden. Daher wird auch das Einfügen des Meshes in den Szenegraphen nun von der Klasse SceneManager vorgenommen, so dass MeshManagerImpl völlig ohne OpenSG Code auskommt. Die eigentlich inter-essanten Verbesserungen liegen aber wo anders.

Der Vorteil des neue Designs ist die erhöhte Flexibilität. Zur Zeit ist Volume Studio in der Lage Meshes aus zwei Dateiformaten zu lesen, *.tri und *.pts. In diesen Dateien sind die Daten unterschiedlich angelegt, so dass jedes Format eine eigene Methode zum auslesen erfordert. Im Alten Design waren diese in der Klasse MeshInfo zu finden. Um ein weiteres Format einlesen zu können, musste eine weitere Methode erstellt werden. Neben MeshInfo musste dann noch MeshListModel erweitert werden und zu guter Letzt war der Code zur Bestim-mung des Dateitypen, der sich wiederum in einer dritten Klasse befindet, zu ändern.

In der überarbeiteten Version wird stattdessen ein neue Implementierung von MeshFileHandler erstellt und eine Instanz davon dem MeshLoader hinzugefügt. Dieser verwaltet die MeshFileHandler – ohne die konkreten Implementierungen zu kennen – in einer Liste und implementiert eine Art Zuständigkeitskette (Chain of Responsibility, siehe Kapitel 2.2 oder [GHJV96]). Soll ein Mesh aus einer Da-tei geladen werden, beauftragt er nacheinander die MeshFileHandler dies durch-zuführen, bis einer dazu in der Lage ist, oder alle abgelehnt haben. In dem Fall ist der Pfad bzw. die Datei ungültig oder es ist kein geeigneter MeshFileHandler vor-

40

Abbildung 4.4: Sequenz zum Laden eines Meshes aus einer *.pts Datei im neuen Programmdesign.

Page 47: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

4.2 Verfeinerung groben Designs

handen um das Format zu lesen. Durch dieses Design lässt sich Unterstützung für Dateiformate Hinzufügen oder Entfernen ohne bestehenden Code ändern zu müssen, wie das bisher der Fall ist. Insbesondere wäre es in einem Pluginsystem denkbar, die MeshFileHandler als Plugins während der Laufzeit zu laden.

Eine weitere Ergänzung ist die MeshData Klasse. Diese enthält die Daten, die ein Mesh ausmachen, also Koordinaten der Polygone, deren Farben und Ähnliches. Ein neues Mesh wird mit diesen Daten initialisiert. Dabei muss es nicht wissen, ob die Daten nun aus einer Datei gelesen oder zur Laufzeit von einem anderen Programmteil erstellt wurden. Volume Studio nutzt zur Vi-sualisierung der Meshes OpenSG und so kann der Code, der die Meshes mit Hilfe von OpenSG Funktionen realisiert, komplett in der MeshImpl Klasse gekapselt werden, die lediglich ein MeshData Objekt zur Initialisierung benötigt. Zuvor musste noch jeder Programmteil, der ein Mesh zur Laufzeit erstellen wollte, selbst mit OpenSG hantieren. Jetzt hat er bloß ein MeshData Objekt zu erstellen und den MeshManager anzuweisen, damit ein neues Mesh Objekt zu instanziieren.

Die Einführung der MeshData Klasse erhöht die Flexibilität der Anwendung noch auf eine weitere Art. Beispielsweise unterstützt Volume Studio zur Zeit keine texturierten Meshes. Angenommen eine neue Visualisierungskomponente ist in der Lage texturierte Meshes darzustellen. Dazu erweitert sie die MeshData Klasse (durch Polymorphie). Andere Komponenten können davon Gebrauch machen und Texturinformationen in den erweiterten MeshData Objekten ablegen. Was aber, wenn nun im Programm statt der neuen eine alte Visualisierungskomponente ohne Unterstützung für texturierte Meshes aktiv ist? Die Komponenten, die Meshes er-stellen möchten sollen nicht prüfen müssen, welche Visualisierungskomponente gerade im Dienst ist. Durch die Nutzung von Polymorphie wird die erweiterte Funktionalität in der alten Visualisierungskomponente schlicht nicht wahrgenom-men und das Mesh wie gehabt untexturiert dargestellt. Die erweiterte MeshData Klasse ist also quasi abwärtskompatibel. Wäre solch ein Vorgehen nicht möglich, würde dies zu Inkompatibilitäten zwischen Komponenten führen. Es ist in meinen Augen besser, wenn eine Komponente eingeschränkt nutzbar ist, als wenn sie überhaupt nicht nutzbar ist.

Die konsequente Trennung von Schnittstellen und Implementierungen erhöht zusätzlich die Erweiterbarkeit. Falls eine Komponente eine Schnittstelle neu bzw. anders implementieren möchte, kann sie dies tun ohne eventuelle Imple-mentierungsdetails der Ursprungsklasse kennen zu müssen. Ohne die Trennung von Schnittstelle und Implementierung gelangt man leicht in Bedrängnis, wenn man die Implementierung anders Umsetzen möchte.

OpenSG ist ein Negativbeispiel für eine Software, dessen Design ohne geson-derte Interfaceklassen daherkommt. Während der Analyse von Volume Studio, ins-besondere der Visualisierungskomponente, wurde bereits auf die Problematik ein-gegangen. So konnte etwa die OpenSG Klasse DVRVolume nicht einfach abgelei-tet werden, weil man ihre Implementierung nicht erben wollte. Da jedoch andere – unverzichtbare – Klassen ein DVRVolume Objekt erwarten gab es nur die Alterna-tive all diese Klassen zu kopieren und sie das neue DVRVolume Objekt nutzen zu lassen, das eigentlich die selbe Schnittstelle bietet. Hätten die OpenSG Entwickler Interface und Implementierung getrennt, gäbe es das Problem nicht.

41

Page 48: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Behebung von Designmängeln

Dieses Beispiel demonstriert, wie ein flexibleres und gleichzeitig robusteres Design durch Verwendung geeigneter Design Pattern, Beschränkung der Funktionalität von Klassen auf möglichst wenige Kernkompetenzen und Trennung von Schnittstellen und Implementierungen erreicht werden kann. Die feinere Gra-nularität der Klassenstruktur führt zwar zu mehr Klassen und zu mehr Code, je-doch ist dieser wohlgeordnet und damit einfacher zu durchschauen, so dass zu-künftige Änderungen mit geringerem Aufwand und größerer Sicherheit durchge-führt werden können.

4.3 Zusammenfassung

In diesem Kapitel wurden einige Verfahren vorgestellt, um ausgewählte Designmängel zu beheben. Ungewollter Abhängigkeiten können beseitigt oder zu-mindest verlegt werden, so dass sie kein Problem mehr für die Struktur der Soft-ware darstellen. Außerdem wurden die Vorteile feingranularer Klassenstrukturen erläutert. Mit diesem Wissen ist es nun möglich Volume Studio schrittweise in eine neues, besseres Design zu überführen.

42

Page 49: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

5 Entwurf einer neuen Architektur

5 Entwurf einer neuen Architektur

In Kapitel 3 wurde Volume Studio analysiert, um seine funktionalen Komponenten sowie seine Struktur in Erfahrung zu bringen. Während dieser Analyse sind einige Schwachpunkte im bisherigen Design der Software entdeckt worden. So sind die funktionalen Komponenten nur lose Ansammlungen von Klassen ohne, dass es klare Komponentenschnittstellen gibt. Das Programm ist daher nur mit großem Aufwand erweiterbar. Zudem bestehen teilweise unnötige Abhängigkeiten zwischen den Komponenten, die ihrer Austauschbarkeit im Wege stehen. Nun soll ein neues, modulares Design entstehen, dass unter anderem durch die Umsetzung eines Pluginkonzepts die Erweiterbarkeit der Anwendung erhöht.

5.1 Architekturanforderungen

Bevor mit dem Redesign fortgefahren wird, werden einige Eigenschaften formuliert, welche die neue Architektur zu erfüllen hat. Anschließend wird disku-tiert, wie diese Eigenschaften sichergestellt werden können.

Die Motivation für das Redesign von Volume Studio ist, dass die Anwendung mangels eines durchdachten Designs zunehmend komplexer und die Weiter-entwicklung und Wartung dadurch entsprechend erschwert wird.

Die Erweiterbarkeit der Software wird nun durch Modularisierung ihrer Archi-tektur erhöht. Die Komponenten von Volume Studio sind soweit wie möglich zu entkoppeln, so dass Änderungen in der einen keine Änderungen in einer anderen notwendig machen und neue Komponenten leicht hinzugefügt werden können. „Eine lose Kopplung macht es wahrscheinlicher, dass eine Klasse allein wieder-verwendet und das System leichter erlernt, portiert, modifiziert und erweitert werden kann“ [GHJV96, S. 34]. Dies gilt analog für Komponenten. Die weitge-hende Unabhängigkeit der Komponenten führt auch dazu, dass diese getrennt voneinander weiterentwickelt werden können.

Ein Begriff, der häufig gemeinsam mit Kopplung genannt wird, ist Kohäsion. In der objektorientierten Softwareentwicklung beschreibt er den Grad des Zu-sammenhangs von Aufgaben einer Klasse oder eines Moduls. Klassen die mehrere Aufgaben erfüllen, welche wenig miteinander gemein haben, besitzen eine niedrige Kohäsion. Eine hohe Kohäsion haben Klassen, deren Methoden allesamt auf einen Aufgabenbereich abzielen. Dies ist wünschenswert, da Klassen mit vielen scheinbar zusammenhanglosen Methoden schwerer zu Begreifen sind. Ihre Rolle im Design der Anwendung ist zudem aufgrund ihres vielfältigen Aufgaben-bereichs nicht klar einzugrenzen. Beides führt zu Schwierigkeiten, wenn Änderungen oder Erweiterungen an einer Funktionalität der Klasse vorgenommen werden sollen. Eine hohe Kohäsion erleichtert Erweiterbarkeit und Wartbarkeit einer Software. Die neue Architektur soll also Klassen mit möglichst hoher Kohä-sion hervorbringen.

Eine weitere sicherzustellende Eigenschaft der neuen Architektur ist die Aus-tauschbarkeit von Komponenten. So sollen Komponenten gegen andere ausge-

43

Page 50: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Entwurf einer neuen Architektur

tauscht werden können, die den gleichen Aufgabenbereich behandeln, aber unter-schiedlich implementiert sind. Beispielsweise stehen Computergrafik-Anwendungen nicht selten mehrere Visualisierungskomponenten (Renderer) zur Verfügung.

Wie können diese allgemeinen Punkte nun in der neuen Architektur und in dessen Implementierung Berücksichtigung finden? Aus den Erfahrungen, die während der Analyse von Volume Studio gemacht wurden, insbesondere durch die aufgedeckten Designschwächen, lassen sich einige Punkte konkretisieren, welche die obigen Designeigenschaften unterstützen.

1. Alle Komponenten sollen so wenige Abhängigkeiten zu anderen Komponenten wie möglich besitzen, also nur genau so viele, wie für ihr Funktionieren erforderlich. Durch Minimierung der Abhängigkeiten – also der Kopplung – können Komponenten, deren Funktionalität zur gegebenen Zeit nicht benötigt wird, aus dem System entfernt und unabhängig voneinander weiterentwickelt werden.

2. Komponenten sollen Komponentenschnittstellen deklarieren, über die ihre Funktionalität angesprochen werden kann. Dadurch und durch die Sicherstel-lung, dass andere Komponenten ausschließlich auf diese Schnittstellen zu-greifen können, werden die Abhängigkeiten der Komponenten untereinander auf diese Schnittstellen begrenzt. Komponenten sollen nur von Schnittstellen, nicht aber von konkreten Implementierungen abhängig sein. Komponenten mit vergleichbarer Funktionalität können somit leicht gegeneinander ausgetauscht werden. Durch die strikte Trennung von Schnittstelle und Implementierung kann letztere geändert werden, ohne dass die Schnittstelle berührt wird. Andere Komponenten werden somit durch die Änderungen nicht beeinflusst.

3. Schmale Schnittstellen sind zu bevorzugen. Schnittstellen sollen also nur diejenigen Methoden besitzen, die von fremden Komponenten benötigt werden, um Zugriff auf die Funktionalität zu erhalten, welche die Komponente zur Verfügung stellt. Dies erleichtert die Handhabung einer Schnittstelle für Entwickler, die eine Komponente mit verwenden wollen.

4. Methoden sollten nach Möglichkeit derart formuliert sein, dass sie keine Annahmen über die Implementierung der Schnittstelle zulassen. Dies soll Entwicklern von Komponenten die größtmögliche Freiheit bei der Imple-mentierung der Schnittstelle gewähren. Ein Beispiel:

virtual const std::list<int>& numbers() const = 0;

Hier wird eine Referenz auf eine Liste als Rückgabewert verwendet. Eine Klasse, die diese Methode implementiert, ist daher gezwungen mit einer sol-chen Liste oder einem Derivat davon zu arbeiten. Es steht den Entwicklern nicht mehr frei, beispielsweise einen std::vector als Container zu verwenden. In diesem Beispiel kann das Problem gelöst werden, indem eine Instanz einer Liste, statt einer Referenz übergeben wird. Die Implementierung der Schnittstelle kann dann die Liste aus ihren Daten erstellen, muss sie aber nicht selbst speichern, wie im Fall einer Referenz oder eines Zeigers. Ist dies

44

Page 51: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

5.1 Architekturanforderungen

nicht ausreichend effizient, bietet es sich häufig an, stattdessen die nötigen Zugriffsmethoden eines Containers in die Schnittstelle aufzunehmen. Der Aufrufer kann dann ebenso leicht über die Werte iterieren wie mit einer Liste und der in der Implementierung verwendete Datentyp bleibt verborgen:

virtual int numberOfValues() const = 0;virtual int valueAt(int index) const = 0;

5. Komponenten und Klassen sollen klar definierte, möglichst homogene Auf-gabenbereiche besitzen – also eine hohe Kohäsion. Klassen, die mehrere Aufgaben erfüllen, welche nur indirekt miteinander zu tun haben sind aufzu-spalten. Die Trennung der Aufgabenbereiche führt zu verständlicherem und robusteren Code.

Zusammengefasst hat das Redesign also folgende Aufgaben zu erfüllen: Die Reduzierung der bestehenden Abhängigkeiten, die Einführung geeigneter Schnitt-stellen, sowie die Aufspaltung von Klassen, die eine zu vielfältige Rolle im Design der Anwendung einnehmen, und falls nötig die Zusammenführung von Funktionalität, die über das Programm verteilt ist.

5.2 Ansätze für Redesignverfahren

Es gibt verschiedene Möglichkeiten ein Redesign vorzunehmen, um eine Soft-ware in die gewünschte modulare Architektur zu überführen. Ein bottom-up An-satz wäre, im kleinen Rahmen zu beginnen und zunächst lokale Designschwächen durch Refactoringtechniken zu beheben. Nachdem Mängel innerhalb der Klassen beseitigt wurden, können Fehler eine Ebene höher, in der Interaktion zwischen den Klassen, angegangen werden und schließlich geht es daran auf Architek-turebene zu arbeiten.

Als Endprodukt erhält man eine komplett runderneuerte Software. Da man vor allem zu Beginn nur in einem kleinen Bereich arbeitet, ist es außerdem nicht er-forderlich, die zu überarbeitende Anwendung komplett zu kennen. Man kann diesen Weg also auch schon ohne umfangreiche Analyse gehen. Zu dem Zeit-punkt, an dem man beginnt die programmweite Architektur zu ändern, hat man durch die vorhergegangenen Schritte theoretisch genug Kenntnisse erworben, um dies erfolgreich tun zu können.

Der Nachteil dieser Methode ist sicherlich der hohe Zeitaufwand sowie die äußerst schlechte Planbarkeit, wenn man nicht genau weiß, wie viele Mängel zu beseitigen sind und wie groß der Aufwand für jeden einzelnen sein wird. Außerdem entstehen bei der Durchführung nicht unbedingt eigenständige Komponenten. Diese müssen anschließend noch gesondert herausgearbeitet werden.

Ein zweiter Ansatz ist ein top-down Verfahren, das sich von den Komponenten ausgehend der Quellcodeebene annähert. Das bedeutet natürlich, dass die Komponenten der Zielarchitektur anders als beim bottom-up Verfahren bereits namentlich bekannt sein müssen. Ist das der Fall, wird sich zunächst auf eine Komponente konzentriert. Diese wird dann überarbeitet, Code ausgesondert, Code eingegliedert, der bisher fälschlicherweise in anderen Komponenten lag, sowie die

45

Page 52: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Entwurf einer neuen Architektur

Schnittstelle angepasst. Das Ziel ist es letztendlich die Komponenten sauber von einander abzugrenzen. Oberstes Anliegen bei ihrer Umgestaltung ist daher ihre Abhängigkeiten und ihre Schnittstellen zu präzisieren und zu minimieren. Dies führt man so für alle Komponenten durch.

Über die Funktionalität der Anwendung muss man hierfür möglichst gut Be-scheid wissen. Der Nachteil dieser Methode besteht darin, dass die Komponenten in erster Linie oberflächlich überarbeitet werden. Sie werden danach zwar funktionierende Schnittstellen besitzen und gut von einander abgegrenzt sein, aber ihr Inneres wird nur in Teilen berührt werden, da dieses Vorgehen sich in erster Linie auf diejenigen Teile des Quellcodes konzentriert, die an den Interaktionen zwischen den Komponenten beteiligt sind. Dafür ist jedoch der Zeitaufwand geringer und falls die Entscheidung fällt, das Innenleben einer Komponenten ebenfalls einem Redesign zu unterziehen, kann dies in einer geschlossenen Umge-bung geschehen ohne die anderen Komponenten zu beeinflussen bzw. ohne sie überhaupt kennen zu müssen. Sind mehrere Entwickler mit dem Redesign beauf-tragt, lässt diese Herangehensweise zudem eine bessere Arbeitsteilung zu. Unser Vorgehen beim Redesign von Volume Studio wird wegen der genannten Punkte diesem zweiten Ansatz entsprechen.

5.3 Redesign von Volume Studio

Das Redesign soll nun Komponente für Komponente in die Tat umgesetzt werden. Dazu muss zunächst bekannt sein, welche Komponenten überhaupt zu betrachten sind. Die Analyse von Volume Studio hat vier Komponenten hervorge-bracht, die als Orientierungshilfe dienen werden. Deren nähere Betrachtung kann zu der Feststellung führen, dass noch weitere Komponenten von ihnen abgespal-ten werden können.

Während meiner Arbeit an Volume Studio wurde dieses aktiv weiterentwickelt, so dass einige Neuerungen hinzugekommen sind, die in der Analyse keine Be-rücksichtigung fanden. Ich werde diese an geeigneter Stelle ansprechen, sofern notwendig.

Bei der Durchführung des Redesigns wird jede Abhängigkeit einer Komponenten zu einer Anderen betrachtet und entschieden, ob diese ohne Ein-buße der Funktionalität beseitigt werden kann. Außerdem werden Abhängigkeiten anderer Komponenten von der momentan untersuchten zurückverfolgt und Schnittstellen eingeführt, welche diese Komponenten an Stelle der konkreten, nicht länger öffentlichen, Klassen benutzen sollen.

Um das System lauffähig zu halten, werden die Funktionsaufrufe aller fremden Komponenten zunächst auf diese neuen Schnittstellen umgeleitet, während das Redesign durchgeführt wird. Die Schnittstellen werden daher zu Anfang einige Methoden beinhalten, die später beim Redesign der anderen Komponenten als überflüssig bewertet werden können. Sie werden außerdem in den meisten Fällen nicht von Anfang an vollständig sein, sondern erst nach und nach aufgebaut.

Nach der Überarbeitung aller Komponenten wird ein Gesamtbild von Volume Studio präsentiert und die Einhaltung der zuvor formulierten Architekturan-forderungen überprüft.

46

Page 53: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

5.3.1 Komponenten

5.3.1 Komponenten

Begonnen wird das Redesign nun mit der Komponente Core. In ihr findet sich der Einstiegspunkt der Anwendung und sie stellt für sich allein quasi ein minimales Volume Studio dar. In einem Pluginsystem ist es von Vorteil, wenn dieser Teil der Anwendung ohne weitere Komponenten ausführbar ist. Natürlich fehlt dann jedwede Funktion, die Volume Studio interessant macht, aber die Komponenten sollen im Idealfall zur Laufzeit geladen werden können.

Core

Die Komponente Core enthält die Hauptfenster26 des Programms sowie die VolumeManager und MeshManager Implementierungen, welche von den meisten anderen Komponenten beansprucht werden.

Die Klasse MainWindow stellt das Hauptfenster dar, über dessen Menüleiste sich weitere Fenster öffnen lassen. SurfacesWindow und VolumesWindow offe-rieren Möglichkeiten für das Laden/Löschen von Meshes bzw. Volumen. Das GLVolumeWidget ist wie gehabt das Fenster, in das diese dann gezeichnet werden. Die Schnittstelle GLWidget wurde aus ihm extrahiert, da auch andere Komponente auf dieses Fenster zugreifen möchten. Das bei der Überarbeitung der

26 Während meiner Arbeit an Volume Studio wurde durch einem anderen Entwickler die Benutzeroberfläche von VolumeStudio überarbeitet. Die zuvor in VolumeMainWindow unterge-brachten Elemente wurden auf mehrere Fenster verteilt.

47

Illustration 1: Die Komponente Core nach dem Re-design.

Page 54: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Entwurf einer neuen Architektur

Benutzeroberfläche eingeführte SettingsClient Interface ermöglicht das Speichern von Einstellungen der Fenster in einer *.ini Datei, die beim Start der Anwendung ausgelesen wird, um die Einstellungen der letzten Sitzung wiederherzustellen.

Das GLVolumeWidget enthält nun statt einem einzigen KeyHandler Objekt eine beliebige Zahl von InputHandlern. Diese behandeln neben Tastatur- auch Mauseingaben. Findet eine Eingabe statt, geht GLVolumeWidget die InputHandler durch, bis einer das Ereignis verarbeitet. Im Moment können InputHandler ein-ander blockieren, wenn sie die selben Ereignisse verarbeiten. Die Möglichkeit Ta-statur- oder Mausaktionen auf andere Tasten zu legen gibt es in Volume Studio noch nicht. Zur Zeit bestehen aber diesbezüglich auch noch keine Konflikte.

Ansonsten unterteilt sich die Komponente Core in zwei Bereiche: den für Meshes und den für Volumen. Über den die Meshes betreffenden wurde im vor-hergegangenen Kapitel bereits gesprochen. Derjenige für Volumen ist dem sehr ähnlich.

Die Klasse FileHandler, dessen Derivate und die Klasse Reader wurden von anderer Stelle aus hinzugefügt, während ich noch mit der Analyse beschäftigt war. Sie Implementieren im Grunde eine Zuständigkeitskette, ähnlich wie die MeshFileHandler Klassen. Da FileHandler jedoch bereits einigen volumenspezi-fischen Code enthält, habe ich davon abgesehen, diese Klasse auch für Meshes zu nutzen.

Die Klassen VolumeManagerImpl und MeshManagerImpl sind auch für die Er-stellung der Volume bzw. Mesh Instanzen zuständig, deren Implementierungen (wie auch die des SceneManagers) Teil der Komponente Visualization sind.

Wie man sieht wurde sich bei der Komponenten Core auf das Wesentliche beschränkt. Sie ist von Visualization abhängig, da dort der SceneManager und die Volume und Mesh Klassen implementiert sind. Ohne diese kann Core schlicht keine Meshes oder Volumen auf den Schirm bringen.

Überhaupt können Interfaces wie Mesh, Volume, MeshData, VolumeData, aber auch die hier nicht dargestellte Interfaces TimeShader und ShaderCode, die im Diagramm der Visualization Komponente zu sehen sein werden, eher als zu Core zugehörig angesehen werden, da diese Interfaces generell sind und auch von anderen Visualisierungskomponenten implementiert werden sollten, nicht nur von der aktuellen. Im späteren Pluginsystem werden diese Interfaces Gemeingut in Volume Studio sein.

Beachtenswert ist, dass auch innerhalb der Komponenten Schnittstellen einge-führt wurden. Sollte die Entwickler von Volume Studio die Entscheidung treffen, die Verwaltung der Volumen und diejenige für Meshes in verschiedenen Komponenten unterzubringen, wäre dies mit geringem Aufwand möglich. Ebenso sind die Bestandteile der Benutzeroberfläche von den anzuzeigenden Daten ge-trennt, so dass diese beiden Programmteile weitgehend unabhängig von einander weiterentwickelt werden können.

Visualization

Die Komponente Visualization ist für das Rendern der Volumen und Meshes zuständig. Dies ist eine Kernfunktion der Anwendung und andere Komponenten greifen wiederum auf die dargestellten Volumen bzw. deren Shader zu.

48

Page 55: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

5.3.1 Komponenten

Wie zuvor mehrfach erwähnt, nutzt Volume Studio für die Visualisierung die OpenSG Bibliothek. Idealerweise sollte sämtlicher Code, der mit dem Rendern zu tun hat, in die Komponente Visualization bewegt werden. Es bietet sich an, dies derart zu tun, dass die übrigen Komponenten nicht mehr selbst die OpenSG Bi-bliothek benutzen müssen, um zum Beispiel die Kameraposition oder die Darstel-lungsweise der Volumen zu ändern. Gelingt dies, ist Visualization die einzige Komponente mit OpenSG Abhängigkeit und kann so leicht gegen eine Komponente ausgetauscht werden, die ein anderes System zur Visualisierung benutzt, ohne die anderen Komponenten zu tangieren.

In der Tat erfuhr ich im Gespräch mit einigen Entwicklern von Volume Studio, dass sie liebend gern auf OpenSG verzichten würden, weil es für den Anwendungszweck nicht unbedingt optimal sei und zudem noch fehlerhaft. Nach meinen eigenen Erfahrungen während der Arbeit an Volume Studio ist OpenSG tatsächlich zumindest gewöhnungsbedürftig und dazu noch schlecht dokumentiert.

Eine Nebenanforderung an die Komponente Visualization ist daher, dass sie sämtlichen OpenSG-bezogenen Code kapselt. Dies schließt auch den Code zum Visualisieren polygonaler Meshes mit ein, der in den während der Analyse erstell-ten Diagrammen noch etwas versteckt in Core zu finden war. Das folgende Dia-gramm zeigt die unter diesen Gesichtspunkten umgestaltete Komponente Visualization.

49Abbildung 5.1: Die Komponente Visualization im neuen Design.

Page 56: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Entwurf einer neuen Architektur

Entscheidende Neuerung in Visualization ist die Nutzung der hinzugekom-menen Interfaces. Diese sind gleichzeitig die Schnittstellen zu anderen Komponenten. Die im Diagramm grau unterlegten Klassen sind die konkreten Im-plementierungen, welche von außen nicht sichtbar sind. Schnittstellen und Imple-mentierungen sind also sauber getrennt. Viele Abhängigkeiten Visualizations von anderen Komponenten konnten entfernt werden, einzig die Core Komponente wird benötigt.

Neu ist weiterhin der SceneManager. Er versteckt den SceneManager von OpenSG und gleichzeitig die Tatsache, dass Visualization einen Szenegraphen benutzt. Schließlich könnten andere Visualisierungskomponenten ein anderes Sys-tem umsetzen wollen. Da bei der Nutzung von Volume Studio häufig nur sehr wenige Objekte zur selben Zeit zu Visualisieren sind (oft nur ein einziges Volu-men), ist dies auch gar nicht so abwegig.

Die Stereo* Klassen ermöglichen das Darstellen der Szene in stereoskopischen Bildern. Sie wurden in diese Komponente verlagert, weil sie dazu OpenSG Funktionalität nutzen. Ich habe zunächst davon abgesehen, sie als eigenständige Komponente mit Abhängigkeit von dieser konkreten Visualisierungskomponente, zu etablieren.

Unschön ist die Anwesenheit der Klassen CrossSectionImpl und CrossSectionPlane. Da aber insbesondere CrossSectionImpl Klassen der Komponente benutzt, die ich ungern veröffentlichen möchte (in erster Linie Brick), sind diese vorerst nicht aus Visualization wegzudenken.

Auf die neue Klasse Volume und weitere Änderungen an der Klasse DVRTimeShader möchte ich gesondert eingehen.

Haltung von Daten pro Volumen

Im alten Design war die Klasse VolumeInfo (von uns der Komponente Core zugeteilt) der Dreh- und Angelpunkt des Systems. Durch sie konnten verschiedene Rendering Einstellungen für das Volumen vorgenommen werden. Außerdem wurden in ihr Informationen, die pro Volumen vorliegen sollten, als Attribut gespeichert. Wenn eine neue Komponente eingeführt wurde, die irgendeine In-formation mit einem bestimmten Volumen assoziieren wollte, wurde VolumeInfo schlicht um diese Information erweitert, was natürlich keine sehr flexible Lösung ist. Die Klasse wurde nun durch die Klasse Volume ersetzt, die ähnlich mächtig ist, aber ein anderes System benutzt, um es fremden Komponenten zu ermöglichen Informationen pro Volumen zu speichern.

Die neue Klasse besitzt einen Container, der nahezu beliebige Objekte27 unter einem Schlüssel speichern kann. Wenn zum Beispiel eine Komponente XY Daten für das Volumen ablegen will, dann kapselt sie diese in einer selbstdefinierten Klasse XYData. Der Schlüssel ist ein eindeutiger String, der von XY selbst ge-wählt wird, beispielsweise der Name der Klasse: „XYData“. Um die Gefahr von

27 Die Objekte müssen lediglich eine gemeinsame Basisklasse haben, damit ein Downcast durch-geführt werden kann. Die Wahl fiel auf die Qt Klasse QObject. Laut Qt Dokumentation können diese per qobject_cast auch über die Grenzen dynamischer Bibliotheken hinweg umgewandelt werden, was für unser zukünftiges Pluginsystem wichtig ist.

50

Page 57: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

5.3.1 Komponenten

Namenskonflikten zu eliminieren, kann man Strings benutzen, die ähnlich wie die Namen von Java Packages hierarchisch aufgebaut sind.

Die wohl wichtigste Eigenschaft diese Systems ist, dass die Entwickler der Komponenten XY die Deklaration von XYData für andere Entwickler veröffentlichen können, so dass auch deren Komponenten in der Lage sind die Daten zu nutzen. Die Alternative dazu wäre gewesen, dass jede Komponente diese Daten in einem eigenen Container hält. Das erscheint zunächst naheliegend, aber dann müssten fremde Komponenten, welche die Daten erfragen möchten, wissen, welche Komponenten nun für deren Verwaltung zuständig ist. Das funktioniert so lange, wie es nur eine solche geben kann, aber sobald es alternative Urheber dieser Daten gibt, wird es kompliziert. Die Lösung, die Daten in der Klasse Volume zu speichern, um sie komponentenübergreifen zugänglich zu machen, ist dagegen simpel und flexibel und wurde auch von den Entwicklern, mit denen ich im Gespräch war, favorisiert. Man beachte, dass Komponenten, die ihre Daten nicht im Container des Volumens ablegen möchten, dazu nicht gezwungen sind.

Shading von Volumen

In der Klasse DVRTimeShader findet sich der Code zum Shading von Volu-men. Jedes Volumen hat einen solchen Shader. Ein Shader ist ein Programm, das die Darstellung eines Objekts am Bildschirm in einer bestimmten Weise ändert. Diese Änderungen können die Eckpunkte von Polygonen oder die mit diesen Eck-punkten assoziierten Daten betreffen (solche Programme nennt man Vertex Shader). Andere Shader berechnen den Farbwert, der für einen bestimmten Pixel der Oberfläche eines Objekts verwendet werden soll (Pixel oder Fragment Shader), wodurch sich beispielsweise bestimmte Beleuchtungsmodelle umsetzen lassen. Volume Studio macht insbesondere von dieser zweiten Art von Shadern Gebrauch, um die Darstellungsweise eines Volumens zu beeinflussen. Einige Funktionalität von Volume Studio – beispielsweise die Segmentierung – ist auf be-stimmte Shaderprogramme angewiesen, um zu funktionieren.

Die Schader, die von Volume Studio verwendet werden, sind in GLSL ge-schrieben, der OpenGL Shading Language, einer Sprache, die stark an C ange-lehnt ist. In VolumeStudio besteht ein Shader aus mehreren individuellen Pro-grammstücken bzw. Funktionen, die nacheinander ausgeführt werden. Aus wel-chen konkreten Funktionen sich ein Shader zusammensetzt, bestimmen die Ein-stellungen des Volumens, die vom Benutzer oder anderen Programmteilen vorge-nommen werden können. Der Aufbau eines Shaders unterliegt jedoch einigen Re-striktionen. Einige Programmteile können nicht gemeinsam benutzt werden und auch die Reihenfolge, in der sie dem Shader hinzugefügt werden, ist von Bedeu-tung. Sie rufen sich gegenseitig auf und wie auch in C müssen Funktionen und Va-riablen in GLSL vor ihrer Benutzung deklariert sein. Die Programmteile liegen in Textform vor, entweder als Textdatei oder als String im Quellcode.

Ein kompletter Shader besteht in Volume Studio aus genau vier Abschnitten. Dabei ruft die Funktion des ersten Abschnitts diejenige des zweiten auf, diese wiederum die des dritten und so weiter. Die Ergebnisse der Funktionen werden in der Regel ebenfalls weiter gereicht, so dass ein Programmteil die in einem vorhe-rigen Abschnitt berechnete Daten verwenden kann.

51

Page 58: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Entwurf einer neuen Architektur

Bisher wurde mit einigen if/else Ausdrücken sichergestellt, dass sich die Pro-grammteile zu einem nutzbaren Shader zusammensetzen. Während des Redesigns habe ich jedoch eine andere Methode implementiert.

Zunächst habe ich mir aus dem bisherigen Code erarbeitet, welche Programm-teile in welchem Abschnitt vorkommen. Anschließend galt es herauszufinden, bei welchen Einstellungen ein Programmteil verwendet wird. Für jede einzelne Ein-stellung wurden dann zwei boolesche Variablen eingeführt, die anzeigen sollen, ob die korrespondierende Funktionalität ein- oder ausgeschaltet ist, das heißt es ist immer jeweils genau einer dieser beiden booleschen Werte „wahr“. Für jeden der vier Abschnitte des Shaders gibt es nun eine Gruppe solcher booleschen Varia-blen. Jede gültige Kombination dieser Variablen wird auf einen Shaderprogramm-teil abgebildet. Dabei können mehrere Kombinationen auf ein und denselben Pro-grammteil verweisen.

Diese Implementierung erlaubt es anderen Komponenten und Klassen ein Shaderprogrammteil für eine bestimmte Kombination von Einstellungen zu de-finieren. Dafür wurde das ShaderCode Interface geschaffen, dass auf Anfrage das Textfragment liefert, welches den Code darstellt. Zusätzlich wurden Methoden eingeführt, die es erlauben Parameter und Texturen an das Shaderprogramm zu übergeben, welche zuvor in der Anwendung erstellt wurden. Bisher waren alle Shader und die von ihnen zu benutzenden Texturen in der Klasse DVRTimeShader definiert. Durch die Änderungen können nun die anderen Komponenten bestimmen, welcher Shader für ihre Funktionalität benutzt werden sollte und welche Daten ihm zu übergeben sind.

Die Implementierung hat jedoch noch einige Schwächen. Angenommen eine neue Komponente möchte ihren eigenen Shadercode einbringen für einen Darstel-lungsmodus, den es bisher nicht gibt. Dafür gibt es zwei Möglichkeiten: Entweder der neue Code wird als Programmteil einem der bestehenden vier Shadingab-schnitte beigefügt oder es wird ein neuer Abschnitt eingeführt.

Wie im alten Design auch, sind Änderungen am Quellcode der Visualization Komponente aber auch der Shaderprogramme selbst nötig, wenn dem Shader ein Abschnitt hinzugefügt werden soll. Dass die Anzahl der Abschnitte, bzw. der Pro-grammteile in einem Shader, fest ist, hat seinen Grund. Die Programmteile rufen sich nacheinander auf. Dazu müssen sie selbstverständlich den ihnen nach-folgenden Programmteil kennen. Um also einen neuen Abschnitt einzuführen,

52

Abbildung 5.2: Ausführung der vier Teile eines Shaders.

Page 59: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

5.3.1 Komponenten

muss mindestens einer der bisherigen geändert werden. Angenommen es gibt mehrere Komponenten, die dies tun. Sie müssten sich alle kennen, um nicht gegenseitig ihre Änderungen zu überschreiben, und wenn die Anzahl der Ab-schnitte ein Mal geändert wurde, müssen sie außerdem wissen, wo sie sich nun in der neuen Ordnung einzufügen haben. Die Komplexität dieses Problems ist also nicht unerheblich.

Man könnte erwägen, einige extra Abschnitte einzuführen, die normalerweise leer sind, aber von Komponenten beliebig belegt werden können. Legt man diese Abschnitte zwischen den bisherigen an, haben Komponenten viele Möglichkeiten ihren Shadercode zu platzieren. Dabei ist jedoch der Performanceverlust zu be-denken, den auch Aufrufe leerer Funktionen hervorrufen können. Bei der Pro-grammierung von Shadern kann eine Codezeile mehr oder weniger deutliche Leis-tungsunterschiede bringen.

Nun zur Alternative, dem Einfügen des neuen Shadercodes in einen be-stehenden Abschnitt. Dies ist nur dann ohne Codeänderungen möglich, wenn die vorhandenen Einstellungsmöglichkeiten für Volumen bzw. dessen Shader ausreichen, um das neue Shadingprogramm anzusprechen.

Angenommen das Programm beschreibt eine neue Beleuchtungsmethode, die als Alternative zu den bisherigen anwählbar sein soll. Um überhaupt anwählbar zu sein, muss es eine entsprechende Option in der Benutzerschnittstelle geben. Zur Zeit sind diese Optionen größtenteils gesammelt in einem einzigen Fenster in Volume Studio zu finden, aber insbesondere wenn es noch weitere Einstellungs-möglichkeiten für den neuen Darstellungsmodus gibt, könnte man die notwen-digen Bildschirmelemente auch in einem durch die Komponente selbst zu de-finierenden Fenster unterbringen, ohne die Benutzbarkeit der Anwendung zu ge-fährden. Für die Segmentierungsfunktionalität wurde dies bereits so gemacht.

Das größere Problem ist, dass die Klasse DVRTimeShader die Option, welche über die Nutzung des neuen Shaderprogramms entscheidet, nicht kennt. Zur Zeit sind alle Einstellungsmöglichkeiten zusätzlich als Attribute von DVRTimeShader realisiert und neue müssten entsprechend im Code hinzugefügt werden.

Um generell verschiedene Programmteile pro Shaderabschnitt zu erlauben, sollte man diese Attribute eventuell anonym in einem Container halten, der belie-big zur Laufzeit erweitert werden kann. Bei den Attributen handelt es sich ohne-hin meistens um boolesche Variablen, die lediglich anzeigen, ob ein Einstellung eingeschaltet ist oder nicht, aber auch numerische Werte kommen vor. Um die At-tribute ansprechen zu können, müssten sie Schlüssel erhalten, beispielsweise Namen, die auch in der Benutzeroberfläche verwendet werden können. Ich habe diese Möglichkeit noch nicht implementiert und auch nicht getestet aber eventuell werden die Entwickler von Volume Studio sie in Zukunft in Betracht ziehen.

Damit nun genug von Shadern. Weiter mit den restlichen Komponenten.

Tissue

Die Komponente Tissue wurde nur geringfügig geändert. Ihre wurde eine Klasse TransferFunctionData hinzugefügt, die im Container eines Volumens gespeichert werden kann, so dass andere Komponenten darauf zugreifen könnten. TransferFunctionData kapselt eine beliebige Zahl von Filtern und die beiden

53

Page 60: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Entwurf einer neuen Architektur

Spatial*TransferFunction Klassen. Abhängig ist die Komponente Tissue allein von der Komponenten Core.

Am Innenleben dieser Komponenten hat sich nicht viel geändert. Insbesondere das Filter Interface (IFilterWidget) ist immer noch unansehnlich, da es öffentliche Attribute, statt die Deklarationen von Zugriffsmethoden auf solche enthält, und die Integrierung der Filter in Transfer2dWindow ist ebenfalls unverändert. Aber diese Fehler stören die Architektur nicht besonders, weshalb ich ihrer Behebung keine hohe Priorität beigemessen habe. Bevor jedoch weitere Filter hinzugefügt werden oder Ähnliches, sollte die Komponente noch ein Mal entgratet werden.

Segmentation

Die Komponente Segmentation erfuhr bereits reichhaltige Verbesserungen durch die Volume Studio Entwickler, während ich mich noch in der Analysephase befand. Daher gab es hier für mich hier nicht viel zu tun. Wie auch in Tissue wurde eine Klasse SegmentationData eingeführt, deren Instanziierungen im Con-tainer der Volumen platz finden.

54

Abbildung 5.3: Die Komponente Tissue nach dem Redesign

Page 61: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

5.3.1 Komponenten

Interessant ist, dass Segmentation als zur Zeit einzige Komponente Daten einer anderen aus dem Container des Volumen nutzt, nämlich die CrossSectionData In-stanzen. Welche konkrete andere Komponente diese erstellt, ist unwichtig, da sie über die Volume Schnittstelle bezogen wird und nicht von der Komponente, wel-che die Daten anlegt. Damit besteht auch keine Abhängigkeit zu jener Komponenten.

Abbildung 3.9: Die Komponente Segmentation nach dem Redesign.

Die Klassen SmoothingFilter und SegmentationFilter sind Basisklassen für eine inzwischen stark angewachsene Zahl an Algorithmen, die ich der Übersicht halber aus dem Diagramm fern gehalten habe. Für jeden Algorithmus, also jedes Derivat dieser Basisklassen, gibt es eine Factory, mittels derer die Algorithmen in-stanziiert werden.

Weitere Komponenten

Wie Eingangs angedeutet, konnten während des Redesigns weitere funktionale Komponenten zusätzlich zu den vier bei der Analyse festgestellten gewonnen werden. Diese sollen kurz und knapp vorgestellt werden.

Presentation

Die Komponente Presentation enthält die Funktionalität, die ehemals in der Klasse AnimationKeyHandler zu finden war, also das Laden und Speichern der Storyboards zu Präsentationszwecken. Das Storyboardkonzept verlangt allerdings noch einige Überarbeitung. Die XML Knoten eines Storyboards sollten von den-jenigen Klassen, auf die sie sich beziehen, gelesen und geschrieben werden, nicht

55

Page 62: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Entwurf einer neuen Architektur

von der Komponenten Presentation, denn dann müsste diese sämtliche im Story-board referenzierbaren Klassen kennen. Da die Erstellung eines neuen Konzepts für Storyboards den vorgesehenen Zeitrahmen gesprengt hätte, wurde das Problem nicht weiter behandelt, so dass diese Komponente nun bis zu ihrer Überarbeitung weitgehend unbenutzbar ist.

CarveClipping

Eine weitere Komponente ist CarveClipping. Während der Analyse habe ich diese Funktionalität Visualization zugeordnet. Da sie aber keinerlei OpenSG Code nutzt, ist sie theoretisch auch mit anderen Visualisierungskomponenten nutzbar. Das Clipping selbst ist durch ein Shaderprogramm gelöst. Die Daten, die der Shader zum Clipping benötigt, werden in der CarveMapData Klasse gespeichert und bei Zeiten vom CarveMapper an den Shader übergeben.

CrossSection

Zu letzt ist noch die Komponente CrossSection zu erwähnen. Im Analyseteil wurde ausgeführt, dass deren Herausarbeitung problematisch ist. In der Tat konn-ten Teile, die intuitiv zu dieser Komponente gehören, wegen zu enger Kopplung

56

Abbildung 5.4: Die Komponente Presentation.

Abbildung 5.5: Die Komponente CarveClipping.

Page 63: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

5.3.1 Komponenten

mit Klassen aus Visualization nicht in diese Komponente überführt werden. Daher besteht eine Abhängigkeit von CrossSection zu Visualization.

5.3.2 Gesamtbild

Das Gesamtbild aller Komponenten und ihrer Abhängigkeiten sieht nun wie folgt aus.

Wie man sieht, sind bis auf CrossSection alle Komponenten lediglich von Core abhängig. Um Volumen und Meshes darzustellen benötigt Core noch die Vi-sualisierungskomponente, sonst bleibt der Bildschirm leer. Das heißt also, dass man Volume Studio auf die Komponente Core reduzieren könnte, und man hätte dennoch eine ausführbare Anwendung – wenn auch ohne nennenswerte Funktionalität. Alle weiteren Komponenten sind dann optional. Die Anforderung der minimalen Abhängigkeiten kann damit als erfüllt betrachtet werden.

Alle Komponenten, die ihre Funktionalität für Andere nutzbar machen wollen, definieren Schnittstellen. Die Core Komponente definiert außerdem eine Schnitt-stelle, die Visualisierungskomponenten zu implementieren haben, um als solche fungieren zu können. Die Interfaceklassen, die als Komponentenschnittstellen dienen, sind abstrakt und beinhalten keine Implementierungsdetails. Die An-

57

Abbildung 5.6: Die Komponente CrossSection.

Abbildung 5.7: Übersicht über die Komponenten von Volume Studio nach dem Redesign.

Page 64: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Entwurf einer neuen Architektur

forderungen an die Schnittstellen sind also ebenfalls erfüllt. Auf Nachweise, der Anforderungen „schmale Schnittstelle“ und „keine Annahme über die Imple-mentierung“ möchte ich hier verzichten. Sie betreffen die konkreten Methoden der Interfaces und sind ohne deutlich tiefer auf die technische Funktionsweise Volume Studios einzugehen, nicht zu erbringen.

Was die Teilung einiger Klassen nach Aufgabenbereichen – also die Erhöhung der Kohäsion – angeht, so wurde insbesondere der Kern von Volume Studio dementsprechend umgestaltet. In einigen Komponenten gibt es jedoch noch Nachholbedarf. So birgt beispielsweise Tissue noch einiges Redesignpotential. Dies hat aber keine Auswirkungen auf die Architektur außerhalb dieser Komponente, so das nun das Pluginsystem eingeführt werden kann.

5.4 Das Pluginsystem

Die während des Redesigns formulierten Komponenten sollen nun in Plugins umgewandelt werden. Aus Nutzersicht sind Plugins Programmteile, die sich nach Bedarf zur Laufzeit hinzufügen und entfernen lassen. Für Entwickler stellt das Pluginsystem die Möglichkeit dar, Erweiterungen für die Anwendung zu erstellen, ohne das bestehende System modifizieren zu müssen.

In diesem letzten Teil der Arbeit, wird ein Pluginkonzept vorgestellt, dass die Anforderungen an Volume Studios neue Architektur, wie Erweiterbarkeit und Aus-tauschbarkeit der Komponenten, unterstützt.

Technisch gesehen ist ein Plugin eine Programmbibliothek, die sich zur Lauf-zeit des Programms laden und auch entladen lässt. Qt bietet einen Mechanismus, um Programmbibliotheken als Plugins zu laden. Dabei wird im Quellcode des Plugins genau eine Klasse als zu exportieren deklariert und durch einen QPluginLoader im Hauptprogramm genau diese Klasse des Plugins instanziiert, so dass mit ihr gearbeitet werden kann. Die Implementierung des Pluginsystems wird sich dieses Mechanismus bedienen. Er ist in der Dokumentation von Qt nä-her erläutert28.

5.4.1 Konzept

Plugins kommunizieren über eigens definierte Schnittstellen. Diese Schnitt-stellen wurden bereits während des Redesigns konstruiert, so dass es theoretisch bereits jetzt mit geringem Aufwand möglich ist, die Komponenten getrennt von-einander als Bibliotheken zu kompilieren.

Das Allein reicht jedoch nicht aus. Das Hauptprogramm muss wissen, welche Bibliotheken zu laden sind. Dies steht erst zur Laufzeit fest. Weil das System in der Lage sein soll, eine große Anzahl verschiedener Plugins zu behandeln, auch solche, die erst in der Zukunft in weiteren Arbeiten erstellt werden, muss es einen generellen Mechanismus zum Laden und Entladen von Plugins geben. Es ist eine Schnittstelle zu definieren, die alle Plugins implementieren müssen, um die nö-tigen Informationen für ihr Einbinden in das Hauptprogramm erfragen zu können.

28 http://doc.trolltech.com/4.3/plugins-howto.html

58

Page 65: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

5.4.1 Konzept

Was dieses „Einbinden“ bedeutet, ist ebenfalls festzulegen. Das Hauptpro-gramm hat dafür zu sorgen, dass Plugins sich in einer Art und Weise in das Pro-gramm einklinken können, die es ihnen gestattet ihren Dienst zu verrichten. Das beinhaltet, dass Plugins das Hinzufügen von Bedienelementen zur Benutzeroberfläche ermöglicht wird. Außerdem müssen sie die Schnittstellen anderer Komponenten ansprechen können, deren Funktionalität sie nutzen. Das Hauptprogramm hat also dafür Sorge zu tragen, dass die benötigten Schnittstellen zur Verfügung stehen, sofern sie im System vorhanden sind. Dies führt zu einem weiteren Problem: Sobald ein Plugin von einem anderen abhängig ist, kann es nur genutzt werden, sofern dieses andere im System verfügbar ist. Da angenommen werden muss, dass dem Benutzer das Hinzufügen und Entfernen von Modulen zu jeder Zeit möglich ist, muss die Erfüllung und Nichterfüllung von Abhängigkeiten zwischen Plugins vor deren Benutzung geprüft werden. Zwei Möglichkeiten kommen in den Sinn:

I. Die Plugins entscheiden selbst, ob sie benutzbar sind, indem sie die erforderlichen Schnittstellen im System erfragen und aus dem Vorhandensein oder Nichtvorhandensein ihre eigenen Konsequenzen ziehen.

II. Eine zentrale Instanz verwaltet die Plugins sowie deren Schnittstellen und kann Auskunft geben, ob eine Schnittstelle bzw. ein Plugin nutzbar ist, sowie dafür sorgen, dass ein Plugin aktiviert oder deaktiviert wird.

Für ersteres spricht, dass den Plugins maximale Freiheit gegeben wird. Dies bedeutet allerdings auch eine größere Verantwortung für ihre Entwickler, wenn sie selbst sicherstellen müssen, das zu einem gegebenen Zeitpunkt eine Funktion verfügbar ist.

Die zweite Möglichkeit führt die Verwaltung von Pluginabhängigkeiten in einem Punkt zusammen, so dass sie nur ein Mal implementiert werden muss. Stellt man außerdem fest, dass irgendeine zentrale Instanz ohnehin nötig ist, um einem Plugin mitzuteilen, dass ein weiteres geladen wurde, oder um die vor-handenen Plugins zu erfragen, erscheint diese zweite Möglichkeit als die bessere Wahl. Der Hauptkomponente von Volume Studio ist also ein Pluginmanager hin-zuzufügen.

5.4.1.1 Der Pluginmanager

Die komplexeste Aufgabe des Pluginmanagers besteht in der Beurteilung der Abhängigkeiten, wenn Plugins geladen oder entladen werden. Bei Entfernung eines Plugins aus dem System, muss geprüft werden, ob andere dadurch un-benutzbar werden. Umgekehrt ist, wenn neue Schnittstellen verfügbar sind, zu prüfen, ob inaktive Plugins dadurch nutzbar werden.

An dieser Stelle ist zu betonen, dass Plugins Abhängigkeiten zu Schnittstellen und nicht zu anderen Plugins definieren. Dies ermöglicht die Austauschbarkeit der Komponenten, denn einem Plugin kann es gleichgültig sind, wer eine konkrete Schnittstelle implementiert. Es interessiert sich nur für das Ergebnis, dass diese Implementierung erzielt. Durch die Abhängigkeit allein von Schnittstellen, können Plugins mit gleicher Funktionalität aber unterschiedlicher Umsetzung

59

Page 66: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Entwurf einer neuen Architektur

gegeneinander ausgetauscht werden oder gar solche, die mehrere Schnittstellen realisieren durch kleinere Plugins, die nur einige davon umsetzten, ersetzt werden.

Plugins teilen also mit, welche Schnittstellen sie benötigen. Dabei ist besonders darauf zu achten, dass sie gegenseitig von einander abhängig sein können, wenn sie Schnittstellen implementieren, die das jeweils andere Plugin benötigt. Zyklische Abhängigkeiten sind nicht auflösbar und dürfen daher nicht vorkom-men.

Im folgenden nun die Aufgaben des Pluginmanagers, die sich aus den bishe-rigen Überlegungen ergeben:

• Eine Programmbibliothek aus dem Dateisystem laden oder entladen.

• Benötigte und bereitstellbare Schnittstellen von Plugins erfragen.

• Schnittstellen von Plugins auf Anfrage herausgeben sofern vorhanden.

• Entscheiden, ob die Anforderungen eines Plugins erfüllt sind.

• Ein Plugin aktivieren bzw. initialisieren und dem System hinzufügen, so dass es nutzbar ist.

• Ein Plugin deaktivieren und aus dem System entfernen, wenn es unbenutzbar wird oder der Benutzer es entladen möchte.

Zum Abschluss dieses Abschnitts soll noch auf ein Feststellung bezüglich zyklischer Abhängigkeiten hingewiesen werden. In den Komponenten der neuen Architektur Volume Studios (Abbildung 5.7) ist eine zyklische Abhängigkeit zu sehen. Sie betrifft die Komponenten Core und Visualization. Während des Redesigns war dies noch kein Problem. Solange die Komponenten noch explizit im Code und in fester Reihenfolge instantiiert wurden, konnte die Initialisierung von Core und Visualization derart durchgeführt werden, dass kein Konflikt ent-steht. Im Pluginsystem ist die Initialisierung der Plugins jedoch generisch und Spezialfälle sollen nicht mehr vorkommen.

In der Beschreibung des Gesamtsystems nach dem Redesign (Abschnitt 5.3.2) wurde festgestellt, dass Core auch ohne Visualization lauffähig ist und lediglich die Funktionalität, Volumen und Meshes erstellen bzw. darstellen zu können, vom Vorhandensein der Visualisierungskomponente abhängt. Daher lässt sich die Aus-sage treffen, dass Core nicht grundsätzlich von Visualization abhängig ist. Es trifft lediglich zu, dass ein Teil der Funktionalität dieser Komponenten ohne die andere nicht zur Verfügung steht. Demnach besteht auch keine zyklische Abhängigkeit zwischen den beiden Komponenten.

Möglicherweise führen zukünftige Arbeiten an Volume Studio dazu, dass Core weiter aufgespalten wird. Dass dies theoretisch möglich ist, wurde in der Beschreibung dieser Komponente angedeutet. In dem Fall kann es sein, dass sich diese leichte Unklarheit bezüglich der Abhängigkeiten auflöst. In dieser Arbeit werden keine weiteren Schritte in diese Richtung unternommen.

60

Page 67: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

5.4.1 Konzept

5.4.1.2 Die Pluginschnittstelle

Wie bereits erwähnt, muss eine allgemeine Schnittstelle eingeführt werden, über die der Pluginmanager die Plugins ansprechen kann, ohne wissen zu müssen, welche spezifische Funktionalität in ihnen steckt. Diese Schnittstelle ergibt sich teilweise aus den Anforderungen, die der Pluginmanager für die Erfüllung seiner Aufgaben an sie stellt: Das bekanntgeben benötigter und bereitgestellter Schnitt-stellen sowie das Liefern einer Instanz einer bestimmten Schnittstelle.

Doch auch die Plugins selbst haben Anforderungen. Um ihre Funktionalität dem Benutzer zur Verfügung zu stellen, ist ihnen das Hinzufügen von Be-dienelementen zu gestatten. In Volume Studio wurde das Problem gelöst, indem jedes Plugin ein oder mehrere Fenster bereitstellen kann. Der Pluginmanager leitet diese an das Hauptfenster weiter, wo sie dann erscheinen. Der Benutzer kann selbst entscheiden, welche Fenster er sehen möchte und wo sich diese befinden sollen. Weder der Pluginmanager noch das Hauptfenster müssen wissen, welche Bedienelemente ein solches Fenster beinhaltet oder welche Aufgabe es erfüllt, einzige Anforderung ist, dass ein Fenster von einer bekannten Basisklasse erbt, hier der Qt Klasse QWidget. Die Pluginschnittstelle muss also folgendes beinhal-ten:

• Gib benötigte Schnittstellen bekannt

• Gib bereitstellbare Schnittstellen bekannt

• Gib Instanz einer bestimmte bereitgestellten Schnittelle

• Aktiviere das Plugin

• Deaktiviere das Plugin

• Gib darzustellende Fenster

Zusätzlich sinnvoll ist es, Dinge wie den Namen des Plugins oder eine in-formelle Beschreibung zu liefern, die dem Benutzer zur Information dienen.

5.4.2 Implementierungsdetails

Nachdem das Konzept bekannt ist, kann es umgesetzt werden. In diesem Un-terkapitel sollen einige nennenswerte Details der Implementierung angesprochen werden.

5.4.2.1 Identifizierung von Plugins und Schnittstellen

Bisher wurde gesagt, dass der Pluginmanager Plugins verwaltet und Schnitt-stellen zwischen ihnen weiterreicht. Es wurde aber noch nicht erwähnt, wie er dazu in der Lage sein soll. Schnittstellen und Plugins müssen eindeutig identifi-ziert werden können. Für Plugins könnte man die Dateinamen der Programmbi-bliotheken heranziehen. Doch diese sind vom Nutzer änderbar und außerdem von Plattform zu Plattform unterschiedlich29. Es bietet sich an Strings zu nutzen und

29 Eine Programmbibliothek xyz würde standardmäßig auf einem Windows System xyz.dll und eauf inem Linux System libxyz.so heißen.

61

Page 68: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Entwurf einer neuen Architektur

eindeutige Namen zu vergeben, die von den Autoren der Plugins selbst bestimmt und im Quellcode festgelegt werden.

In der Programmiersprache Java wird ein hierarchisches Namensschema für sogenannte Packages benutzt, das sich aus mehreren Teilen, wie dem Namen des Herstellers sowie dem eigentlichen Bezeichner des Pakets zusammensetzt. Hier-durch wird die Gefahr von Namenskonflikten minimiert. Ich habe mich für ein ähnliches Schema entschieden und beispielsweise die Komponente Tissue de_upb_volumestudio_tissue genannt30. Schnittstellen benutzen ebenfalls dieses Schema, nur mit dem Namen der Schnittstelle sowie einer Versionsnummer am Ende, wie es auch in der Dokumentation von Qt vorgeschlagen wird31. So ist de_upb_volumestudio_plugin/1.0 der identifizierende Name der Pluginschnittstelle.

5.4.2.2 Benutzeroberfläche des Pluginmanagers

Damit der Nutzer Plugins Laden kann, muss diese Funktion in der Benutzeroberfläche von Volume Studio zur Verfügung gestellt werden. Der Folgende Screenshot zeigt den Dialog, über den Plugins verwaltet werden können. Im oberen Bereich findet sich eine Auflistung der geladenen Plugins, im Unteren sind nähere Informationen des ausgewählten Plugins gelistet, wie etwa seine Beschreibung und der Pfad zur Programmbibliothek im Dateisystem.

30 Es werden Unterstriche statt wie in Java Punkte benutzt, da es auf Linux Systemen ein Namensschema für Programmbibliotheken gibt, das Punkte nur an bestimmten Stellen erlaubt.

31 http://doc.trolltech.com/4.3/tools-plugandpaint.html

62

Abbildung 5.8: Der Pluginmanager Dialog.

Page 69: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

5.5 Zusammenfassung

5.5 Zusammenfassung

Dieses Kapitel hat die Überführung einer Software in ein modulares Design erläutert. Dazu gehören die Anforderungen, die an ein solches Design gestellt werden können, sowie Ansätze zur Durchführung des Redesigns.

Einem dieser Ansätze wurde gefolgt und Volume Studio eine neue Struktur gegeben sowie einige gravierende Mängel beseitigt. Die Anwendung wurde mo-dularisiert und ein Pluginsystem installiert. Einige Mängel sind jedoch weiterhin präsent, so sind die Strukturen der Komponente Tissue noch nicht zufrieden-stellend, die Komponente Presentation muss komplett überarbeitet werden und auch das Shadersystem der Visualisierungskomponente ist nicht flexibel genug und nur eingeschränkt erweiterbar.

Dennoch konnte das Pluginsystem gegen Ende des Kapitels erfolgreich umge-setzt werden, so dass der Weiterentwicklung von Volume Studio nun nichts mehr im Wege steht.

63

Page 70: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Zusammenfassung und Ausblick

6 Zusammenfassung und Ausblick

In dieser Arbeit wurde eine monolithisch gewachsene, undokumentierte Soft-ware einem Redesign unterzogen. Dabei wurde zunächst ein Analyseverfahren beschrieben, dass durch Reverse Engineering Techniken die Offenlegung des Designs der Software ermöglicht. Die Analyse hat die Klassen- und Komponentenstruktur offengelegt aber auch zahlreiche Designmängel. So führten viele überflüssige Abhängigkeiten zu einer unnötig engen Kopplung der Komponenten. Die Funktionalität der Anwendung war teilweise schlecht auf sie und die Klassen verteilt, was zu starker Verschränktheit der Komponenten geführt hat.

Die Behebung der entdeckten Designmängel wurde anhand einiger Beispiele erläutert. Anschließend wurde die Software durch ein Redesign in eine neue, modulare Architektur überführt. Durch die weitgehende Entkopplung der Komponenten und die Einführung einiger Komponentenschnittstellen konnte eine Architektur etabliert werden, die der Software eine bessere Wartbarkeit und eine deutlich höhere Erweiterbarkeit verschafft.

Die Erweiterbarkeit wurde insbesondere durch ein Pluginsystem sichergestellt, das nicht nur dem Benutzer der Anwendung mehr Freiheit in der Konfiguration des Programms gibt, sondern auch Entwicklern ermöglicht Erweiterungen einzu-binden, ohne die bestehende Software modifizieren zu müssen.

Für die Zukunft ist eine bessere Werkzeugunterstützung sowohl für die Analyse als auch das Redesign wünschenswert. Zwar gibt es einige Programme, die bei Reverse Engineering Prozessen hilfreich sind, aber ganzheitlich überzeugen konnte keines von ihnen, entweder weil ihre Funktionalität unzureichend war, oder ihre Bedienbarkeit zu wünschen übrig ließ. Sehr geringfügig ist auch der Funktionsumfang der getesteten Refactoringwerkzeuge.

Der bearbeiteten Software, Volume Studio, kamen zwar auf Architekturebene umfassende Änderungen zu teil, einige Mängel bleiben jedoch bestehen, da ihre Behebung den Zeitrahmen dieser Arbeit überschritten hätte. Mit leistungsfähigen Werkzeugen hätten die notwendigen Schritte für Analyse und Redesign eventuell schneller durchgeführt und damit ein größerer Anteil der Anwendung verbessert werden können.

Um noch einige Aufgaben zu nennen, welche die Entwickler von Volume Studio in Zukunft zu beheben habt, so wären dies in erster Linie die Verbesserung des Shadersystems, um dessen Erweiterbarkeit herzustellen, also das Hinzufügen neuer Shader für neue Anwendungsfälle zu ermöglichen. Dann besitzen einige Komponenten noch kleinere Designmängel, die behoben werden könnten, ins-besondere Tissue.

Die Komponente Presentation ist größtenteils unbenutzbar, da ein neues Konzept für ihre Funktionalität entworfen werden muss, beispielsweise durch eine Schnittstelle, die Plugins, welche von Presentation berücksichtigt werden wollen, zu implementieren haben, und die Presentation anhand des Pluginnamens vom Pluginmanager anfordern kann.

64

Page 71: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Verwandte Arbeiten

Verwandte Arbeiten

In dieser Arbeit wurde die Analyse von Software zur Designrückgewinnung, Behebung einiger ausgewählter Designmängel, sowie die Durchführung eines Re-designs und Umsetzung eines Pluginkonzepts beschrieben. Verwandte Arbeiten, die alle diese Bereiche abdecken, konnte ich nicht ausmachen, wohl aber einige, die Teilbereiche dieser Arbeit betreffen.

Andrew Sutton und Jonathan I. Maletic haben in [SM05] einige Abbildungs-regeln („Mapping Rules“) vorgestellt, die helfen sollen UML Modelle aus C++ Code zu gewinnen. Dabei geht es unter anderem darum Klassen und deren At-tribute zu klassifizieren sowie einige Relationsarten wie Assoziation und Gene-ralisierung zu erkennen.

In [GPG04] wird auf die speziellere Problematik eingegangen, C++ Templates zu analysieren und ein Werkzeug namens TUAnalyzer vorgestellt, dass dabei Un-terstützung leisten soll.

In [CKM03] wird ein Fact Extractor vorgestellt, der C++ Code in einen XML Dialekt (srcML) übersetzt. Diese neue Repräsentation des Quellcodes erlaubt bei-spielsweise das einfache Finden von Klassen- und Funktionsdeklarationen sowie die Nutzung verschiedener XML Werkzeuge.

Am Laboratory for Quality Software (LaQuSo) in den Niederlanden wird an CPP2XMI gearbeitet, einem Tool, dass UML Klassen-, Sequenz- und Aktivitäts-diagramme aus C++ Code generieren und im XMI Format ausgeben können soll. Eine kurze Vorstellung findet sich in [KPBM06].

In [KSRP99] wird über die Erkennung von Design Patterns in Quellcode be-richtet und dessen Nutzen hinsichtlich Designrückgewinnung herausgestellt.

Was Designmängel angeht, werden in [CH91] Metriken vorgeschlagen, um Designqualitäten zu bewerten. Unter anderem eine, welche die Kohäsion von Klassen beschreibt. Dabei wird von den Objektattributen ausgegangen, die von den Methoden der Klasse benutzt werden. Wenn sich die Methoden in mehrere Mengen unterteilen lassen, die mit keinerlei gemeinsamen Attributen arbeiten, deutet dies daraufhin, dass die Klasse eine niedrige Kohäsion hat und ihre Auf-spaltung erwogen werden sollte.

In [KPSSV99] wird die Softwarearchitektur eines gegebenen System schrittweise verbessert. Die zu verbessernden Programmteile werden durch verschiedene Metriken ermittelt, ein abstraktes Model dieses Programmteils erstellt und darauf dann Transformationen durchgeführt, die bewertet und gegebenenfalls auf die Software übertragen werden.

Das Redesign einer objektorientierten Anwendung wird in [FR98] behandelt. Es werden einige Refactorings auf C++ Code angewandt, um fehlplatzierten Code zwischen Klassen zu verschieben.

EinPluginsystem wird in [A04] entworfen und implementiert (in Java). Nennenswert ist auch [CR06], wo das Pluginsystem von eclipse erläutert wird.

65

Page 72: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Literaturverzeichnis

Literaturverzeichnis

[A04] Alpetkin, Sinan: Ein dynamischer Erweiterungsmechanismus für Fujaba. Studienarbeit an der Universität Paderborn, Arbeits-gruppe Softwaretechnik, April 2004.

[AMH02] Akenine-Möller, Tomas und Eric Haines: Real-Time Rendering, Second Edition. A K Peters, 2002

[BaDe04] Balzer, Michael und Oliver Deussen: Hierarchy Based 3D Visualization of Large Software Structures. IEEE Visualization, 2004.

[BD06] Bohnet, Johannes und Jürgen Döllner: Visual Exploration of Function Call Graphs for Feature Location in Complex Software Systems. ACM Symposium on Software Visualization, September 2006.

[BD07] Bohnet, Johannes und Jürgen Döllner: CGA Call Graph Analyzer - Locating and Understanding Functionality within the Gnu Compiler Collection's Million Lines of Code. 4th IEEE International Workshop on Visualizing Software for Understanding and Analysis, Juni 2007.

[BMMM98] Brown, William J., Raphael C. Malveau, Hays W. McCormick III und Thomas J. Mowbray: AntiPatterns: Refactoring Software, Architecture and Projects in Crisis. John Wiley & Sons, Inc, 1998.

[CC90] Chikofski, Elliot J. und James H. Cross II.: Reverse Engineering and Design Recovery: A Taxonomy. IEEE Software, Volume 7, Issue 1, Januar 1990 .

[CDiP07] Canfora, Gerardo und Massimiliano Di Penta: New Frontiers of Reverse Engineering. Future of Software Engineering (FOSE), 2007.

[CH91] Chidamber, Shyam R. und Chris F. Kemerer: Towards a metrics suite for object oriented design. OOPSLA '91: Conference proceedings on Object-oriented programming systems, languages, and applications, 1991.

66

Page 73: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Literaturverzeichnis

[CKM03] Collard, Michael L., Huzefa H. Kagdi und Jonathan I. Maletic: An XML-Based Lightweight C++ Fact Extractor. Proceedings of the 11th IEEE International Workshop on Program Comprehension, 2003.

[CR06] Clayberg, Eric und Dan Rubel: eclipse – Building Commercial-Quality Plugin-Ins. Addison Wesley, 2006.

[FBTG] Ferenc, Rudolf, Árpád Beszédes, Mikko Tarkiainen und Tibor Gyimóthy: Columbus – Reverse Engineering Tool and Schema for C++. 18th International Conference on Software Maintenance (ICSM 2002), Maintaining Distributed Heterogeneous Systems, 2002.

[FG06] Fischer, Michael und Harald Gall: EvoGraph: A Lightweight Approach to Evolutionary and Structural Analysis of Large Software Systems. Proceedings of the 13th Working Conference on Reverse Engineering (WCRE), 2006.

[FMBKT] Ferenc, Rudolf, Ferenc Magyar, Árpád Beszédes, Ákos Kiss und Mikko Tarkiainen: Columbus – Tool for Reverse Engineering Large Object oriented Software Systems. Symposium on Programming Languages and Software, 2001

[Fow99] Fowler, Martin: Refactoring: Improving the Design of Existing Code. Addison Wesley, 1999 (vorliegend ist die 19. Auflage von 2006).

[FR98] Fanta, Richard und Václav Rajlich: Reengineering Object-Oriented Code. Proceedings of ICSM, 1998.

[GHJV96] Gamma, Erich, Richard Helm, Ralph Johnson und John Vlissides: Entwurfsmuster: Elemente wiederverwendbarer objektorientierter Software. Addison Wesley, 1996.

[GLW06] Greevy, Orla, Michele Lanza und Christoph Wysseier: Visualizing Live Software Systems in 3D. Proceedings of the 2006 ACM symposium on Software visualization, 2006.

[GPG04] Gschwind, Thomas, Martin Pinzger und Harald Gall: TUAnalyzer – Analyzing Templates in C++ Code. Proceedings of the 11th Working Conference on Reverse Engineering (WCRE), 2004.

[Jer99] Jermaine, Christopher: Computing Program Modularization Using the k-Cut Method. Proceedings of the Sixth Working Conference on Reverse Engineering, 1999.

67

Page 74: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Literaturverzeichnis

[OMG07] Object Management Group (OMG): Unified Modeling Language: Superstructure. Februar 2007 (Version 2.1.1).

[KPBM06] Korshunova, E., M. Petkovic, M.G.J. van den Brand und M.R. Mousavi: CPP2XMI: Reverse Engineering of UML Class, Sequence, and Activity Diagrams from C++ Source Code. Proceedings of the 13th Working Conference on Reverse Engineering (WCRE), 2006.

[KPSSV99] Krikhaar, R., Postma, A., Sellink, A., Stroucken, M. und Verhoef, C.: A two-phase process for software architecture improvement. Procceedings of the International Conference on Softwaremaintenance (ICSM '99), 1999.

[KSRP99] Keller, Rudolf K., Reinhard Schauer, Sébastien Robitaille und Patrick Pagé: Pattern-Based Reverse-Engineering of Design Components. Proceedings of the 21st international conference on Software Engineering, 1999.

[MB07] Maqbool, Onaiza und Haroon A. Babri: Hierarchical Clustering for Software Architecture Recovery. IEEE Transactions on Software Engineering, Vol. 33, No. 11, November 2007.

[SM05] Sutton, Andrew und Jonathan I. Maletic: Mappings for Accurately Reverse Engineering UML Class Models from C++. Proceedings of the 12th Working Conference on Reverse Engineering (WCRE), 2005.

[SSW03] Storey, Margaret-Anne D., Susan Elliott Sim und Kenny Wong: A Collaborative Demonstration of Reverse Engineering Tools. ACM Applied Computing Review, 2003.

[WE02] Weiler, Manfred und Thomas Ertl: Ein Volume-Rendering-Framework für OpenSG. Beitrag zum 1. OpenSG Symposium: OpenSG 2002.

[YR06] Yang, Yaojin und Claudio Riva: Scenarios for Mining the Software Architecture Evolution. Proceedings of the 2006 International Workshop on Mining Software Repositories, 2006.

[ZWDZ04] Zimmermann, Thomas, Peter Weißgerber, Stephan Diehl und Andreas Zeller: Mining Version Histories to Guide Software Changes. Proceedings of the 26th International Conference on Software Engineering, 2004.

68

Page 75: Analyse, Redesign und Refactoring einer …...Computergrafik-Anwendung Bachelorarbeit zur Erlangung des Grades Bachelor of Science für den Studiengang Informatik von Jan-Hendrik Göllner

Anhang

Anhang

69

Abbildung A.1: Die Klassenstuktur von Volume Studio (Revision 69) mit sämtli-chen ermittelten Relationen. Zusätzlich ist die Komponentenzugehörigkeit durch

Farben gekennzeichnet:Gelb: Segmentation Hellblau: Visualization

Rose: Tissue Weiß: Core


Recommended