Durchführung eines Softwareprojekts

Aus Wiki
Wechseln zu: Navigation, Suche

Dieser Artikel ist gedacht als Anlaufstelle für Studierende, die im Rahmen ihres Studiums ein Software-Entwicklungsprojekt durchführen, z.B. als Module Teamprojekt, Medienprojekt, Interdisziplinäres Teamprojekt, Projektstudium usw., wie sie in den Bachelor- und Masterstudiengängen des Fachbereichs Informatik der Hochschule Trier vorkommen, siehe Modulhandbücher [1] [2]. An einem solchen Projekt beteiligen sich i.d.R. zwei bis sechs Studierende. Es spielt im Curriculum des Informatikstudiums eine zentrale Rolle, weil es in besonderer Weise auf die spätere Berufspraxis vorbereitet. Hier werden Methoden und Kenntnisse zusammengeführt und praktisch angewendet, die im Laufe des Studiums in verschiedenen Modulen vermittelt werden.

Ansprechpartner für dieses Wiki ist Prof. Dr. Heinz Schmitz. Bevor Sie mit einem Projekt auf Basis dieses Artikels beginnen, stimmen Sie sich hierüber mit dem Betreuer Ihres Projekts ab. Neben der inhaltlichen Ausgestaltung ergeben sich unter Umständen alternative Vorgaben zur Vorgehensweise oder besondere Anforderungen an einzelne Aspekte.


Der Artikel stellt auf den folgenden Seiten sehr kompakt einige Grundsätze zusammen, die nach den bisherigen Erfahrungen mit Software-Entwicklungsprojekten beachtet werden sollten. Er hat zum Ziel, einen Rahmen für eine gute Qualität der Projektergebnisse vorzugeben und insbesondere den Einstieg in ein Projekt zu erleichtern. Dazu werden folgende Informationen bereitgestellt:

  • Kurze Anleitung zu Projektorganisation und -planung
  • Bereitstellung von Beispieldokumenten für alle Projektphasen anhand eines Mini-Projekts
  • Übersicht über bewährte Entwicklungswerkzeuge
  • Erfahrungen aus vergangenen Projekten mit Tipps & Tricks


Was dieser Artikel nicht ist: Eine umfassende Wiederholung von Modulinhalten oder eine allgemeine Diskussion von Software-Engineering-Methoden findet ganz bewusst nicht statt. Der Artikel macht keine Vorgaben für ein bestimmtes Vorgehensmodell und legt auch keine Programmiersprache fest. Außerdem ist die Darstellung möglichst unabhängig von einem bestimmten Projektthema gehalten.


Die Inhalte dieses Artikels sind entlang der Tätigkeiten strukturiert, wie sie üblicherweise in Projekten vorkommen:

  • Projektplanung und -organisation
  • Spezifikation der Anforderungen
  • Technischer Entwurf der Software
  • Implementierung und Test
  • Qualitätssicherung


Inhaltsverzeichnis

Projektplanung und -organisation

Rollen

Die Aufgabenverteilung im Projekt wird durch Rollen festgelegt, die einzelnen Personen zugeordnet werden. In der Literatur werden unterschiedliche Angaben zu sinnvollen oder notwendigen Rollen innerhalb eines Projekts gemacht, deren Umsetzung u.a. von Größe und Art des Projekts abhängen. Diese gehen von einer Unterscheidung von Projektleiter und Projektmanager über Qualitätsbeauftragter und Qualitätspate bis hin zu Chefdesigner und Entwickler, siehe z.B. [3].

Meistens wird es so sein, dass alle Teammitglieder in der Rolle Entwickler beteiligt sind. Zusätzlich hat sich die explizite Wahrnehmung folgender Rollen durch Teammitglieder als nützlich erwiesen. Die Rollen sollten im Laufe des Projekts zwischen den Teammitgliedern getauscht werden, z.B. bei Abschluss einzelner Projektphasen.

Projektleiter

Der Projektleiter trägt die Verantwortung über die allgemeine Projektplanung und ist über den aktuellen Stand des Gesamtprojekts informiert. Er sorgt dafür, dass der Projektplan bei den Projekttreffen in aktualisierter Form vorliegt und fordert dazu rechtzeitig die notwendigen Informationen von den Teammitgliedern ein. Er kümmert sich um die Schaffung geeigneter Rahmenbedingungen (Projektlaufwerk, Werkzeuge, ... ) und kann einen Teil seiner Aufgaben delegieren. Schließlich vertritt er das Projekt nach "außen" (z.B. gegenüber dem Betreuer) und organisiert die regelmäßigen Projekttreffen.

Qualitätsbeauftragter

Der Qualitätsbeauftragte ist verantwortlich für die Durchführung der verschiedenen Maßnahmen zur Qualitätssicherung. Umfang und Art dieser Maßnahmen werden zu Anfang im Team abgestimmt. Dies sind üblicherweise Reviews aller wichtigen Projektdokumente (z.B. Lastenheft, Entwurfsdokumente, Sourcecode) sowie verschiedene Teststufen (Entwicklertest, Integrationstest, Systemtest). Zur Durchführung dieser Maßnahmen gehört zwingend die Vorbereitung und nachvollziehbare Dokumentation der Ergebnisse. Sämtliche Q-Aktivitäten sind im Projektplan vorzusehen und deren gewissenhafte Ausführung zu überwachen.

Tipps

Zu den Spielregeln im Projekt gehört selbstverständlich, dass jeder Projektbeteiligte - unabhängig von der aktuellen Rolle - durch offene und sachliche Kommunikation seinen Teil der Verantwortung für das Gelingen des Gesamtprojekts wahrnimmt. Insofern macht jeder im Team das Projekt zu seinem Projekt.

Projektplan

Der Projektplan ist das zentrale Dokument für die Steuerung des Projekts. Er dient in erster Linie dem Projektteam selbst als Werkzeug zur realistischen Einschätzung des Projektstatus (Fortschrittskontrolle, Machbarkeit der Projektziele), um frühzeitig auf Schwierigkeiten reagieren zu können. Außerdem eignet sich der Projektplan hervorragend zur Abstimmung im Team und zur Kommunikation mit dem Betreuer.

Je nach gewähltem Vorgehensmodell und Aufteilung der Projekt-Phasen kann der Projektplan in seinem Aufbau variieren. Allen gemeinsam ist jedoch, dass für die kleinsten Arbeitspakete festgelegt wird, wer diese bis wann zu machen hat und wie viel Zeit dafür schätzungsweise nötig ist. Nachdem ein Arbeitspaket begonnen wurde ist außerdem in regelmäßigen Abständen wichtig zu erfassen, wie viel Zeit für das Arbeitspaket bereits investiert wurde und wie der Restaufwand geschätzt wird. Das hat folgende Vorteile:

  1. Es ist jederzeit nachvollziehbar, wie viel Zeit bereits in ein Arbeitspaket geflossen ist und wie sehr der geschätzte Zeitaufwand von dem tatsächlichen abweicht. Das ist wichtig, um die eigenen Schätzungen für zukünftige Arbeitspakete zu verbessern.
  2. Wenn sich der geschätzte Restaufwand eines Arbeitspaketes über einen gewissen Zeitraum nicht deutlich verringert oder sogar größer wird, ist das ein deutliches Zeichen für Probleme. Entweder das Arbeitspaket ist zu groß und die Schätzung damit nur sehr ungenau möglich. Dann bietet es sich an, das Arbeitspaket in kleinere Pakete aufzuteilen. Oder es bestehen möglicherweise Schwierigkeiten bei der Umsetzung, worüber im Team diskutiert werden muss.
  3. Aus den geschätzten Restaufwänden der Arbeitspakete, deren Abhängigkeiten untereinander und aus der Aufteilung der Verantwortlichkeiten auf die Teammitglieder lässt sich eine voraussichtliche Gesamtlaufzeit des Projekts ermitteln. Durch Vergleich mit dem Endetermin des Projekts ist sofort klar, ob dieser noch realistisch eingehalten werden kann. Ist dies nicht der Fall, muss frühzeitig in Abstimmung mit dem Betreuer über Maßnahmen gesprochen werden, um dem Termin doch noch gerecht zu werden (z.B. Reduktion von Funktionalität statt Qualität).

Mehrere zusammengehörende Arbeitspakete werden typischerweise einem Zwischentermin (Meilenstein) zugeordnet, um den Projektfortschritt in kürzeren Abständen zu überwachen.

Meilensteine

Meilensteine sind Terminfestlegungen für wichtige Teilziele des Projekts und werden durch Arbeitspakete charakterisiert, die bis zu einem bestimmten Datum fertiggestellt sein müssen, um das Projektergebnis bis zum Fertigstellungstermin zu erreichen. Meilensteine sind wichtig, um den tatsächlichen Fortschritt des Projekts sicherzustellen. Sie sollten bereits zu Projektbeginn festgelegt werden, auch wenn das zu diesem Zeitpunkt möglicherweise nur sehr grob möglich ist. Kommt es zu einer Verschiebung eines Meilensteins, müssen alle nachfolgenden Meilensteine mindestens um diese Zeit verschoben werden, falls keine neue Aufwandsschätzung etwas anderes nahelegt. Die Abnahme der Meilensteine und der damit verbundenen Ergebnisdokumente erfolgt nach team-internen Qualitätssicherung durch den Betreuer des Projekts.

Bedienungsanleitung des Musterdokuments Projektplan

Um einen schnellen Einstieg zu ermöglichen, bieten wir hier einen Muster-Projektplan in Form eines OpenOffice-Calc-Sheets an. Auf diese Weise lassen sich einige Aufgaben der Projektplanung automatisieren und wichtige Informationen können direkt berechnet und übersichtlich dargestellt werden. Einige Zellen des Dokuments sind mit Hilfe der eingebauten Kommentar-Funktion erläutert, was jedoch für eine sinnvolle Nutzung möglicherweise noch nicht ausreicht. Aus diesem Grund wird im Folgenden eine Bedienungsanleitung gegeben, die den Einstieg so weit wie möglich erleichtern soll.

Aufbau des Projektplans

Das OpenOffice-Sheet besteht aus 4 Tabellen-Seiten, in denen unterschiedliche Informationen hinterlegt sind:

  • Projektplan
  • Meilensteine
  • Team
  • Aufwände laut Curriculum

Wir gehen nun die einzelnen Seiten durch und beschreiben, was sich dahinter verbirgt und welche Anpassungen für die eigene Nutzung durchgeführt werden müssen. Generell gilt, dass grau hinterlegte Felder mit Formeln ausgestattet sind und deshalb nicht bearbeitet werden dürfen.

Tabellenblatt: Aufwände laut Curriculum
(thumbnail)
Muster-Projektplan: Liste der voreingestellten Projekttypen, wie sie an der Hochschule Trier, Fachbereich Informatik existieren.

