El-Oh-De revisited

Einmal im halben Jahr komme ich an Dan Mangles’ Blogeintrag über Missverständniss des Gesetz von Demeter vorbei. Und meistens – das scheint eine Eigenart von mir zu sein – lese ich ihn nochmal. So auch vor ein paar Tagen. Und auch dieses Mal habe ich das Gefühl ihn bisher noch nicht richtig gelesen zu haben.

Der Inhalt ist eine nette kleine Geschichte – weniger: ein Geschichtsfragment -, das von einem Kunden, einem Zeitungsjungen und einer Brieftasche handelt. Zunächst wird die Geschichte in Form der naivsten Implementierung (die Geschichte ist eigentlich nur Ruby-Code) erzählt. Der Zeitungsjunge bekommt die Brieftasche des Kunden und nimmt sich selbst das Geld für die Zeitung. Da niemand freiwillig dem Zeitungsjungen seine Brieftasche gibt, wird das Gesetz von Demeter (‘Sprich nicht mit Fremden’) (oder technisch: ‘keine Aufrufe mit mehr als einem Punkt’) eingeführt und die Geschichte wird noch einmal erzählt, jetzt wird die Brieftasche aber nicht aus der Hand gegeben.

Dan Mangles untersucht die Richtung der Delegation der Aufrufe – und das ist mir erst dieses Mal so richtig aufgefallen. Bei der Datendelegation ist die Richtung genau umgekehrt zur Verhaltensdelegation. Datendelegation: Der Zeitungsjunge bekommt den Kunden und nimmt sich vom Kunden die Brieftasche. Der Zeitungsjunge hat also die Brieftasche in der Hand. Bei der Verhaltensdelegations sagt der Zeitungsjunge dem Kunden ‘bezahl’ und der Kunde sagt der Brieftasche ‘Geld her’. Es ist nicht das Datum (Brieftasche) was nach außen, sondern das Verhalten (‘Bezahl’) was als Aufforderung nach innen wandert.

Diese Unterscheidung ist so interessant, weil sie davor schützt LOD-Verletzungen einfach durch Datendelegation zu lösen. Wenn der Kunde auf einmal eine Geldmenge hätte, er also seine Innereien ausstellen würde, wäre dem Gesetz der ‘Zwei-Punkte-Vermeidung’ genüge getan, aber substantiell hätte sich nichts geändert. Also: Richtungsumkehr und Verhaltensdelegation.

Dan Mangles kluge Gedanken gehen noch weiter. Er bringt ein Beispiel aus einem View. Dort wird eine Bestellung dargestellt. Diese Bestellung hat einen Kunden, der Kunde hat einen Namen. Das bedeutet wir haben im View eine Stelle mit zwei Punkten: bestellung.kunde.name. Die Verletzung lässt sich in der bekannten Art auflösen. Die Bestellung bekommt neben dem Kunden eine Methode kunde_name. Das ist fachlich unsinnig, eine Bestellung sollte keinen Kundennamen haben. Dan Mangles fragt sich, was das für das Gesetz von Demeter bedeutet. Er kommt zu dem Schluss, das ein View kein Geschäftsobjekt sei und deshalb sei für die Darstellung eine Verletzung des Gesetzes von Demeter erlaubt, besser: er sagt das Gesetz von Demeter beziehe sich eigentlich nur auf das Verhältnis von Geschäftsobjekten.

Und das habe ich erst beim zweiten oder dritten Besuch verstanden. Was wohl beim nächsten Besuch auf mich wartet?

GIT oder die Suche nach der richtigen Abstraktion

Ich glaube von Marshall McLuhan stammt der Gedanke, dass neue Medien immer in Gestalt der alten die Welt erblicken. Sie finden ihre eigene Form erst im Laufe ihrer Entfaltung. Der Gedanke ist wahrscheinlich eine spezifische Fassung eines Allgemeineren. Das Neue tritt prinzipiell immer zuerst in Gestalt des Alten auf und wird auch in seinen Kategorien gedacht. So war das Auto zunächst eine Kutsche ohne Pferde und das Internet war ein Sammelsurium von Texten.

Das Gleiche scheint mir auch für die Geschichte der Versionskontrollsysteme zu gelten. Von Generation zu Generation ändern sich ihre Kernkonzepte, die Konzepte mit denen der Begriff Versionskontrolle gedacht wird.

Die ersten Versionskontrollsysteme systematisierten nur das, was vorher in Form von manueller Versionskontrolle vollzogen wurde. Versionskontrolle ohne System bestand im Kopieren und Umbennen von Dateien. Neben httpd.conf lag httpd.conf.old und vielleicht noch httpd.conf.backup. Die ersten Systeme wie RCS pakten diese Infos – Version 1, 1.1, 1.2 – einfach in eine eigene Datei. Der Wildwuchs war gebannt.

Die zweite Generation der Systeme löste das Problem, dass jetzt mehrere Leute in einem Projekt miteinander arbeiten wollten. Es gab einen Server, der ein Repository verwaltete, und Cientsoftware, die mit diesem Server kommunizierte. Ganze Verzeichnisbäume konnten  ausgecheckt werden, die Versionierung auf dem Server folgte allerdings weiterhin den Gesetzen des RCS: Pro Datei eine Datei mit allen Versionen. (Ich glaube die erste Version des CVS bestand nur aus Shellskripten, die RCS benutzten.)

