Das Konfigurationsmanagement definiert und unterhält Regeln für das reproduzierbare Erstellen und Pflegen von Produkten, die aus Projekteinheiten mit spezifischem Lebenszyklen und Abhängigkeiten aufgebaut sind.
Das Buildmanagement definiert und unterhält einen Prozess, der nach den Vorgaben des Konfigurationsmanagements aus den Arbeitsständen verschiedener Projekte ein Produkt zusammenbaut. 'Projekt' ist hier ein weit gefasster Begriff. Ein Projekt kann beispielsweise die Arbeit der Anforderungsanalyse sein. Im engeren Sinne ist damit natürlich ein Entwicklungsprojekt gemeint, in dem eine Softwarekomponente entsteht. Wesentlich ist, dass Projekte zueinander Abhängigkeiten besitzen, die verwaltet werden müssen und die sich im Laufe der Zeit verändern werden. Im Rahmen des Buildmanagements wird ein Buildprozess erarbeitet, der die Arbeitsabläufe bei des Buildmanagements definiert.
Ein Beispiel: Für ein Software-Projekt im Rahmen einer Mehrschichtarchitektur werden im Laufe des Projekts iterativ Anforderungen entwickelt. Das Projekt nutzt third party Software. Das Projekt wird kontinuierlich von Fachtests begeleitet. Das so skizzierte Produkt setzt sich dann grob aus folgenden Projekteinheiten zusammen:
Anforderungen 3rd party
^ ^ ^
| | |
| +-- Servercode --+ <----+
| ^ |
| | |
+----- Clientcode <-- Testergebnisse
Server und Client sind in weitere Projekteinheiten nach den Vorgaben der Softwarearchitektur unterteilt. Das Konfigurationsmangement muss nun einen Prozess bereitstellen, der das so skizzierte Produkt erstellt. Noch einmal sei betont: der Stand der Anforderungen und die Testergebnisse sind vielleicht nicht öffentlich aber dennoch Produktbestandteil.
Bevor es losgeht soll noch die Terminologie dieses Artikels festgelegt werden:
- Ein Produkt ist eine lauffähige Kombination von Systemkomponenten zur Erfüllung eines bestimmten Zwecks der im Releasplan festgehalten wird. Produkte werden ausgeliefert, sie verlassen die Umgebung des Entwicklungsprojekts und werden, zumindest teilweise, öffentlich gemacht.
- Ein Projekt ist hier die Bezeichnung für eine Komponente des Produks, die im Konfigurationsmanagment als eine Entwicklungseinheit betrachtet wird. Aus Sicht des Konfigurationsmanagements ist ein Produkt also nicht in weitere Subkomponenten unterteilt.
- Einen reproduzierbaren Produktstand auf der Basis stabiler, gekennzeichneter Projektstände heißt Produktrelease. Eine Sonderstellung nimmt das Produktrelease auf der Basis der Arbeitsstand-Revisionen in der Versionierung ein: es wird nicht veröffentlicht sondern dient ausschließlich der Weiterentwicklung.
- Ein besonders gekennzeichneter, physikalischer oder logischer Stand eines Projekts wird als Tag oder Label bezeichnet. Hier wird synonym der Begriff Revision aus der Subversion-Terminologie verwendet.
- Eine physikalische oder logische Kopie eines Projekts zum Zwecke der Weiterentwicklung und Wartung heißt Projektbranch. Produktversionen werden auf der Grundlage von Projektbanches bereitgestellt. Gewöhnlich muss für jedes ausgelieferte Produktrelease ein Branch eingeplant werden. Ebenso wird ein Branch normalerweise regelmäßig in sein Original gemerged. Verpasst man das, so wird man die parallel Pflege mehrerer Produktversionen verantworten müssen.
Drei grundlegende Aufgaben müssen vom Konfigurationsmanagement gelöst werden:
- Die Versionierung der Quellen. Diese Aufgabe wird meist an ein Versionswerkzeug wie Subversion, CVS oder GIT übertragen und kann damit als erledigt angesehen werden.
- Die Verwaltung von Projektständen und Generierung eines Produktreleases aus diesen Projektenständen.
- Planung, Erstellung und Verwaltung von Produktbranches. Solche Branches kommen immer dann ins Spiel, wenn an einem veröffentlichten Produkt Wartungen und Erweiterungen vorgenommen werden müssen. Solche Veröffentlichungen sind in erster Linie Produktions- oder Kundenreleases - es wäre unzumutbar und oft auch vertragswidrig, dem Kunden jedesmal einen 'Arbeitsstand' mit all seinen Fehlern und Unzulänglichkeiten zu präsentieren. Aber auch das firmeneigene Testteam-Release oder das Release für die nächste Präsentation vor dem Projekt-Lenkungsgremium muss auf der Basis der ausgelieferten Stände gewartet werden. Das Konfigurationsmanagement plant deshalb für jedes veröffentlichte Release einen Branch ein.
Das Buildmanagement als eine Exekutive des Konfigurationsmanagements, plant und definiert einen Buildprozess mit folgenden Eigenschaften:
- die Vorgaben des Konfigurationsmanagements müssen realisiert werden - das sind die drei eben genannten Punkte
- er unterstützt die Verteilung eines Produkts auf verschiedene Projekte mit jeweils eigenen Lebenszyklen und die damit ins Spiel kommenden Abhängigkeiten
- er ist weitestgehend automatisiert
Folgende Eigenschaften des Buildprozesses sind dabei wünschenswert:
- er ist entweder unabhängig von der oder intergriert in der Entwicklungsumgebung des Projekts
- er beeinflusst die laufende Entwicklung so wenig wie möglich
- er vermeidet Redundanzen und ist dadurch einfach wartbar
Das allgemeine Vorgehen zur Erstellung eines Produktreleases kann man sich in etwa so vorstellen. Die laufende Entwicklung macht von ihren
Projekten Momentaufnahmen wenn sie den Eindruck hat, dass eine solche Momentaufnahme einen gewissen stabilen Stand besitzt. Eine solche Momentaufnahme wird üblicherweise tag oder label genannt. Davon abhängige Projekte entwickeln gegen solche Stände. Irgendwann lässt sich ein Produkt komplett aus getaggedten Ständen definieren. Mindestens gilt dann das Produkt lässt sich i) compilieren und ii) erfolgreich Unit-testen. Darüber hinaus bescheinigen die Entwickler nach ihren Maßstäben den getaggedten Ständen ein Mindestmaß an Qualität und Funktionalität und das Produkt hat grundlegende Integrationstests bestanden.
Das so gelieferte Produkt wird nun funktional getestet. Besteht es diese Tests dann ist das Produktrelease fertig und kann geliefert werden. Im allgemeinen wird das nicht der Fall sein und Fehler werden aufgedeckt. Jetzt muss eine Entscheidung gefällt werden, zur Auswahl stehen zwei Alternativen:
- Das gesamte Produktrelease wird verworfen und das Spiel beginnt von vorne. So einfach dieses Vorgehen ist, in großen Projekten läuft man Gefahr, dass dieser Zyklus nicht fristgerecht endet.
- Man fixed jene Projekte, die als Fehlerquelle identifiziert werden konnten und fertigt neue Momentaufnahmen, die in das ursprüngliche Release integiert werden. Die Chancen dass das Release auch einmal fertig wird steigen. Der Nachteil dieses Vorgehens: es können Projektbranches ins Spiel kommen da die Entwickler parallel zu den Testaktivitäten weiterentwickeln.
Ein Beispiel soll das illustrieren. Das Produkt besteht aus drei Projekten P1, P2 und P3 (P1 hängt von P2 und P2 von P3 ab) in den Entwicklungsständen 2, 1 und 1. Auf dieser Basis wird ein Release erstellt und an das Testteam ausgeliefert:
geliefertes Release: 2,1,1
P1 -- 1 -- 2
P2 -- 1
P3 -- 1
Nach einer Woche hat das Testteam seine Tests abgeschlossen und in P1 konnte ein Fehler lokalisiert werden. Die Projektstände sind inzwischen fortgeschritten, P2 ist nun im Stand 2 und P1 im Stand 3:
Entwicklungsstand: 3,2,1
P1 -- 1 -- 2 -- 3
P2 -- 1 -- 2
P3 -- 1
Zur Behebung des Fehlers in P1 kann man nun P1 aus dem Stand 3 weiterentwickeln zu Stand 4.
geliefertes Release: 4,2,1
P1 -- 1 -- 2 -- 3 -- 4
P2 -- 1 -- 2
P3 -- 1
Das neue Produktrelease würde nun aber nicht mehr das schon getestete P2 im Stand 1 enthalten und neue Fehlerquellen entstehen die wieder gestestet werden müssen. Deshalb ist es vielleicht sinnvoller, von P1 einen Branch zu erstellen:
geliefertes Release: 2.1,1,1
+-- 2.1
P1 -- 1 -- 2 -- 3
P2 -- 1 -- 2
P3 -- 1
In diesem Release ist nur ein Projekt geändert worden, es ist also potenziell stabiler.
Spätestens hier werden Sie einwenden: alles schon fertig, es gibt Maven! Und Sie haben Recht - Maven ist ein Buildsystem (also ein Werkzeug für einen festen Buildprozess) das allen aufgezählten Ansprüchen gerecht wird:
- es compiliert, verpackt und Unit-tested Projekte
- Abhängigkeiten werden per Deklaration verwaltet
- der Build- und Releaseprozess ist fest vorgegeben und sauber
- die Integration mit gängigen Versionsverwaltungssystemen und Entwicklungsumgebungen ist ausgereift
- die Architektur von Maven ist auf Erweiterbarkeit ausgelegt und es gibt jede Menge Unterstützung durch eine weltweite Entwicklergemeinde
Es gibt auch Nachteile, sie sind gegen die Vorteile von Maven sorgsam abzuwägen:
- die Dokumentation der vielen, oft unverzichtbaren Maven-Plugins ist unzureichend
- Maven stellt gewisse Anforderungen an seine Infrastruktur (Internetzugang für das Remote Repository, SCP/SSH für zentrale Repositorys), die nicht bei allen Kunden einfach zu erfüllen sind
- Maven erscheint Unerfahrenen umständlich und schwer zu beherrschen, die Akzeptanz kann darunter leiden und mit ihr die Projektkultur
- mindestens ein Maven-Guru ist im Projekt erforderlich, alles andere ist ein unkalkulierbares Risiko
- die Arbeit mit Artefakten von Remote Repositorys ist gegen die IT Policy vieler Kunden - diese wollen den Einsatz von Software individuell geprüft sehen
- der Einsatz von Maven ist ein 'alles-oder-nichts' Ansatz, die Philosophie von Maven in bestehende (legacy!) Buildprozesse des Kunden Schritt für Schritt zu integrieren schlicht unmöglich
Ich empfehle ohne Einschränkung den Einsatz von Maven:
- auf der 'grünen Wiese': es existiert kein anderer Buildprozess der zu integrieren wäre
- wenn man sauberes Konfigurationsmanagement lernen möchte: die Konzepte von Maven sind korrekt und zeitlos
Dieser Artikel erläutert einen Buildprozess, der bei einem Kunden entwickelt wurde, bei dem aus genannten Gründen der Einsatz von Maven nicht in Frage kam. Die Umsetzung erfolgte mit Ant als Buildwerkzeug, Eclipse als IDE und Subversion als Versionierungswerkzeug. Von Anfang an war dabei unser Ziel, einen möglichst leichtgewichtigen Buildprozess zu entwickeln. Um Sie neugierig zu machen, antizipiere ich die wichtigsten Ergebnisse:
- Der Buildprozess stellt keinerlei Voraussetzungen an seine Projekte - mit anderen Worten gibt es in den Projekten keine Ant-Targets, die den Buildprozess repräsentieren. Das heißt, die Entwickler können nach Belieben mit Ant in den jeweiligen Projekten arbeiten, ohne den Buildprozess zu beeinflussen.
- Der Buildprozess unterstützt lediglich i) das Erstellen von Momentaufnahmen eines Produkts, ii) das Konsolidieren einer solchen Momentaufnahme und iii) das Anlegen von Produktbranches. Nicht mehr, aber auch nicht weniger.
- Der Buildprozess verzichtet auf die Anlage von 'tags' oder 'labels' im Sinne einer Kopie im Repository. Projektbranches werden gleichberechtigt zu den 'Hauptzweig' Projekten in der Wurzel des Repositorys angelegt. Das heißt im Repository wird auf eine Struktur mit 'tag'- und 'branch'-Verzeichnissen komplett verzichtet, da wir nicht die Semantik des Buildprozesses im Repository abgebildet sehen wollten.
- Auf die Ablage von Projektreleases (sprich: JAR Dateien) in lokale Verzeichnisse ist komplett verzichtet worden.
- Für Produktbranches werden nur für die fehlerhaften Projekte Branches angelegt. Ein Produktbranch versucht also möglichst auf den 'Hauptzweig' Projekten zu bleiben.
Im zweiten Abschnitt gehe ich auf die Werkzeuge Ant, Subversion und Eclipse näher ein, um dann im dritten Abschnitt den Buildprozess konkret zu erläutern.