Hier sind die einzelnen Projekt-Typen aufgelistet, wie sie im Rahmen des Informatik-Studiums an der Hochschule Trier vorkommen. In den meisten Fällen muss hier keinerlei Änderung durchgeführt werden. Wird das Projekt nicht im Rahmen einer Studienleistung durchgeführt, kann diese Seite komplett ignoriert werden.

Tabellenblatt: Team
(thumbnail)
Muster-Projektplan: Liste des Team mit Informationen über Projekttyp laut Curriculum, sowie Summe investierter und geplanter Aufwände.

Hier werden alle Teammitglieder aufgelistet, die an dem Projekt beteiligt sind. Jedes Teammitglied erhält eine Nummer, mit deren Hilfe es an anderer Stelle eindeutig identifiziert wird. Hier ist ersichtlich, nach welchem Projekttyp laut Curriuculum das Teammitglied arbeitet, wie viele Stunden es bereits investiert hat und wie viele Stunden noch ausstehen. Diese Informationen werden automatisch anhand der Zeiterfassung im Projektplan errechnet.

Möchte man ein neues Mitglied hinzufügen, reicht es eine neue Nummer zu wählen und die restlichen weiß hinterlegten Felder entsprechend auszufüllen.

Tabellenblatt: Meilensteine
(thumbnail)
Muster-Projektplan: Liste des Team mit Informationen über Projekttyp laut Curriculum, sowie Summe investierter und geplanter Aufwände.

Auf diesem Datenblatt werden die Meilensteine verwaltet, die das Projekt in kleinere Ziele unterteilt. Jeder Meilenstein erhält eine Nummer, eine Bezeichnung und ein Datum. Die Nummer muss eindeutig sein und identifiziert einen Meilenstein im Projektplan. Mit ihr werden einzelne Arbeitspakete dem Meilenstein zugeordnet. Im Projektplan werden später pro Arbeitspaket einzelne Aufwände erfasst und verplant. Auf diese Weise wird es möglich, pro Meilenstein eine Übersicht zu generieren, welche Aufwände bereits eingeflossen sind, wie hoch der Restaufwand ist und schließlich basierend darauf, wie weit der jeweilige Meilenstein von seiner Erreichung entfernt ist. Diese Werte errechnen sich automatisch, sofern bereits IST- und REST-Aufwände im Projektplan erfasst sind.

Tabellenblatt: Projektplan
(thumbnail)
Muster-Projektplan: Übersicht

Dies ist das wichtigste Tabellenblatt, mit dem auch am meisten gearbeitet wird. Hier fließen nun viele Dinge zusammen:

  • Allgemeine Angaben zum Projekt, unter anderem der Start des Projekts. Diese Angabe ist notwendig, damit der Kalender im rechten Teil des Projektplans den korrekten Zeitraum anzeigt.
  • Thematische Einteilung des Projekts in einzelne Kategorien, die wiederum in einzelne Arbeitspakete aufgeteilt sind. Die Größe eines Arbeitspakets sollte so gewählt werden, dass der Aufwand realistisch geschätzt werden kann. Um so größer das Arbeitspaket, um so schwieriger wird eine realistische Zeit-Schätzung.
  • Die Zuweisung von Arbeitspaketen zu vorher definierten Meilensteinen.
  • Die Zuweisung von Arbeitspaketen zu einem verantwortlichen Teammitglied.
  • Zeitplanung und Zeiterfassung pro Arbeitspaket.
  • Eine Kalenderübersicht, die den heutigen Tag, die Grenze des Planungshorizontes (PH) und alle eingetragenen Meilensteine anzeigt. Die Kalenderübersicht dient gleichzeitig als Zeiterfassung der IST-Aufwände sowie zur Vorausplanung im Rahmen des Planungshorizontes ab dem aktuellen Tag.
(thumbnail)
Muster-Projektplan: Zeiterfassung des IST-Aufwandes links vom heutigen Tag.
(thumbnail)
Muster-Projektplan: Zeiterfassung des bereits verplanten REST-Aufwandes rechts vom heutigen Tag bis mindestens zur Grenze des Planungshorizontes.

Die meisten Punkte erklären sich von selbst, während der letzte jedoch etwas mehr Erläuterung verdient. Im Kalender kann pro Arbeitspaket eingetragen werden, wie viel Zeit bereits dort hinein geflossen ist (IST-Aufwand). Dieser ergibt sich aus der Summe der Stunden von Beginn des Projekts bis zum jeweils aktuellen Tag. Der geschätzte REST-Aufwand gibt an, wie viele Stunden schätzungsweise noch für das Arbeitspaket aufgewandt werden müssen. Diese Zahl kann dann über den Planungshorizont verteilt werden, wobei es nicht zwingend notwendig ist, alle Stunden sofort zu verplanen.

Aktualisierung des Projektplans

Die Aktualisierung muss in regelmäßigen Abständen erfolgen, typischerweise vor den Projekttreffen mit dem Betreuer. Dabei werden durch den Projektleiter folgende Schritte ausgeführt:

  1. die bis zum aktuellen Datum tatsächlich erbrachten IST-Aufwände eintragen (Planungswerte ggf. korrigieren), Daten von den Teammitgliedern einfordern
  2. REST-Aufwände in Absprache mit den Bearbeitern aktualisieren, bei Abschluss eines Arbeitspakets REST-Aufwand 0 eingetragen
  3. Verteilung der offenen REST-Aufwände je Arbeitspaket auf den PH in Absprache mit den Bearbeitern
  4. kritische Würdigung des Projektfortschritts: Gibt es neue Probleme, Risiken oder Verzögerungen? Sind Meilensteine gefährdet?

Es bietet sich an, vor jeder Aktualisierung eine Kopie des alten Projektplans abzulegen oder den Projektplan einer Versionsverwaltung zu unterstellen. Ein Vergleich des tatsächlichen Projektverlaufs mit einem früheren Planungsstand ist oft interessant.

Tipps

Begreifen Sie den Projektplan als Hilfsmittel für das eigene Team, nicht als Überwachungsinstrument des Betreuers, das jeweils für die Projekttreffen geschönt wird. Der Nutzen des Projektplans entsteht nur, wenn er die tatsächliche Situation abbildet. Es ist nicht ungewöhnlich, dass in einem Projekt Verzögerungen und Schwierigkeiten auftreten, was nicht automatisch bedeutet, dass das Projekt scheitern wird. Es macht allerdings einen großen Unterschied, ob sich das Projektteam der Probleme bewusst ist und sinnvoll darauf reagieren kann, oder ob das Projekt im Blindflug auf den Endetermin zusteuert.

Vergessen Sie nicht, die Aufwände für die Projektorganisation inkl. der Projektplanung ebenfalls zu schätzen und zu erfassen.

Wir schlagen hier eine relativ einfache Projektplanung auf Basis einer Tabellenkalkulation vor, die ausreicht, um in den kleinen Projekten im Rahmen der Ausbildung den Überblick zu behalten und um den Umgang mit einem Projektplan zu üben. Spezielle Werkzeuge zur Projektplanung sind viel mächtiger und ermöglichen beispielsweise eine Anbindung an Zeiterfassungssysteme oder eine bessere Verwaltung von Abhängigkeiten zwischen Arbeitspaketen. Andererseits erfordern sie einen größeren Einarbeitungsaufwand.

Projekttreffen

Projekttreffen finden regelmäßig statt und werden im Projektplan vorgesehen, zum Beispiel im ein- oder zwei-Wochen-Takt. Dies hat folgende Vorteile:

  1. Es wird sicher gestellt, dass alle nach wie vor am selben Strang ziehen und Missverständnisse bzw. Unklarheiten werden rechtzeitig erkannt.
  2. Teilergebnisse können den Team-Mitgliedern präsentiert werden, was sich positiv auf die Motivation aller auswirkt, da man sieht dass es voran geht.
  3. Es besteht stets Klarheit über den Stand des Projekts, sodass der IST und SOLL-Stand laut Projektplan verglichen und möglicherweise neu geplant werden kann.

Die regelmäßigen Projekttreffen sollten nicht übermäßig lange dauern und immer ein klares Ziel verfolgen. Neben den immer wiederkehrenden Ritualen wie die gemeinsame Validierung des Projektplans oder die Aufwandsschätzung noch ausstehender Arbeitspakete, könnten auch kritische Entscheidungen anfallen, die den weiteren Projektverlauf beeinflussen. Dabei ist es wichtig, dass sich die Teammitglieder nicht erst während des Treffens über solche Punkte Gedanken machen, sondern bereits vorher Wege oder Vorschläge erarbeitet haben, die dann in der Runde diskutiert werden können.

Es ist Aufgabe des Projektleiters, vorher die Ziele für ein jedes Treffen zu definieren und die restlichen Teammitglieder rechtzeitig über diese zu informieren. Schließlich kann es sehr frustrierend sein, wenn viel Zeit für unvorbereitete Projekttreffen vergeudet wird.

Tipps

Es ist wenig sinnvoll viel Zeit damit zu verbringen, während eines Projekttreffens sofort gemeinsam eine Lösung für ein technisches Problem o.ä. zu erarbeiten. Es ist wesentlich besser, kleine Gruppen zu bilden (2-3 Personen), die sich intensiv und vor allem konzentriert mit einem Problem auseinandersetzen und Lösungswege erarbeiten, die dann wiederum im Team vorgestellt und diskutiert werden.

Projektlaufwerk

Das Projektlaufwerk ist die zentrale gemeinsame Datenbasis, auf die jedes Team-Mitglied zugreifen kann. Es kann beim r/ft beantragt werden, indem man (nach Anmeldung) ein Online-Formular auf den Seiten des Rechenzentrums ausfüllt[4]. Es dient einerseits zum Datenaustausch und andererseits als Backup, denn die Projektlaufwerke werden regelmäßig vom Rechenzentrum gesichert. Auf dem Laufwerk sollten mindestens folgende Dinge hinterlegt werden:

  • eine aktuelle und ausführbare Version der Software
  • alle Arten von Dokumentationen in ihrer aktuellen Fassung
  • der Projektplan
  • die Quelldateien (zum Beispiel in Form eines SVN- oder Git-Repositories)

Wir stellen beispielhaft eine Ordnerstruktur zur Verfügung, die bereits sämtliche Beispieldokumente enthält. In dieser sind ausschließlich die Quelldateien in Form eines Git-Repositories versioniert. Je nach Team-Größe und gewähltem Workflow kann es jedoch sinnvoll sein, wesentlich mehr zu versionieren, zum Beispiel auch die Anforderungs- und Entwurfsdokumente.

Das Beispielprojekt

