GIT und warum SVN-Merges keine Merges sind

Seit zwei Wochen arbeiten wir im Projekt wirklich mit GIT. Bisher kannte ich es nur als Tool, um Open-Source-Projekte zu bekommen, oder für Spielzeug-Repositories auf der eigenen Platte. Die wirklichen Fragen kommen erst jetzt – im realen Leben. ‘Bekomme ich wirklich jedesmal alle Updates aller Branches aus dem Repository oder nur den HEAD?’ ‘Wie läuft denn das mergen, wenn ich gleichzeitig mehrer Branches bekomme?’ Ich merke bei meinen Fragen, dass ich noch in SVN denke.

GIT könne endlich Mergen, Branchen mache Spass, weil das Mergen kein Problem sei, habe ich im Vorfeld von den GIT-Befürwortern gehört und nie so richtig geglaubt. SVN kann doch auch mergen. Nachdem ich den ersten Konflikt hatte und die GIT-merge-Datei genauso aussah wie ich das von SVN gewohnt war (letztlich unix-merge), fühlte ich mich bestätigt.

Was ist eigentlich das Problem beim Mergen? In unseren Projekten passiert es öfter, dass es einen Branch gibt, der mehrere Wochen existiert. Sei es, dass hier der Umstieg auf eine neue Version der Software vorbereitet wird, sei es, dass hier Feature programmiert sind, die erst am Tag X in Erscheinung treten sollen, oder dass der Kunden im Live-Betrieb seine Infrastruktur noch erweitern muss. Diese Branches entwickeln sich parallel zum Trunk. Damit das Mergen nicht so kompliziert wird, werden alle paar Tage die Änderungen aus dem Trunk in den Branch gemergt. Und das kann SVN – irgendwie, oder eigentlich doch nicht. Es gibt zwar ein Kommando ‘svn merge’, doch das merged nur ein Changeset (die Differenz von zwei Versionen – bspw. Trunk zum Zeitpunkt 1 und zum Zeitpunkt 2) in den Branch. Ich sitze dann da mit all den Konflikten, die mir der Merge beschert hat und muss sie auflösen. Danach committe ich wieder und habe eine neue Version im Branch. Das SVN weiss nichts davon, das es sich bei diesem Comit um einen Merge von Version X und Version Y gehandelt hat. Svn hat die Version  geliefert und die Tools angestoßen, die dann den Merge durchführen, den ich selbst als unabhängigen Commit speichere. Wenn ich also den nächsten Merge aus dem Trunk in den Branch mache, muss ich wissen, was ich denn beim letzten Mal gemergt habe. Nur dann kann ich ein neues Changeset so definieren, dass ich alle neuen Änderungen bekomme. Ich kann mir helfen, indem ich in der Commit-Message speichere, was ich beim letzten Mal getan habe, aber das ist nur eine Krücke.

Ganz anders GIT. In GIT nur ein paar Entitäten. Es gibt Blobs, das sind die Inhalte der Dateien. Es gibt Baumobjekte, die die Dateien benennen und die aufeinander verweisen. Und es gibt Commits, die auf ein Baumobjekt und andere Commits verweisen. Branches sind nur PostIts an Commits. Jeder Branch ist also ein Commit mit einem anderen Commit als Vater. Mache ich einen Merge, ist das ein Commit mit zwei Müttern. Die Geschichte meiner Merges und Branches ist explizit im Versionskontrollsystem abgelegt. Ich habe nicht das oben beschriebene Problem. GIT weiss genau, was ich gemergt habe und was noch aussteht. Ich muss nicht durch Kommentare dafür sorgen, das meine Merges funktionieren. (Und natürlich: Beim Mergen auf Dateieben kann GIT auch nicht hexen.)

Was ist jetzt der Unterschied beim Mergen? Für GIT ist ein Merge ein essentielles Konzept, welches explizit modelliert ist. In svn gibt es den Merge nur auf der Ebene der Benutzungsschnittstelle. Die Kernkonzepte kennen ihn nicht. (svn 1.5 soll – Achtung: Hörensagen – den Merge explizit modellieren, allerdings nicht als Kernkonzept.)

Kanban versus Scrum

Im März waren Arthur und ich in Hamburg bei einer Veranstaltung des ObjektForum Nord zum Thema Lean Software Development. Referent war Stefan Roock. Der Vortrag bestand aus zwei Teilen. Im ersten referierte Stefan die Thesen der Poppendieks zum Thema Lean Software Development, wie sie auch in ihren Büchern veröffentlicht sind. Im zweiten Teil beschrieb er Kanban und Kanban-Boards wie sie im Moment im Scrum-Kontext diskutiert werden.