Die dritte Generation (eher die zweieinhalbte) trat unter dem Motto an, das gleiche zu tun wie CVS, aber jetzt alles richtig zu machen: SVN. Die Daten wurden jetzt serverseitig in einer Datenbank gespeichert. SVN erhielt die Historie eine Datei auch bei einer Umbenennung. SVN kannte das Konzept der Transaktion beim Commit: Entweder gelangen alle Dateien in der neuen Fassung in das Versionskontrollsystem oder keine.

Die vierte oder dritte Generation der Versionskontrollsysteme – GIT – kennt nun verteilte Repositories. Es gibt nur Repositories, die miteinander sprechen, es gibt kein Zentrum mehr, keinen zentralen Server um den sich alles dreht. Die Commits im System existieren nicht mehr implizit wie bei SVN, sondern explizit in einem Baum. GIT folgt nicht mehr der Commit-Semantik einer Datenbank, die nach einem Commit die Transaktion vergessen darf, sondern es baut eine Historie auf, in der jeder Commit ein Knoten bleibt und der Weg zu den Dateien nur über die Commits im Baum funktioniert. In SVN wird die Version eines Verzeichnisbaumes erschlossen. Es ist die höchste Version einer seiner Dateien, in GIT ist die Verbindung von Commit (Version) und Dateibaum als Graph modelliert.

Zurück zum Anfang. Welches ist die alte Form in der sich zunächst das Neue zeigt? Und was ist der neue Begriff, der immer stärker wird, bis er in Form von GIT/Mercurial/bazaar seine aktuelle Form findet? Zwei Konzepte werden in der Geschichte immer schwächer. Die Datei verliert immer mehr an Bedeutung. Im RCS war sie das einzige Konzept, das es gab, im GIT ist sie nur noch über einen Baum erreichbar und in zwei Knoten (Beschreibung/Attribute und Inhalt) zerfallen. Die ersten Systeme – bis zum SVN – speicherten und kommunizierten an Stelle der Dateien nur mit Diffs, um Netzwerklast und Platz zu minimieren, in GIT spielt das – im Prinzip – keine Rolle mehr, die Datei ist komprimiert als ganze in jeder Version abgelegt.

Das zweite Konzept das verschwindet ist das technisch festgelegte Zentrum. Im CVS war es ganz klar, was der Hauptpfad der Entwicklung war und was ein Nebenpfad. Im SVN gab es – technisch – zwischen beiden keinen Unterschied mehr, der Unterschied wurde durch die Konvention gemacht. Das eine wurde Trunk genannt, die anderen wurden unter der Überschrift branch einzeln abgespeichert. In SVN gab es immer noch den Unterschied von zentralem Repository und lokalen – ja was eigentlich? – Auscheckungen. In GIT ist auch die Differenz von Peripherie und Zentrum beseitigt. Es gibt – technisch – nur gleichtberechtigte Repositories. Unterschiede werden hier über die Konvention gemacht.

Welche Abstraktion ist in der Geschichte der Versionskontrolle stärker geworden? Ein Commit, eine Version ist immer expliziter und deutlicher formuliert worden. Für RCS gab es verschiedene Versionen einer Datei – und das lokal. Das Problem das GIT-Commits lösen bestand noch gar nicht. Keine Bäume, keine verschiedenen Benutzer, keine Merges. Im CVS wurde der Commit auf der Datei-Ebene abgebildet. Der Commt über einem Verzeichnisbaum konnte bei ein paar Dateien funktionieren, bei anderen scheitern, und der Benutzer hatte das Problem, dass er die verschiedenen Stände wieder zusammensetzen musste. (Ignoriert habe ich in meiner kleinen Geschichte hier den Unterschied von pessimistischem – SCCS – und optimistischem Locking – CVS). SVN gibt dem Commit eine Semantik wie eine Datenbanktransaktion. Entweder er klappt als Ganzer oder nicht. Wenn er klappt ist er verschwunden und nur noch aus der Historie der Dateien – der Version – zu rekonstruieren. In GIT wird der Commit zu einem expliziten Konzept. Nun ist es auch möglich einen Merge zu modellieren: ein Commit mit zwei Commits als Eltern.

Ergo: Datei und Zentralismus werden immer schwächer, Baum und Historie (explizit als Baum – Graph der Commits) wird immer stärker. Ob das schon das Ende der Entwicklung ist werden wir sehen.

Fussnote: Subversion 1.5 hat das Merge-Tracking eingeführt, 1.6 hat es verbessert. Das ist sicher hilfreich für viele SVN-Projekte und adressiert ein zentrales Problem von SVN, aber ich glaube die konzeptuelle Schwäche im Kern des Systems wird das nicht ausgleichen. SVNs Tage sind gezählt, wenngleich wir auch wissen, wie lange Systeme leben können, die im Interface Schwächen ausgleichen, die sie im Kern enthalten.