Um den Einstieg noch weiter zu vereinfachen, wird hier ein Projektlaufwerk zur Verfügung gestellt, das ein komplettes (wenn auch kleines) Beispielprojekt enthält. Dabei handelt es sich um die Umsetzung eines Movie-Managers zur Verwaltung einer Filmsammlung. Neben den Quelldateien, die in einem Git-Repository versioniert sind, und einer lauffähigen Version sind außerdem eine Anforderungssammlung sowie ein Projektplan vorhanden. Es wurde versucht die hier angesprochenen Aspekte einfließen zu lassen. Inbesondere die Strukturierung der Software und die Verwendung der Entwurfsmuster könnte hilfreich sein. Bitte beachten Sie, dass das Beispielprojekt nur zur Veranschaulichung dient und keinen Anspruch auf Vollständigkeit erhebt. Außerdem repräsentiert die zugehörige Software nur eine mögliche Art der Umsetzung.

Der Download der Zip-Datei befindet sich unten im Abschnitt Downloads.

Um an die Quelldateien zu kommen, muss man zunächst einen Git-Client installieren und dann das (Remote-)Repository in der Zip-Datei klonen. Wie das funktioniert ist in der Git-Dokumentation nachzulesen[5]. Weiter unten existiert außerdem ein Abschnitt, der einen kurzen Überblick über Git verschafft.

Projekt-Phasen

Im Folgenden werden die typischen Tätigkeiten während eines Projekts beschrieben. Deren Ausprägung und konkreter Ablauf hängt sehr stark vom verwendeten Vorgehensmodell ab, weshalb wir hier nur ganz allgemein in Phasen gliedern.

Phase: Spezifikation der Anforderungen

Zu Anfang eines jeden Projekts sollte man sich über die Ziele und Anforderungen im Klaren werden und diese im Detail aufschreiben. Diesem Zweck dienen Dokumente wie das Lasten- und Pflichtenheft. Im Lastenheft wird zunächst das Problem im Detail und anschließend die Ziele des Projekts beschrieben. Daraus resultieren verschiedene Arten von Anforderungen, die zum Erreichen der Ziele notwendig sind. Das Lastenheft wird in Zusammenarbeit mit dem Kunden / Betreuer erstellt und dient als Basis für das Pflichtenheft. Im Pflichtenheft hingegen wird beschrieben, wie das Team gedenkt die Anforderungen technisch umzusetzen. Dazu gehört dann, je nach Projekt, unter anderem das Aufstellen eines Modells, die Definition von Schnittstellen sowie der Entwurf einer grafischen Benutzeroberfläche.

Wie ein solches Dokument aufgebaut sein kann, ist zum Beispiel in dem IEEE-Standard 830-1998 festgelegt[6].

An folgenden Qualitätsmerkmalen für Anforderungen kann man sich bei deren Formulierung orientieren:

Atomarität der Anforderungen

Anforderungen sollten atomar sein, d.h. nur genau eine Anforderung beschreiben, die sich nicht weiter in mehrere Anforderungen unterteilen lässt. Auf diese Weise wird es möglich, später genau sagen zu können, ob die Anforderung erfüllt ist oder nicht.

Eindeutigkeit der Anforderungen

Für jede formulierte Anforderung muss man sich die Frage stellen, wie viel Platz für mögliche Fehlinterpretationen übrig geblieben ist. Wichtig dabei ist, dass sich sowohl das Team als auch der Kunde über den Sinn und Zweck der Anforderung einig sind. Dabei sollte jedoch auch eine gewisse Zweckmäßigkeit beibehalten werden, da eine Formulierung schnell unnötig lang wird. Grundsätzlich gilt: So knapp wie möglich, so lang wie nötig.

Messbarkeit der Anforderungen

Eine Anforderung ergibt nur dann einen Sinn, wenn zu jeder Zeit festgestellt werden kann, ob diese bereits erfüllt ist oder nicht. Aus diesem Grund sollte eine Anforderung stets messbar sein. Das kann zum Beispiel dadurch erreicht werden, in dem konkrete Zahlenwerte für Grenzen existieren.

Realisierbarkeit der Anforderung

Eine Anforderung muss immer auch die Chance haben, realisiert werden zu können. Es ergibt keinen Sinn Anforderungen zu formulieren, bei denen von vorneherein klar ist, dass sie nicht umgesetzt werden können.

Vollständigkeit der Anforderungen insgesamt

Am Ende der Anforderungssammlung muss sich gefragt werden, ob tatsächlich alle geforderten Funktionen beschrieben und deren Rahmenbedingungen erfasst sind. Dies ist vor Beginn der Planungsphase ein wichtiges Ziel, da nachträglich hinzukommende Anforderungen möglicherweise schwer zu integrieren sind.

Tipps

Ein häufiger Fehler ist, dass die gesammelten Anforderungen von ihrer Qualität her nicht ausreichend sind. So kann es zu Missverständnissen zwischen Kunden und Projekt-Team kommen. Um dies zu vermeiden sollte stets sichergestellt werden, dass mit dem Kunden Einigkeit darüber besteht, wie die einzelnen Anforderungen gemeint sind.

Phase: Software-Entwurf

Nachdem möglichst alle Anforderungen erfasst und mit dem Kunden / Betreuer abgestimmt sind, beginnt die Entwurfsphase der Software. Teile davon fließen ebenfalls in das Pflichtenheft mit ein und sind somit Bestandteil des Vertrags mit dem Kunden / Beteuer. Welche Aspekte dazugehören, hängt stark von der Art und des Umfangs der zu entwickelnden Software ab. Wir werden im Folgenden einige typische Softwarekomponenten aufzählen und jeweils beschreiben, wie und mit welchem Werkzeug ein Entwurf möglich ist.

Entwurf der Grafischen Benutzeroberfläche

In den meisten Softwareprojekten spielt die Grafische Benutzeroberfläche (kurz GBO oder GUI) eine entscheidende Rolle dabei, ob die Software von den Nutzern und damit vom Kunden akzeptiert wird, oder nicht. Oft gibt es für die Bedienung bzw. für die Erfassung von Daten mehrere unterschiedliche Möglichkeiten der Realisierung und oft ist die erste Idee nicht unbedingt die beste. Grundsätzlich sollte von Nutzerseite an dieses Problem heran gegangen werden, d.h. es sollte herausgefunden werden, welche Aktionen und Ziele der Benutzer während der Nutzung der Software wann und wie oft verfolgt. Daraus ergeben sich wichtige Informationen darüber, welche Bedienelemente beispielsweise besonders häufig genutzt werden und somit, wie viel Energie in eine effiziente Bedienbarkeit gesteckt werden sollte. Die gesammelten Anforderungen geben bereits Hinweise darauf und können durch weitere Nutzerbefragungen ergänzt werden. Ergebnis können sogenannte Usecase-Diagramme sein und darauf aufbauend erste GUI-Entwürfe.

Usecase-Diagramme sind Teil der UML-Spezifikation und somit von den meisten UML-Tools unterstützt. Ein freies und sehr mächtiges UML-Tool ist Astah-Community[7].

Für einen ersten GUI-Entwurf eignet sich, neben vielen speziellen Tools, besonders eine Präsentationssoftware wie Microsoft Powerpoint oder OpenOffice Impress. Die Idee ist dabei auf einzelnen Folien die Zustände der Bedienelemente abzubilden und diese dann geschickt miteinander zu verlinken.

Beispiel: Angenommen, man würde die Auswahl aus einem Dropdown-Feld simulieren wollen. Dann gäbe es eine Folie, bei der das Feld eingeklappt (1), eine weitere wo diese aufgeklappt ist (2) und schließlich eine, wo ein Eintrag erfolgreich ausgewählt wurde (3). Zu (2) kommt man, indem auf den Pfeil neben der Dropbox geklickt wird. Zu (3) dann durch Klicken auf die Liste.

Auf diese Weise kann bereits sehr früh ein GUI-Entwurf präsentiert werden, der sogar ein Gefühl darüber vermittelt, wie die Bedienung später aussieht. Die Nutzer können früh ihr Feedback abgeben und es wird sehr viel Zeit damit gespart, dass der Ablauf der Bedienung schon vor der eigentlichen Implementierung klar ist.

Algorithmen-Entwurf

Sollte es für die gegebene Problemstellung erforderlich sein, dass ein neuer Algorithmus erstellt werden muss, so empfiehlt sich der Entwurf zunächst in Pseudo-Code. Dies hat die folgenden Vorteile:

  • Jeglicher technischer Overhead, der den meisten gängigen Programmiersprachen anhängt, kann zunächst vernachlässigt werden. So bleibt der Algorithmus übersichtlich und beschränkt sich ausschließlich auf die Anweisungen und Kontrollstrukturen, die den Kern des Algorithmus ausmachen. Auf diese Weise wird die Entwurfsphase stark vereinfacht.
  • Der Entwurf bleibt so allgemein, dass die Ziel-Sprache schließlich keine Rolle mehr spielt.
  • Eine Laufzeit- und Korrektheitsanalyse ist wesentlich einfacher möglich.
  • Im Pseudo-Code können abstrakte mathematische Ausdrücke und Datenstrukturen verwendet werden, was einen Korrektheitsnachweis vereinfacht.
  • Wenn der Algorithmus erst einmal fertig durchdacht ist, stellt die Implementierung in die Zielsprache keine größeren Probleme mehr dar.

Entwurf des Datenmodells

Hier werden alle Überlegungen getroffen, die den Zugriff und die Verwaltung der zu verarbeitenden Daten betrifft. Sollen die Daten in einer Datenbank gespeichert werden, eignet sich zum Entwurf ein ER-Diagramm[8]. Darin ist festgehalten, welche Entitäten existieren und wie die Beziehungen untereinander aussehen. Eine weitere Überlegung könnte sein, ob ein sogenannter OR-Mapper[9] verwendet werden soll. Auf diese Weise erspart man sich das manuelle Mapping der Datenbank auf geeignete Datenstrukturen der Programmiersprache. Ein bekannter OR-Mapper für Java ist beispielsweise Hibernate[10].

Egal für welche Persistierungs-Methode man sich entscheidet oder ob überhaupt eine Persistierung stattfindet, die zu verarbeitenden Daten müssen in jedem Fall irgendwie repräsentiert sein. Im Allgemeinen sind dabei folgende Gesichtspunkte zu berücksichtigen:

  • Wahl der Datenstrukturen für einen effizienten Zugriff
  • Konsistenzhaltung bei Änderung der Daten (wird ggf. vom OR-Mapper übernommen)
  • Zugriffsmöglichkeiten von außerhalb
  • Vermeidung von Redundanzen
  • Datenkapselung

Entwurf der Software-Komponenten

Hier gilt es zu analysieren, wie die Anwendung sinnvoll in Komponenten aufgeteilt werden kann und wie diese voneinander abhängen. Je nach Anwendungstyp hat das unterschiedliche Auswirkungen auf den Entwurf. Im Allgemeinen möchte man einzelne Komponenten, die unabhängig voneinander entwickelt und getestet werden können und über vordefinierte Schnittstellen kommunizieren. Dies ermöglicht erst die zeitgleiche Entwicklung der Anwendung mit mehreren Teammitgliedern.