Durch den Vortrag habe ich zum ersten Mal verstanden, wie Scrum und Kanban in Toyotas Philosophie verwurzelt sind und doch so unterschiedlich sein können. Scrum hat seine Wurzeln im Toyota-Produkt-Entwicklungs-System. Die frühen Artikel zu Scrum beziehen sich immer auf einen Aufsatz aus der Harvard Business Review The New New Product Development Game. In diesem Aufsatz geht es um die Art wie neue Produkte entwickelt werden. Dabei spielt die japanische Automobilindustrie eine entscheidende Rolle. Einer der Grundgedanken des Artikels sind crossfunctional Teams.

Kanban dagegen ist das Herzstück des Toyota-Produktions-Systems. Kanban stellt die Logik der Prozessverkettung unterschiedlicher Stationen eines Produktionsprozesses dar. Die Stationen werden durch einen ‘ich sage dir was ich brauche’-Mechnismus (pull) verbunden. (Das Pushprinzip, zentrale Planung der Mengen, fordistisch/tayloristische Organisation, wäre ein anderes, genauer das entgegengesetze Prinzip.)

Während Scrum seine Anleihen bei der Entwicklung neuer Produkte macht, orientiert sich Kanban an der Herstellung von Produkten. Scrum steht für den kreativeren Prozess, der immer das ganze Team braucht, weil sich erst im Prozess zeigt, wann welche Fähigkeit benötigt wird. Kanban optimiert einen per Definition arbeitsteiligen Prozess. Die Reibungsverluste an den Übergängen werden durch Nachfragesteuerung optimiert. Das Was der Produktion steht im Kanban-Prozess nicht zur Disposition, nur das Wie seiner Herstellung.

Vielleicht könnte hier auch der unterschiedliche Fokus der Adaption beider Methoden in der Softwareentwicklung liegen. Scrum für die neuen Dinge, Kanban für die Wartungsprojekte.

Klassisches Testen von Software versus TDD

Im Januar hatte die Agile Grupppe Bremen  Andreas Spillner zu Gast. Andreas hat an der Hochschule Bremen eine Professur, sein Gebiet ist das klassische Testen von Software. Er stellte beim Treffen der Agilen Gruppe vor, was das sei: Testen von Software. Die Diskussion drehte sich um die Frage, ob denn TDD klassisches Testen ersetze oder wie das Verhältnis zu bestimmen sei.

Im April hatte ich das Glück von der GI-Regionalgruppe zu einem Vortrag eingeladen zu sein. Mein Thema war: ‘TestDrivenDevelopment – Letzte Fragen. Warum testgetriebene Softwareentwicklung nichts mit Testen zu tun hat und was sie denn dann ist.’ Wie der Titel unschwer verrät, habe ich versucht meinen Unmut mit der Diskussion im Januar auf den Begriff zu bringen und bin bei der These ‘TDD hat nichts mit Testen zu tun’ gelandet.

Der Kern meines Argumentes war, dass TDD eine Technik der Entwickung von Software ist, während klassisches Testen von Software eine Methode beschreibt, wie die Anforderungskonformität eines Programms  festgestellt wird. Beide Techniken besitzen so etwas wie eine Orthogonalität zueinander. Das was für die eine wichtig ist, ist für die andere nicht substantiell und umgekehrt.

Beispiel Testsuite: Für TDD ist es wesentlich, dass die Suite vor dem produktiven Code geschrieben wird. Für klassisches Testen kann man das machen (Test First), es spielt aber eigentlich keine Rolle. Die nackte Existenz der Suite ist im Feld des Softwaretestens die Essenz, was wiederum für TDD nicht die entscheidende Frage ist.

Ein anderes Beispiel ist die Frage ‘Wann ist man fertig’. Die Frage ist für klassisches Testen substantiell, im Kontext des TDD wird sie in der Regel lapidar gehandhabt: ‘Man ist fertig, wenn man fertig ist.’

Noch ein Beispiel: ‘Wer testet’ – für TDD ist substantiell, dass Entwicklung und Testen integriert sind, für klassisches Testen spielt das keine Rolle.

Diese Orthogonalität zieht sich wie einer roter Faden durch die gesamte Diskussion. Wenn sie ignoriert wird, wird die Debatte relativ unproduktiv. Klassische Tester halten TDD für eine amateurhafte Form des Testens. TDDler rümpfen die Nase ob der Neutralität gegenüber der Qualität des erzeugten Codes. Deshalb endete die Diskussion mit der These, dass klassisches Testen und TDD erst sinnvoll ins Zusammenspiel gebracht werden können, wenn ihr grundsätzlicher Unterschied verstanden ist.