Es gibt verschiedene Lösungsansätze und Entwurfsmuster, wie eine saubere und sinnvolle Unterteilung in Komponenten umgesetzt werden kann. Diese sind meist sprachunabhängig, da die verwendeten Eigenschaften von den meisten gängigen (objektorientierten) Programmiersprachen unterstützt werden. Einige werden wir im Folgenden vorstellen, die sich im Zusammenspiel als sehr geeignet erwiesen haben. Dazu zählen die folgenden:

  • Entwurfsmuster "Singleton"
  • Entwurfsmuster "Factory"
  • Entwurfsmuster MVC (Modell, View, Controller)
  • Entwurfsmuster MVP (Modell, View, Presenter)
  • Entwurfsmuster Event-Bus
Entwurfsmuster Singleton

Unterteilt man eine Anwendung in Komponenten, so gibt es oft eine, die von mehreren anderen verwendet wird.

Eine naive Herangehensweise wäre ganz zu Anfang ein Objekt dieser Komponenten zu erzeugen und die Referenz über Konstruktoren "durchzureichen". Der Nachteil ist, dass bei einer hierarchischen Struktur der Komponenten auf diese Weise die Anzahl der Konstruktoren-Parameter anwächst. Zudem gibt es den Fall, dass eine Komponente A, die von C verwendet wird, erst über B gereicht werden muss, da C erst von B erzeugt wird. B selbst braucht die Komponente jedoch nicht. So entstehen Abhängigkeiten zwischen Komponenten, die nicht notwendig sind.

Statische Attribute und Methoden einer Klassen lösen das Problem insofern, als dass diese von überall aus per qualifiziertem Aufruf erreichbar sind. So müssen keine Objekte durch Konstruktoren durchgereicht werden und es bleibt bei einer flachen Abhängigkeitshierarchie. Nachteil ist, dass hier die Vorteile der Vererbung auf der Strecke bleiben.

Das Entwurfsmuster Singleton verbindet nun die Vorteile aus den zuvor besprochenen Ansätzen. Das eine Objekt der Klasse wird dabei in einem privaten, statischen Attribut innerhalb der Klasse selbst gespeichert (z.B. instance). Andere Komponenten beschaffen sich die Referenz auf dieses Objekt mittels einer statischen, öffentlichen Methode (z.B. getInstance). Die Erzeugung der Instanz erfolgt beim ersten Methodenaufruf. Die Klasse hat nur private Konstruktoren, was die Erzeugung zusätzlicher Instanzen von außerhalb verhindert.

Weitere Informationen zu dem Entwurfsmuster Singleton sind in dem Wikipedia-Artikel zu finden[11]. Eine weitere Lösung für das Problem ist die sogenannte Dependency Injection[12]. Für Java existiert beispielsweise das von Google entwickelte Framework Google Guice[13], was den "Injektionsvorgang" mit Hilfe von Java Annotations[14] besonders komfortabel macht.

Entwurfsmuster Factory

Wenn eine Instanz eines Objekts benötigt wird, erzeugt man das neue Objekt normalerweise mit Hilfe des Schlüsselwortes new (in Java). Der passende Konstruktor wird aufgerufen und eine Referenz auf das Objekt zurück geliefert. Nun kann es jedoch vorkommen, dass man besondere "Ausführungen" eines Objekts haben möchte. Instanzen, bei denen bestimmte Attribute bereits mit bestimmten Werten vorbelegt sind, ohne dass jedoch andere Informationen beim Erzeugen gebraucht und somit ein anderer Konstruktor benötigt werden würde.

Dieses Problem löst das Entwurfsmuster Factory, wobei es auch hier verschiedene Varianten gibt. Die einfachste sieht so aus, dass der Konstruktor einer Klasse als private deklariert wird und stattdessen beliebig viele statische Erzeuger-Methoden existieren, die unterschiedliche Varianten eines Objekts erzeugen und dessen Referenz zurück liefern.

Weitere Informationen zu den Entwurfsmuster Factory sind zum Beispiel auf Wikipedia zu finden[15].

Entwurfsmuster MVC (Modell, View, Controller)
(thumbnail)
Entwurfsmuster MVC

MVC ist ein Entwurfsmuster zur Strukturierung einer Software mit dem Ziel, später notwendig werdende Änderungen oder Erweiterungen zu vereinfachen und einzelne Teile wiederverwendbar werden zu lassen. Es setzt sich zusammen aus einem sogenannten Model (Datenhaltung und je nach Variante auch Geschäftslogik), einem Controller (Entgegennahme und Auswertung der Benutzereingaben) sowie einer View (Präsentation der Daten). Das Konzept sieht vor, dass der Controller Datenänderungsanfragen an das Modell weitergibt, dieses wiederum nimmt seinerseits die Änderung vor und benachrichtigt alle Views, die sich für eine Datenänderung des Models interessieren. Dazu können sich beliebig viele Views an dem Modell als Listener anmelden.

Auf diese Weise wird eine Trennung und Austauschbarkeit von Datenhaltung, Anzeige und Geschäftslogik möglich. Außerdem skaliert das Konzept gut, da es dem Modell beispielsweise egal sein kann, wie viele unterschiedliche Views sich für Modell-Änderungen interessieren. Des Weiteren spielt es auch keine Rolle, auf welch unterschiedliche Arten der Benutzer Aktionen auslösen kann, die eine Datenänderung herbei führen, da das Model durch seine Methoden klar definierte Möglichkeiten bereitstellt, die von allen Controllern genutzt werden müssen.

Weitere Informationen zu MVC finden sich auf Wikipedia[16].

Entwurfsmuster MVP (Modell, View, Presenter)
(thumbnail)
Entwurfsmuster MVP

MVP unterscheidet sich vom klassischen MVC (Modell, View, Controller) in der Art und Weise, wie die drei Komponenten miteinander kommunizieren und wie die Verantwortlichkeiten verteilt sind. Während bei MVC die View das Modell kennt und von diesem über Änderungen benachrichtigt wird, kennt in MVP die zugehörige View das Modell nicht. Stattdessen übernimmt der Presenter die Kommunikation mit dem Modell und reicht die Änderungen an die View weiter. Auf diese Weise kann die gesamte Logik in den Presenter wandern, während die View ausschließlich alle Anzeige- und Steuerelemente enthält.

Auch hier gibt es verschiedene Varianten des Entwurfsmusters MVP. Die hier vorgestellte lehnt sich an die von Martin Fowler[17] definierte Variante mit dem Namen "Passive View" an. Das Entwurfsmuster lässt sich am einfachsten mit einem Beispiel erläutern.

(thumbnail)
Beispiel-Dialog


Beispiel

Angenommen, es soll eine Anwendung geschrieben werden, mit Hilfe der Personen verwaltet werden können. Betrachten wir den Dialog, bei dem ein neuer Benutzer hinzugefügt werden kann (s. Abbildung rechts). Nachdem die Personendaten korrekt eingegeben wurden, kann der Benutzer auf OK klicken, um den Eintrag zu übernehmen, oder auf Abbrechen, um den Vorgang zu beenden. Außerdem wird das Feld Email auf syntaktische Korrektheit überprüft und alle Felder dürfen nicht leer sein. Das Ergebnis der Feldprüfung wird jeweils dahinter mit Hilfe eines Icons angezeigt. Außerdem soll der Button OK nur gedrückt werden können, wenn alle Eingaben korrekt sind.

Es gibt hier also verschiedene Interaktionen mit dem Benutzer, die wir im Folgenden kurz aufzählen.

Zunächst die Aktionsmöglichkeiten des Benutzers:

  • Eingabe in das Feld Name
  • Eingabe in das Feld Vorname
  • Eingabe in das Feld Email
  • Klicken des Buttons OK
  • Klicken des Buttons Abbrechen
  • Klicken des X-Buttons oben rechts

Die möglichen Aktionen der GUI:

  • Hinweis-Icon hinter dem Feld Name anzeigen
  • Hinweis-Icon hinter dem Feld Vorname anzeigen
  • Hinweis-Icon hinter dem Feld Email anzeigen
  • Button OK deaktivieren
  • Feld Name auslesen
  • Feld Vorname auslesen
  • Feld Email auslesen

Das Entwurfsmuster MVP ist nun so aufgebaut, dass sich View und Presenter jeweils kennen. Die View enthält ausschließlich die GUI-Komponenten, während der Presenter die zugehörige Logik enthält. Welche Methoden zur Kommunikation zur Verfügung gestellt werden müssen, wird durch zwei Interfaces festgelegt und kann aus den gesammelten Aktionen von Benutzer und GUI abgeleitet werden (s. oben).

Beispiel-Dialog

Jedes Mal wenn der Benutzer in der GUI nun den Inhalt der Eingabe-Felder ändert, wird der Presenter von der View mit Hilfe der entsprechenden Methoden informiert. Der Presenter überprüft daraufhin den Feldinhalt und veranlasst gegebenenfalls die View dazu, hinter den Feldern das Fehler-Icon dazustellen. Wenn mindestens eine Eingabe nicht korrekt ist wird außerdem die View dazu veranlasst, den OK-Button zu deaktivieren. Wichtig ist hier zu erkennen, dass die Namen der View-Methoden nicht vorschreiben, auf welche Art und Weise der Benutzer darüber informiert wird, was gerade falsch ist bzw. welche Aktionen er ausführen kann und welche nicht. Die Methoden sind semantisch benannt und lassen dem GUI-Entwickler die volle Kontrolle darüber, wie die Oberfläche aus Usability-Sicht aufgebaut ist. Die Methode setSaveEnabled(...) sagt beispielsweise nur, ob die Aktion "Speichern" vom Benutzer gerade ausgeführt werden kann oder nicht. Die View könnte anstatt den Button zu deaktivieren, diesen auch ganz verschwinden lassen, sollte das aus Gründen der Benutzbarkeit als sinnvoll angesehen werden.

In der anderen Richtung verhält es sich genauso. Der Presenter stellt zum Beispiel die Methode abort() zur Verfügung, die den Vorgang beendet. Es wird hier nicht vorgeschrieben, welche Möglichkeiten der Benutzer hat, diese Aktion auszuführen. Neben den Buttons Abbrechen und dem "X" oben rechts, könnte später vielleicht noch die "Esc-Taste" als dritte Möglichkeit hinzukommen. In allen drei Fällen wird auf dem Presenter die selbe Methode aufgerufen.

Auf diese Weise wird eine sehr natürliche Art der Trennung möglich. Die Wahl der notwendigen Interface-Methoden ergibt sich relativ intuitiv aus der Analyse der Benutzer-Interaktionen.

Ein weiterer großer Vorteil des Entwurfsmusters ist die äußerst gute Testbarkeit des Presenters mit Hilfe von Unit-Tests, da die View selbst keine nennenswerte Logik enthält. Dazu werden typischerweise sogenannte "View-Teststubs" erstellt, die das View-Interface implementieren, jedoch keine wirklichen GUI-Elemente erzeugen. Diese stellen zusätzlich Methoden zur Verfügung, die den Zustand des Teststubs für die Testklassen komfortabel setzen und auslesen lassen.

Ein Presenter-Test sieht im Allgemeinen wie folgt aus:

  • Erzeugung des View-Teststubs
  • Erzeugung des zu testenden Presenters und gegenseitige Registrierung zwischen View und Presenter
  • Initialisierung der Test-View, sodass sie die Ausgangssituation des Testfalls repräsentiert
  • Aufruf der zu testenden Methode im Presenter
  • Überprüfung des erwarteten Zustands der Test-View

Trotz der oben genannten Vorteile sollte man sich stets über den Mehraufwand durch die zusätzlichen Interfaces im Klaren sein. MVP kann seine vollen Stärken besonders bei GUI-Komponenten mit ausgeprägter Benutzerinteraktion entfalten. Kleinere Views, die dem Benutzer ausschließlich etwas anzeigen, ohne dass dieser selbst mit ihr interagiert, brauchen keinen gesonderten Presenter. Hier reicht das klassische Observer-Muster, bestenfalls umgesetzt mit einem Eventbus (s. nächster Abschnitt).


(thumbnail)
Entwurfsmuster Eventbus
Entwurfsmuster Eventbus

Wir haben oben den Unterschied zwischen MVC und MVP kennen gelernt. MVC arbeitet zur Benachrichtigung der View typischerweise mit dem sogenannten Observer-Entwurfsmuster. Dabei hat ein Observer (zum Beispiel die View) die Möglichkeit, sich an einem Objekt (zum Beispiel dem Modell) als Listener anzumelden, um fortan über entsprechende Änderungen informiert zu werden. Dazu implementiert der Observer ein Interface, was von der zu überwachenden Entität zur Verfügung gestellt wird. Diese Entität ist außerdem für die Verwaltung der angemeldeten Observer-Objekte verantwortlich. Es muss Methoden zur Registrierung und Deregistrierung zur Verfügung stellen.

Das Problem hier ist, dass die Listener-Verwaltung in jeder überwachbaren Entität implementiert werden muss. Gibt es zudem unterschiedliche Ereignisse, erhöht sich der Implementierungsaufwand noch weiter, da für jeden Ereignis-Typ weitere Verwaltungs-Methoden hinzu kommen. Dieser Aufwand lässt sich reduzieren, wenn es nur einen Listener-Typ gibt und das Ereignis mit Hilfe von Enums unterschieden wird. Hier verlagert sich der Aufwand dann zum Observer, der sich möglicherweise nicht für alle Ereignistypen interessiert und anhand der Enums eine Fallunterscheidung durchführen muss.

An diesem Punkt setzt das Entwurfsmuster Eventbus an. Auch mit diesem kann man das Entwurfsmuster Observer umsetzen. Im Wesentlichen stellt ein Eventbus eine zentrale Ereignis-Quelle zur Verfügung, an denen sich Observer für Ereignisse anmelden können und bei entsprechendem Auftreten informiert werden. Gleichzeitig dient es Komponenten als zentrale Stelle, über die Ereignisse publik gemacht werden. Typischerweise existiert in einer Applikation nur genau ein Eventbus, der von allen Komponenten verwendet wird. So bietet es sich an, den Zugriff als Singelton zu implementieren. Daraus resultiert eine erhebliche Reduzierung des Implementierungsaufwands, da nicht mehr für jedes Modell eine Listener-Verwaltung geschrieben werden muss, was auch die Fehleranfälligkeit reduziert.

Ein weiterer wichtiger Vorteil ist die dadurch entstehende Entkopplung der Komponenten. Da der Eventbus nun als zentrale Einheit in die Mitte rückt, muss weder der Observer die tatsächliche Quelle des Ereignisses kennen, noch muss die Ereignisquelle wissen, wer tatsächlich auf das Ereignis reagiert. Ein Austausch bzw. die Erweiterung von zusätzlichen Quellen und Empfängern ist ohne Probleme möglich. Eine nützliche Erweiterung des Eventbus sieht außerdem die Einführung von sogenannten Topics oder Channels vor. So kann eine Quelle Ereignisse nur über ein bestimmtes Topic veröffentlichen und ein Empfänger nur auf solche Ereignisse reagieren, die zu einem bestimmten Topic veröffentlicht wurden.

Auch hinsichtlich Testbarkeit bietet ein Eventbus besondere Vorteile. Zum Testen der Quelle muss sich der Unit-Test lediglich am Eventbus für das entsprechende Ereignis anmelden und darauf reagieren. Zum Testen eines Empfängers kann der Unit-Test als Ereignisquelle dienen.

Tipps

Grundsätzlich sollte man die Wahl des Entwurfsmusters von Fall zu Fall ganz individuell treffen. Es ist nicht sinnvoll für alles zwanghaft ein einziges Muster zu verwenden, nur weil es das vermeintliche Gefühl von Konsistenz oder schöner Software-Architektur vermittelt. Außerdem sollte man sich überlegen, wann die Verwendung von Interfaces sinnvoll ist. Wenn zunächst nur eine Implementierung vorgesehen ist und eine weitere nur in der Theorie und in ferner Zukunft besteht, sollte man zunächst darauf verzichten und die Klasse ohne Interface implementieren. Auf diese Weise ändert sich nur an einer Stelle etwas, sollten während der Entwicklung noch einmal die Methoden-Signaturen geändert werden oder weitere Methoden hinzu kommen.

Der objektorientierte Softwareentwurf kann gut mit Hilfe von UML-Klassendiagrammen durchgeführt werden. Hier gilt wie bei allen Diagrammen: Nur so viele Details mit aufnehmen, wie es für den aktuellen Fall sinnvoll ist. Eine riesige Tapete aller Klassen mit Methoden und Attributen sowie jeglicher Beziehungen bringt selten die gewünschte Übersicht. Es ist sinnvoller lieber mehrere Diagramme für unterschiedliche Teile der Software zu haben, die jeweils auf ein anderes Detail eingehen. Es kann beispielsweise ein Diagramm geben, in dem die Hauptkomponenten als Klassen auftauchen und auch deren Beziehungen untereinander, nicht aber deren Methoden und Attribute. Vermutlich hilft es dem Leser auch nichts, alle Getter- und Setter in ein solches Diagramm mit aufzunehmen.

Phase: Implementierung und Test

Arbeitsteilung bei der Implementierung

Bei der personellen Aufteilung der Implementierungsaufgaben gibt es nun verschiedene Varianten, die jeweils ihre Vor- und Nachteile haben.

Eine horizontale Aufteilung sähe vor, dass die Verantwortlichkeiten entlang der Software-Schichten geteilt werden. So wäre beispielsweise ein Teil des Teams für die Grafische Benutzeroberfläche zuständig, während sich ein weiterer Teil des Teams um die Geschäftslogik und die Datenhaltung kümmert. Ein letzter Teil könnte ausschließlich für die Implementierung der Algorithmen zuständig sein. Diese Aufteilung hat den Vorteil, dass die einzelnen Teammitglieder jeweils ihr Spezialgebiet haben, in dem sie sich gut auskennen müssen und auf das sie sich voll und ganz konzentrieren können. Nachteil ist, dass gerade kleine Teams dadurch nicht sonderlich robust sind. Fällt ein Teammitglied im Laufe des Projekts aus, kann es im Team schnell an fachlicher Kompetenz mangeln, was zu größeren Verzögerungen führen kann.

Eine vertikale Aufteilung hingegen sieht vor, dass die Aufgabenverteilung eher Feature orientiert vorgenommen wird. Ein Teammitglied ist dabei voll für ein Feature verantwortlich und implementiert dieses über alle Software-Schichten hinweg. Auf diese Weise kann der Ausfall eines Teammitglieds besser kompensiert werden, da das gesamte Team von vorne herein in allen Schichten der Software eingewiesen ist. Nachteil ist hingegen, dass jeder Kompetenz in jedem Bereich besitzen muss, was ggf. anfangs zu höheren Einarbeitungszeiten führen kann.

Welche Aufteilung man für das Projekt wählt, sollte zu Anfang im Team besprochen werden. In die Entscheidung mit einfließen sollte dabei die Größe des Teams und auch die Vorkenntnisse der einzelnen Teammitglieder. Mischformen sind natürlich auch möglich. Wichtig ist nur, dass man sich gemeinsam Gedanken darüber macht, sich über die Konsequenzen klar wird und dann eine für das Projekt sinnvolle Vorgehensweise wählt.

Tipps für die Implementierung

Grundsätzlich ist es eine gute Idee sich vor der ersten Zeile Programmcode zu überlegen, was genau zu tun ist. Manchmal hilft es auch zunächst die Schritte in Form von Kommentaren untereinander zu schreiben und diese dann Schritt für Schritt abzuarbeiten.

Es gibt einige Fragen, die man sich während der Programmierung immer wieder stellen sollte:

  • Gibt es Quellcode der öfter verwendet wird und besser in eine Methode ausgelagert werden sollte?
  • Ist der Quellcode nachvollziehbar?
  • sind die Variablen- und Methodennamen sprechend?

Gelegentlich gibt es Nachbedingungen am Ende einer Methode, die dringend eingehalten sein müssen. Während der Entwicklung hilft es, diese in jedem Fall abzuprüfen und im Falle einer Verletzung eine Ausnahme zu werfen. Sollte es beim manuellen Testen des Programms eine Eingabe geben, die genau zu diesem Fall führt und möglicherweise bei den automatischen Tests vergessen wurde, wird man mit der geworfenen Ausnahme darauf hingewiesen. Viele Programmiersprachen bieten zu diesem Zweck sogenannte "Asserts" als Teil ihres Sprachumfangs.

Dokumentation des Quellcodes

Hier stellt sich oft die Frage: Was sollte man in Form von Kommentaren dazu schreiben und was ist bereits offensichtlich und somit beim Lesen und Verstehen hinderlich? Aus der Erfahrung lassen sich einige Fälle aufzählen, wann man in jedem Fall kommentieren sollte:

  • Beim Behandeln von Sonderfällen
  • Wenn der nachfolgende Verarbeitungsschritt von einer nicht sofort offensichtlichen Vorbedingung ausgeht, weshalb dieser überhaupt erst korrekt ist
  • Wenn eine tiefe Verschachtelung von Kontrollstrukturen notwendig ist und der daraus resultierende Kontrollfluss nur schwer nachvollziehbar ist
  • Bei der Verwendung mehrdimensionaler Datenstrukturen

Außerdem sollten mindestens jene Public-Methoden dokumentiert werden, die von anderen Teammitgliedern verwendet werden sollen. Aus diesen Spezifikationen muss hervorgehen, was die Methoden im Allgemeinen machen, welche Eingabeparameter (inkl. Definitionsbereich) diese erwarten, was wann zurück gegeben wird (inkl. Wertebereich) und in welchen Fällen Exceptions geworfen werden. Viele Entwicklungsumgebungen bieten bei der Verwendung von Methoden einer fremden Klasse Hilfe in Form von Auto-Vervollständigungen und komfortabler Anzeige der Spezifikation an. Auf diese Weise muss das betroffene Teammitglied nicht selbst in den Quellcode der fremden Klasse schauen sondern kann sich voll und ganz auf die angezeigte Spezifikation verlassen. Daraus folgt natürlich, dass die Spezifikation stets aktuell gehalten sein muss. Inbesondere nachträgliche Änderungen müssen im Team kommuniziert werden.

Auch der Kopf einer Klasse sollte dokumentiert werden. Dabei ist eine kurze Beschreibung des Zwecks sinnvoll sowie mindestens ein hauptverantwortlicher Autor.

Versionierung während der Implementierung

Wenn man im Rahmen des Projekts für den Quellcode ein Versionierungstool wie Git oder SVN verwendet, was nur dringend empfohlen werden kann, stellt sich die Frage, wann und wie häufig die Arbeit versioniert werden sollte. Das hängt unter anderem davon ab, auf welchen Workflow man sich in dieser Hinsicht geeinigt hat. Folgende Situationen sind gute Zeitpunkte für einen Commit:

  • nach der Behebung eines Bugs
  • nach der Implementierung eines Features (nachdem man sich von der Lauffähigkeit überzeugt hat)
  • nach einem Refactoring

Diese ehere kleinen und atomaren Versionierungen haben auch den Vorteil, dass die anderen Teammitglieder mit Hilfe der Commit-Nachrichten gut nachvollziehen können, was im Einzelnen getan wurde.

Testen während der Implementierung eines Features

Wie oben bereits angesprochen testet der Entwickler sein entwickeltes Feature vor der Versionierung regelmäßig und ausführlich selbst, bevor es zum weiteren Test an Teamkollegen weitergegeben wird. Erfahrungsgemäß passiert das weitestgehend manuell, indem das Programm gestartet und einige Eingaben geprüft werden. Hier ist es eine gute Idee stattdessen gleich erste Unit-Testfälle (beispielsweise mit JUnit[18]) zu schreiben. Dies ersetzt nicht das ausführliche Testen des Features (bestenfalls) durch eine weitere Person, hat aber den Vorteil, dass die geschriebenen Tests auf Knopfdruck immer wieder ausgeführt werden können.

Für viele Programmiersprachen stehen Test-Frameworks zur Verfügung, die das Schreiben von automatischen Tests recht einfach machen.

Styleguide

Um eine gute Lesbarkeit und Wartbarkeit des Quellcodes zu gewährleisten ist es wichtig, dass genaue Code-Conventionen festgelegt und durchgesetzt werden. Diese sollten am Anfang des Projekts vom Team bestimmt werden. Viele Entwicklungsumgebungen wie Eclipse unterstützen den Programmierer in dieser Hinsicht von Haus aus sehr gut. Code-Conventionen lassen sich über die Projekt-Einstellungen konfigurieren und der Quelltext wird beim Speichern durch sogenannte Save-Actions ggf. automatisch anhand dieser formatiert.

Phase: Auslieferung

Hier ist man nun an einer Stelle im Projektverlauf angekommen, wo der Kunde / Betreuer die (möglicherweise erste) lauffähige Version der Software erhält. Das Produkt ist ausgiebig getestet und bereit nun endlich genutzt zu werden. Vor der Auslieferung sollten allerdings einige organisatorische Schritte durchgeführt werden, die folgende Aktivitäten vereinfachen. Das gilt insbesondere dann, wenn die Software nach der Auslieferung noch weiter entwickelt wird.

Ein wichtiger Punkt ist die Versionierung. Die ausgelieferte Version sollte in der Versionsverwaltung entsprechend markiert (getagged) werden und als eigenständiger Branch existieren. Das hat den Vorteil, dass später hinzukommende Bug-Fixes für die ausgelieferte Version und die Entwicklung neuer Features klar getrennt und unabhängig voneinander geführt werden können. Auf diese Weise können neue Features implementiert werden, ohne dass diese beim nächsten Patch für den Kunden zwangsläufig mit ausgeliefert werden müssen.

Es ist eine gute Idee für den Auslieferungsprozess eine Check-Liste zu führen, um keine Punkte zu vergessen, z.B.:

  • Scheitert keiner der automatischen Testfälle?
  • Sind die Versionshinweise in der Software entsprechend angepasst?
  • Ist die Version im Repository entsprechend markiert?
  • Sind wirklich nur solche Features enthalten, die tatsächlich bereits für eine Auslieferung bestimmt waren?
  • Wurden neue Software-Bibliotheken verwendet, die nun aus lizenztechnischen Gründen erwähnt werden müssen?

Qualitätssicherung

Die Qualitätssicherung während eines Software-Projekts begrenzt sich nicht ausschließlich auf die Tests während und nach der Implementierung. Vielmehr sollten in allen Projektphasen kontinuierlich qualitätssicherende Maßnahmen eingeplant und durchgeführt werden. Das betrifft sowohl die Anforderungen zu Beginn des Projekts als auch die Entwurfsdokumente und schließlich den Quellcode der implementierten Software. Qualitätsmerkmale für die formulierten Anforderungen wurden im Abschnitt oben bereits beschrieben.

(thumbnail)
Testverfahren
Jedes Team eines Softwareprojekts hat das Ziel eine fehlerfreie Software zu erstellen. Bei diesem Kriterium handelt es sich um einen Qualitätsaspekt der Software. Neben diesem wichtigen Aspekt, gibt es weitere Merkmale, die die Qualität der Software beschreiben und typischerweise in Form von Anforderungen formuliert werden. Einige sind hier aufgeführt:
  • Funktionalität
  • Zuverlässigkeit
  • Benutzbarkeit
  • Effizienz
  • Änderbarkeit
  • Übertragbarkeit
  • Testbarkeit

Diese Qualitätsmerkmale sind allgemein formuliert, so dass sie auf jedes Software-Produkt anwendbar sind. Zur Überprüfung der gestellten Anforderungen gibt es nun verschiedene Methoden, die unterschiedlich kombiniert werden können und auch unterschiedlich aufwendig sind. Hier sollte eine Kosten/Nutzen-Kalkulation durchgeführt werden. Selten ist es zeitlich möglich und auch sinnvoll, alle qualitätssichernden Methoden auf alle Teile der Software anzuwenden. Hier hilft es, zuvor eine Prioritäten-Liste zu erstellen und anhand dieser angemessene Verfahren anzuwenden.

Bei Testverfahren kann allgemein in dynamische und statische Testverfahren unterschieden werden. Die dynamischen Testverfahren sind dadurch gekennzeichnet, dass der Prüfling (das zu prüfende Software-Produkt) mit einer konkreten Eingabe ausgeführt und in einer realen Umgebung getestet wird. Im Gegensatz dazu gibt es statische Testverfahren, bei denen der Prüfling nicht ausgeführt wird, sondern der Quellcode zu analysieren ist. Beispielsweise ist für die Eigenschaft "Änderbarkeit" keine Ausführung der Software notwendig, wohingegen für die Überprüfung der "Funktionalität" nur mit einem dynamischen Testverfahren überprüfbar ist. Beide Verfahren ergänzen sich gegenseitig.

Dynamischer Test

Das dynamische Testverfahren wird dadurch gekennzeichnet, dass die zu prüfende Software mit einer konkreten Eingabe in einer realen Umgebung ausgeführt wird. Hierbei handelt es sich um ein Stichprobentest, was heißt, dass die Software stichprobenartig mit möglichen Eingaben ausgeführt wird, um Fehler zu finden. Werden keine Fehler gefunden, so impliziert dies nicht, dass es keine Fehler gibt. Demnach kann mit diesem Verfahren die Korrektheit des Prüflings nicht nachgewiesen werden. Das muss jedem beim Testen bewusst sein.

Automatische Tests

Automatische Tests (auch Unit-Tests genannt) sind im Prinzip kleine Programme, die ein Modul oder eine Komponente der Software testen. Sie werden von dem Tester einmalig programmiert und können danach jederzeit erneut ausgeführt werden, um beispielsweise nach einer Änderung des Prüflings zu schauen, ob sich Fehler eingeschlichen haben. Für die meisten Programmiersprachen existieren dazu Frameworks, die das Schreiben von automatischen Tests stark vereinfachen. Ein Testfall ist im einfachsten Fall wie folgt aufgebaut:

  • Initialisierung des Systems, sodass der gewählte Test durchgeführt werden kann (zum Beispiel das Laden bestimmter Daten, oder die Überführung in einen bestimmten Zustand)
  • Ausführung der zu testenden Methode mit den für den Testfall gewählten Parametern
  • Überprüfung des Rückgabeergebnis der zu testenden Methode mit dem Soll-Ergebnis
  • Logging des Testergebnis

Etwas komplizierter wird es, wenn nicht nur eine einzelne Methode getestet werden soll sondern vielmehr das Systemverhalten beim Aufruf einer ganzen Kette von Methoden. Dann reicht es nicht mehr nur die Rückgabewerte der Methoden zu überprüfen (sofern diese überhaupt existieren) sondern es muss der resultierende Systemzustand evaluiert werden. Dieser ist oft nicht ganz so einfach zu ermitteln und hier kommt der oben erwähnte Qualitäts-Begriff der Testbarkeit ins Spiel. Bereits im Entwurf der Software sollte berücksichtigt werden, dass später geschriebene Testfälle an bestimmte Informationen leicht heran kommen müssen, um das Resultat der getesteten Aktion evaluieren zu können. Oft ist es so, dass dies immer irgendwie mit entsprechendem Aufwand möglich ist. Dem Tester kann jedoch sehr viel Arbeit abgenommen werden, wenn das von vorne herein berücksichtigt wird.

Wie kommt nun zu sinnvollen Testfällen? Einerseits sollen alle Fehler gefunden werden, andererseits können nicht alle möglichen Eingaben ausprobiert werden. In der Literatur findet man häufig Begriffe wie Äquivalenzklassenbildung[19] und Grenzwertanalyse[20]. Dahinter verbergen sich Vorgehensweisen zur systematischen Bildung von Testfällen, die möglichst viel Abdecken sollen. Bei der Wahl der Testfälle können folgende Dinge helfen:

  • Die Spezifikation der Methoden. Welchen Definitionsbereich gibt es? Welchen Wertebereich? In welchen Fällen soll ein Fehler geworfen werden? Gibt es Sonderfälle?
  • Die Usecase-Diagramme aus dem Entwurf. Zuvor aufgeführte Use-Cases sind gute Kandidaten für Testfälle, da sich typische Abläufe bei der Benutzung der Software beschreiben. Dies kann dann schwierig sein, wenn dabei eine Interaktion mit der grafischen Benutzeroberfläche notwendig ist. Wie diesen Schwierigkeiten entgegengewirkt werden kann, ist weiter oben in dem Abschnitt zum Thema MVP beschrieben. Für viele Programmiersprachen gibt es auch Frameworks zum Test von GBOs.
  • Die eigene Phantasie. Es gibt meist sehr viele Bedienschritte bei der Verwendung der Software, die so in der gewählten Reihenfolge erstmal keinen Sinn ergeben. Doch gerade bei ungeschulten Benutzern können diese tatsächlich auftreten. Auch hier sollte die Software nicht unkontrolliert abstürzen. Dies ist vielleicht der schwierigste Teil beim Testen.

Abschließend sei gesagt, dass der Tester eines Moduls nach Möglichkeiten nicht gleichzeitig der Author sein sollte. Für die Auswahl der Testfälle ist es besser nicht die Internen Strukturen des Modul zu kennen, sondern ausschließlich die Spezifikation.

Unittest-Frameworks gibt es für die meisten Sprachen:

  • Für Java und Eclipse: JUnit[21]
  • Eine umfangreiche Liste von Unittest-Frameworks für viele Sprachen findet sich auf Wikipedia[22]
Qualitätssicherung der Testfälle mit Hilfe von Quellcode-Überdeckungs-Tests

Beim Erstellen von Testfällen kann es hilfreich sein zu wissen, welche Teile des Quellcodes tatsächlich abgedeckt sind und welche nicht. Struktur-Tests in Form von Quellcode-Überdeckungs-Tests können diese Frage beantworten. Dabei wird der Quellcode zunächst instrumentiert und die Testfälle dann ausgeführt. Bei der Ausführung kann das Test-Framework feststellen, welche Teile des Quellcodes ausgeführt wurden und welche nicht. Daraus können verschiedene Metriken berechnet werden, die jeweils ein unterschiedliches Maß der Überdeckung beschreiben. Eine Befehls-Überdeckung von 100% würde beispielsweise bedeuten, dass jede Zeile Quellcode von mindestens einem Testfall ausgeführt wurde. Des Weiteren gibt es noch Zweig-Überdeckung, Schleifen-Überdeckung und schließlich auch die Pfad-Überdeckung, sowie noch einige mehr. Die zuletzt genannte ist in der Praxis jedoch irrelevant, denn eine vollständige Pfad-Überdeckung würde bedeuten, dass wirklich jeder mögliche Ausführungspfad der Software von Testfällen abgedeckt wäre.

Die Erreichung bestimmter Überdeckungsmaße kann als Anforderung für Testfälle herangezogen werden. Dabei sollte jedoch stets klar sein, was die Maße im Einzelnen aussagen. Schnell suggeriert die Erreichung einer bestimmten Überdeckungsrate eine gewisse Testvollständigkeit und läutet somit das vorzeitige Ende der Bemühungen ein. Tatsächlich sagen die Maße nichts über den Sinn und Zweck der Testfälle aus. Um diesen Trugschluss von vorne herein zu vermeiden, ist es eine gute Idee den Quellcode-Überdeckungs-Test erst dann durchzuführen, wenn man der Meinung ist, dass nun alles ausreichend getestet sei. Auf diese Weise profitiert man von diesem, indem er dem Tester noch die eine oder andere Stelle Quellcode aufweist, die von den Testfällen noch nicht erreicht wurde.

Die meisten Frameworks für Quellcode-Überdeckungs-Tests bieten eine Integration für diverse Entwicklungsumgebungen an. Für Java sind zur Zeit folgende Frameworks mit unterschiedlich ausgeprägter Feature-Auswahl verfügbar:

  • CodeCover (Eclipse-Plugin) [23]
  • Emma[24]
  • EclEmma (Eclipse-Plugin basierend auf Emma)[25]
  • Cobertura [26]
Tipps

Es ist gute Praxis, mit einer leicht destruktiven Mentalität an das Testen heranzugehen. Ein Testlauf ist dann "erfolgreich", wenn tatsächlich Fehler dabei gefunden wurden, d.h. wenn Testfälle fehlschlagen. Fehler sind in größern Projekten mit Sicherheit vorhanden, sowohl kritische als auch weniger kritische. Wenn also die gerade geschriebenen automatischen Testfälle ohne Zwischenfall zu Ende laufen, wurden "leider" keine weiteren Fehler gefunden. Es ist wichtig, diese Mentalität bei allen Team-Mitgliedern zu forcieren. Niemand im Team sollte sich über gefundene Fehler in einem fertig geglaubten Modul ärgern, im Gegenteil: Der Fehler war schon immer da, wurde aber gerade erst aufgedeckt - herzlichen Glückwunsch! Ein Grund zur Freude, denn seine Beseitigung führt zur Steigerung der Softwarequalität.

Beim Testen von Softwaresystemen mit Datenbanken kann das Testen recht umständlich werden, wenn man bedenkt dass vor jedem Test ein bestimmter Zustand in der Datenbank angenommen werden muss und nach dem Test der Ursprungszustand wieder hergestellt sein soll. Da in vielen Test-Frameworks die Ausführungsreihenfolge der Testfälle nichtdeterministisch ist, muss die Datenbank in jedem Fall immer wieder zurückgesetzt werden. Anstatt die Datenbank nun nach jedem Testfall immer wieder manuell zurückzusetzen (z.B. mit einer Kette von Löschoperationen) empfiehlt es sich, die von den meisten Datenbanksystem zur Verfügung gestellten Transaktions-Mechanismen zu verwenden. Ein Datenbank-Test könnte dann wie folgt aufgebaut sein:

  • Datenbankverbindung herstellen
  • Für den Testfall notwendige Einträge durchführen (zuvor Auto-Commit auf False setzen!)
  • zu testende Aktionen durchführen
  • System- bzw. Datenbankzustand entsprechend überprüfen
  • Rollback durchführen

Manipulationen, die nicht mit einem Datenbank-Commit abgeschlossen sind, können in der aktuellen Session sehr wohl mit einem Select gelesen werden. Diese Tatsache kann man sich beim Testen zu Nutze machen.

Reviews

(thumbnail)
Review-Prozess

Reviews haben das schwere Los bei knapp bemessener Planung der erste Kandidat zu sein, der aufgrund von Zeitmangel gekürzt oder ganz gestrichen wird.

Wie in der Abbildung zu sehen, wird der Review Prozess für ein Prüfling (zum Beispiel eine fertig implementierte Klasse) vom Entwickler gestartet, indem er den Prüfling einem Gutachter zuordnet und für den Review-Prozess freigibt. Die Kriterien, nach denen der Gutachter anschließend den Quelltext der entsprechenden Klasse untersucht sind vorher festgelegt und werden als eine Review-Vorlage gespeichert. Falls der Gutachter Beanstandungen in der Klasse findet, werden diese im Review-Protokoll festgehalten und die zugehörigen Abschnitte im Quelltext markiert. Diese Markierungen können beispielsweise mittels Task-Tags 'REVIEW_NameDesEntwicklers' durchgeführt werden. Der Entwickler kann anschließend das Review-Protokoll sowie die Markierungen einsehen und seine Implementierung anpassen. Dies schließt er mit der Umbenennung von 'REVIEW_NameDesEntwicklers' in 'REVIEW_NameDesGutachters' ab, so dass der Gutachter über die Änderungen informiert wird. Anschließend untersucht der Gutachter die Klasse erneut. Dies wird solange durchgefügt bis der Gutachter keine Beanstandungen mehr hat. Abschließend markiert dieser das Review-Protokoll als "geschlossen" und entfernt alle zugehörigen Task-Tags aus dem Quelltext.

Vor allem bei großen Software-Projekten ist es wichtig ein Dokument mit dem Stand der Qualitätssicherung immer auf dem aktuellsten Stand zu haben. Es sollte immer direkt erkennbar sein für welche Dateien der Review-Prozess durchgeführt wurde und wie das Ergebnis des Reviews war. Nur falls ein solches Dokument existiert, kann am Ende mit Sicherheit festgestellt werden, ob für alle Dateien der Review-Prozess erfolgreich beendet wurde. Diese Dokumentation kann manuell durchgeführt werden, beispielsweise in einer Excel-Datei. Jedoch kann es passieren, dass das Dokument nicht immer auf dem aktuellsten Stand ist. Somit ist die Verwendung von Review-Tools eine empfehlenswerte Alternative. Die Vorteile eines solchen Tools sind unter anderem, dass die Reviews online durchführbar sind und somit Treffen eingespart werden können. Des Weiteren können manche Prozesse, wie beispielsweise die Zuteilung einer zu prüfenden Datei zu einem Gutachter, automatisiert werden. Darüber hinaus stellt ein solches Tool sicher, dass die Dokumentation der (Zwischen-)Ergebnisse (Protokolle) auf dem aktuellsten Stand sind und durch die automatische Aufnahme der Kommunikation zwischen dem Entwickler und Gutachter, werden alle Informationen zu den Reviews festgehalten.

Ein Beispiel für ein Review-Tool ist das webbasierte Gerrit[27], welches auf dem Versionsverwaltungssystem Git basiert.

Werkzeuge

Bei einem Software-Projekt an dem mehr als eine Person arbeitet ist es unerlässlich Software-Werkzeuge zu verwenden, die bei der Umsetzung helfen. Dazu gehört ein Projektlaufwerk des r/ft, auf dem unter anderem die Fortschritte und Ergebnisse zentral gespeichert werden. Des Weiteren ist ein Versionsverwaltungssystem wie zum Beispiel SVN[28] oder Git[29] notwendig, ohne das ein gemeinsames und gleichzeitig produktives Arbeiten am Quellcode nicht möglich ist. Außerdem sollte man, abhängig von der gewählten Programmiersprache, eine Entwicklungsumgebung verwenden (zum Beispiel Eclipse im Falle von Java). Eine solche kann die Implementierung erheblich vereinfachen und hat zudem den Vorteil, dass durch Plugins oft auch eine nahtlose Integration mit dem gewählten Versionsverwaltungssystems möglich wird. Schließlich bleiben verschiedene Modellierungstools zur Erstellung von Grafiken und UML-Diagrammen zu erwähnen.

Für die Erstellung der Projektdokumente bietet sich aus folgenden Gründen LaTeX[30] an:

  • Es ist kostenlos, für alle Plattformen geeignet und sehr gut dokumentiert.
  • LaTeX ermöglicht die Erstellung leserlicher und einheitlich formatierter Dokumente.
  • Es bietet eine sehr gute Unterstützung für mathematischen Formeln.
  • Da Dokumente aus einzelnen Modulen zusammengesetzt werden können, eignet es sich für Gruppenarbeiten.


Versionsverwaltungssysteme

SVN

SVN ist ein weit verbreitetes Versionsverwaltungssystem, das bei studentischen Softwareprojekten im Fachbereich Informatik bisher häufig verwendet wurde. Das hat unter anderem folgende Gründe:

  • SVN ist einfach zu verstehen und bietet gerade für Eclipse eine sehr gute Toolunterstützung.
  • Das SVN-Repository kann auf dem Projektlaufwerk gehostet werden.
  • SVN ist kostenlos

Wie man ein SVN-Repository auf dem Projektlaufwerk einrichtet, ist auf den Seiten des r/ft beschrieben[31].

Hier einige SVN-Clients:

  • Eclipse-Plugin Subversive[32] oder Subclipse[33]
  • Tortoise SVN für Windows[34]
  • Eine umfangreiche Liste von Clients inklusive Vergleich ist auf Wikipedia zu finden[35]
Git

Git[36] ist dabei nach und nach SVN abzulösen. Einer der wesentlichen Unterschiede zu SVN besteht darin, dass es dezentral ist. Das heißt es gibt nicht ein zentrales Repository auf einem entfernten Server, wie das bei SVN der Fall ist, sondern jeder Benutzer hat eine Kopie des gesamten Repositories lokal verfügbar. Auf diese Weise kann auch weiter versioniert werden, wenn man gerade keine Verbindung zum Server hat. Außerdem bietet der dezentrale Ansatz eine erhöhte Ausfallsicherheit. Sollte das sogenannte Remote-Repository (besonderes Repository zur Synchronisation im Team) ausfallen, kann ein beliebiges lokales Repository als Backup dienen. Ein weiterer Vorteil ist die Performanz, da für keine Operation eine Server-Verbindung hergestellt werden muss (abgesehen von den Synchronisations-Operationen).

Git ist zudem sehr gut dokumentiert. Das frei verfügbare Buch Pro Git[37] wird direkt auf der Projekt-Seite zum Download angeboten.

Auch die Tool-Unterstützung ist relativ gut. Unter Windows hat sich besonders die Software Git Extensions[38] bewehrt. Eine Liste verfügbarer GUI-Clients für unterschiedliche Plattformen ist auf der Git-Seite zu finden[39].

Eclipse IDE

Eclipse ist mächtig und man lernst ständig neue Features oder Shortcuts, die einem das Leben beim Programmieren deutlich vereinfachen. Hier zunächst eine Auflistung sinnvoller Plugins, dann ein paar Worte zu Einstellungen, die am Anfang eines Projekts vor dem ersten Commit vollzogen werden sollten und dann eine Liste praktischer Shortcuts. Der Fachbereich Informatik bietet auf seinem YouTube-Channel eine Tutorial-Reihe an, welche den Einstieg und das effiziente Arbeiten mit Eclipse behandelt[40].

Plugins:

  • SVN-Plugin (s. obene)
  • Checkstyle[41]
  • FindBugs[42]
  • Texlipse[43]

Eclipse kennt zwei verschiedene Einstellungs-Scopes. Zum einen die "Globalen Einstellungen", die für die gesamte Eclipse-Installation gelten und zum anderen "Projektspezifische Einstellungen", die nur für ein Projekt gelten. Projektspezifische Einstellungen überschreiben möglicherweise bereits gesetzte globale Einstellungen. Außerdem werden diese in einer Datei ".project" gespeichert, die sinnvollerweise ebenfalls in die Versionsverwaltung wandern sollte. Auf diese Weise müssen projektspezifische Einstellungen nur einmal gesetzt werden und sind dann nach dem Einchecken auch für die restlichen Teammitglieder verfügbar.

Projektspezifische Einstellungen:

  • Text-Encoding auf UTF-8 setzen. Auf diese Weise gibt es keine Probleme, wenn aktuell im Team oder auch in zukünftigen Teams nicht nur auf Windows, sondern auch auf Mac OS X und Linux entwickelt wird.
  • Einrichtung geeigneter Task-Tags pro Entwickler.
  • Geeignete Einrichtung aller anderen Plugins, die im Projekt verwendet werden sollen (z.B. FindBugs und Checkstyle).

Globale Einstellungen:

  • Einrichtung des automatischen Formatters. Dabei sollte man im Team festlegen, ob die geschweiften Klammern bei Beginn eines Codeblocks an das Ende einer Zeile kommen oder in die nächste rutschen.
  • Aktivierung und Einrichtung von "Save-Actions". Dabei handelt es sich um Aktionen, die bei jedem Speichern der aktuellen Datei ausgeführt werden. Aktivierbar ist zum Beispiel die automatische Ausführung des Formatters oder auch die automatische Organisation der Imports. Es lohnt sich dort einen genaueren Blick drauf zu werfen.

Ticket-System

Ein Ticket-System dient zur zentralen Sammlung von auftretenden Bugs bei der Software-Entwicklung. Jeder Bug wird in einem eigenen Ticket erfasst, wobei der aufgetretene Fehler und dessen Reproduktion möglichst genau beschrieben wird. Dabei hat jedes Ticket einen sogenannten Life-Cycle, der den aktuellen Zustand eines Tickets beschreibt (z.B. "New", "Accepted", "Test", "Closed", "Dublicated"). Welche Zustände existieren hängt vom verwendeten Ticket-System und dem dazugehörigen Workflow ab. Oft lässt sich dieser Workflow für jedes Projekt individuell einstellen.

Die Verwendung eines Ticket-System hat sich in der Vergangenheit in Projekten im Fachbereich Informatik als sehr nützlich erwiesen. In großen Software-Projekten ist ein solches System eigentlich unumgänglich.

Hier einige bekannte und zudem freie Beispiele:

Das Rechenzentrum der Hochschule Trier bietet für studentische Projekte eine Trac-Instanz an. Diese kann beim Rechenzentrum beantragt werden. Assembla ist proprietär, bietet für offene Community-Projekte jedoch nahezu vollen Funktionsumfang. Neben einem äußerst guten Ticket-System bietet es dem Nutzer jedoch noch viel mehr, was für ein Projekt notwendig sein kann. Besonders wenn man agil entwickeln möchte, sollte man einen Blick darauf werfen.

Ausarbeitung und Präsentation

Bei den meisten Projekten wird es wohl so sein, dass der Hintergrund eine Abschluss- oder Projektarbeit ist, wozu laut Curriculum eine Ausarbeitung und eine Präsentation gehören. Die Bewertung dieser Leistungen fließen anteilig in die abschließende Note mit ein. Die Ausarbeitung ist das Ergebnisdokument und setzt sich unter anderem aus angepassten und zusammengefassten Versionen der Einzeldokumente der Projektphasen zusammen. Hier zahlt sich nun der zusätzliche Dokumentationsaufwand und die laufende Qualitätssicherung in den Phasen aus!

Der Fachbereich Informatik stellt im internen Bereich Dokumentations- und Präsentationsvorlagen in verschiedenen Formaten zur Verfügung[48], sodass der Einstieg aus technischer Sicht stark erleichtert ist. Außerdem wird in den Bachelor-Studiengängen ein Pflichtfach mit dem Namen "Wissenschaftliches Arbeiten"[49] angeboten, in dem sich unter anderem mit Themen wie Informationsrecherche, dem Verfassen wissenschaftlicher Berichte sowie das Gestalten von Präsentationen auseinander gesetzt wird. Dieses Fach sollte man gehört haben, bevor man mit einer Projekt- oder Abschlussarbeit beginnt.

Auch dieser letzte Teil muss von vorne herein im Projektplan zeitlich mit vorgesehen werden, denn oft ist damit mehr Arbeit verbunden als vielleicht zunächst angenommen. Es wäre schade, wenn ein großartiges Projekt am Ende aus dem Grund schlechter honoriert wird, weil zu wenig Zeit für das Abschlussdokument eingeplant wurde. Man sollte bedenken, dass dies das Dokument ist, was später der betreuende Dozent und insbesondere auch ein potentieller Zweitgutachter in den Händen hält. Aus diesem Grund sollte hier viel Wert auf Qualität gelegt werden. Korrekturlesungen und Reviews von Dritten sind hier ein Muss.

Downloads

Literatur

  • Peter Brössler, Johannes Siedersleben: Softwaretechnik. Praxiswissen für Software-Ingenieure Hanser-Verlag, München 2000, ISBN 3-446-21168-3
  • Walter Jakoby, Projektmanagement für Ingenieure Vieweg+Teubner Verlag, 2010, ISBN 3-834-80918-7

Einzelnachweise

  1. Hochschule Trier Modulhandbuch Bachelor-Studiengänge Informatik
  2. Hochschule Trier Modulhandbuch Master-Studiengänge Informatik
  3. Peter Brössler, Johannes Siedersleben: Softwaretechnik. Praxiswissen für Software-Ingenieure Hanser-Verlag, München 2000, S. 8-9
  4. r/ft: Projektgruppen-Daten
  5. Git: Ein Repository klonen
  6. Wikipedia: Software Requirements Specification
  7. Astah Community
  8. Wikipedia: Entity-Relationship-Modell
  9. Wikipedia: OR-Mapper
  10. Hibernate
  11. Wikipedia: Singleton (Entwurfsmuster)
  12. Wikipedia: Dependency Injection
  13. Google Code: Google Guice
  14. Wikipedia: Java Annotations
  15. Wikipedia: Factory Pattern
  16. Wikipedia: Model View Controller
  17. Wikipedia: Martin Fowler
  18. Wikipedia: JUnit
  19. Wikipedia: Äquivalenzklassentest
  20. Wikipedia: Grenzwertanalyse
  21. Unittest-Framework: JUnit
  22. Wikipedia: Liste von Unittest-Frameworks
  23. Quellcode-Überdeckungs-Framework: CodeCover
  24. Quellcode-Überdeckungs-Framework: Emma
  25. Quellcode-Überdeckungs-Framework: EclEmma
  26. Quellcode-Überdeckungs-Framework: Cobertura
  27. Google-Code: Gerrit
  28. Wikipedia: Apache Subversion
  29. Wikipedia: Git
  30. Wikipedia: LaTeX
  31. r/ft: Versionsverwaltung mit SVN
  32. Eclipse: Subversive - SVN Team Provider
  33. Eclipse: Subclipse
  34. Windows: Tortoise SVN
  35. Wikipedia: Vergleich von SVN-Clients
  36. Git
  37. Buch: Pro Git
  38. Google-Code: Git Extensions
  39. Git: GUI-Clients
  40. YouTube: Einführung in die Java-Programmierung mit Eclipse
  41. Eclipse: Checkstyle
  42. Eclipse: FindBugs
  43. Eclipse: Texlipse
  44. Ticket-System: Bugzilla
  45. Ticket-System: Mantis
  46. Ticket-System: Trac
  47. Projekt-Platform: Assembla
  48. FH-Trier, Fachbereich Informatik, interner Bereich (Anmeldung erforderlich): Dokumentations- und Präsentationsvorlagen
  49. FH-Trier, Fachbereich Informatik (B.Sc.), Modulhandbuch: Wissenschaftliches Arbeiten