2002-Nov-11 Das Gesetz von den leckenden Abstraktionen

From The Joel on Software Translation Project

Jump to: navigation, search

Joel on Software - The Law of Leaky Abstractions
Deutsche Übersetzung

Das Original
http://www.joelonsoftware.com/articles/LeakyAbstractions.html
Joel Spolsky, 11. November 2002
Diese Übersetzung
http://www.bitloeffel.de/DOC/joelonsoftware/LeakyAbstractions_de.html
Hans-Werner.Heinzen, Dezember 2006

Das Gesetz von den leckenden Abstraktionen

Ein Zauber waltet tief im Inneren des Internets, auf das wir tagtäglich angewiesen sind, und zwar im TCP-Protokoll, einem seiner Fundamente.

TCP ist eine Methode, Daten auf zuverlässige Weise zu übermitteln. Soll heißen: Wenn du eine Nachricht mit TCP übers Netz verschickst, dann wird sie ankommen und weder fehlerhaft noch verstümmelt sein.

Wir benutzen TCP für vielerlei, fürs Laden von Internet-Seiten genauso wie zum Versand von Elektropost. Die Verlässlichkeit von TCP stellt sicher, dass uns jede aufregende Nachricht finanzjonglierender Ostafrikaner auch buchstabengetreu erreicht. Wie schön!

Eine andere Methode, Daten zu übermitteln, heißt IP und ist vergleichsweise unzuverlässig. Niemand garantiert, dass Daten ankommen, und es kann sein, dass Daten unterwegs übel zugerichtet werden. Angenommen, du schickst ein ganzes Bündel von Nachrichten per IP, dann wundere dich nicht, wenn nur die Hälfte davon ankommt, wobei einige davon in anderer Reihenfolge ankommen, als sie abgeschickt worden sind, andere wiederum durch irgendwelche fremden Nachrichten ersetzt wurden, vielleicht durch durch Fotos von liebenswerten Orangutan-Babys, wahrscheinlicher aber durch einen Haufen unleserlichen Schrott, der aussieht, wie die Betreffzeilen von Spam-Post aus Taiwan.

Hier nun kommt der Zaubertrick: TCP setzt auf IP auf. Anders gesagt, TCP verpflichtet sich sozusagen, zuverlässig Daten zu verschicken, indem es ein unzuverlässiges Werkzeug benutzt.

Ein Szenario aus der wirklichen Welt soll den Zauber illustieren; wenn auch ziemlich absurd, so doch zweifellos vergleichbar:

Stell dir vor, wir hätten ein Verfahren, Schauspieler vom Broadway nach Hollywood zu verfrachten, indem wir sie in Autos setzen und quer durchs Land fahren. Einige Autos würden verunglücken, dabei würden Schauspieler sterben. Einige Schauspieler würden sich unterwegs besaufen, sich den Kopf scheren oder sich die Nase tätowieren lassen, so dass sie zu hässlich für die Arbeit in Hollywood würden, und sehr oft würden sie in anderer Reihenfolge ankommen als losgeschickt, weil sie verschiedene Wege gewählt hätten. Nun stell dir vor, ein neuartiger Service für die Lieferung von Schauspielern namens "Hollywood Express" würde garantieren, dass (a) die Schauspieler ankommen, (b) in der bestellten Reihenfolge und (c) in einwandfreiem Zustand. Das Magische daran ist, dass "Hollywood Express" auch keine andere Möglichkeit hat, als die Schauspieler in Autos zu setzen und sie quer durchs Land zu fahren. "Hollywood Express" erreicht sein Ziel, indem es für jeden Schauspieler und jede Schauspielerin überprüft, ob er oder sie in einwandfreiem Zustand angekommen ist, und, wenn nicht, beim Versandbüro einen identischen Zwilling als Ersatz nachbestellt. Wenn die Schauspieler in falscher Reihenfolge ankommen, arrangiert "Hollywood Express" sie neu. Wenn eine Ufo auf dem Weg zum Sektor 51 in Nevada bruchlandet und dort den Highway unpassierbar macht, werden alle Schauspieler, die dort fahren wollten, über Arizona umgeleitet. Und "Hollywood Express" müsste das den Filmdirektoren in Hollywood noch nicht einmal mitteilen. Für die würde es nur so aussehen, als würden die Schauspieler etwas langsamer ankommen. Und nicht mal von dem Ufo-Crash würden die was mitkriegen.

Ähnlich ist es mit dem Zauber des TCP. Er ist das, was Informatiker gerne Abstraktion nennen: eine Vereinfachung von etwas, das unter der Oberfläche viel komplizierter ist. Wie es sich herausgestellt hat, besteht ein Großteil der Computerprogrammierung daraus, Abstraktionen zu bilden. Was ist eine String-Bibliothek ? Sie ist eine Methode vorzutäuschen, das der Computer Zeichenketten genauso leicht manipulieren kann wie Zahlen. Was ist ein Dateisystem ? Ein Dateisystem ist eine Methode so zu tun, als wäre eine Festplatte kein Stapel rotierender, magnetisierbarer Scheiben, der an bestimmeten Positionen Bits speichern kann, sondern vielmehr eine Hierarchie von Ordnern innerhalb von Ordnern, die einzelne Dateien enthalten, die wiederum jeweils aus einer oder mehreren Ketten von Bytes bestehen.

Zurück zum TCP. Weiter oben habe ich der Einfachheit halber ein wenig geschwindelt. Einigen von euch kommt schon Dampf aus den Ohren, weil euch dieser Schwindel aufregt. Ich sagte, TCP garantiere die Ankunft der übermittelten Nachricht. Das tut es natürlich nicht. Angenommen, dein Lieblingsmarder hat sich durch das Netzwerkkabel durchgekaut, IP-Pakete passen nicht mehr durch, TCP kann daran nichts ändern, und die Nachricht kommt nicht an. Oder, wenn du unfreundlich warst zu den Systemverwaltern deiner Firma, und sie strafen dich dadurch, dass sie dich an einen überlasteten Verteilerknoten anschließen, dann wird nur ein Teil deiner IP-Pakete durchkommen. TCP wird zwar funktionieren, aber nur gaaanz langsaaam.

So etwas nenne ich eine leckende Abstraktion. TCP versucht eine vollständige Abstraktion des darunterliegenden unzuverlässigen Netzwerks zu sein, aber machmal tropft etwas Netzwerk durch die Abstraktion durch, denn sie kann dich nicht zuverlässig davor schützen. Das ist nur ein Beispiel dafür, was ich "Gesetz von den leckenden Abstraktionen" getauft habe:

Alle nicht-trivialen Abstraktionen lecken (mehr oder weniger).

Abstraktionen versagen. Manchmal wenig, ein andermal viel. Hier sind undichte Stellen, dort geht was schief. Und es passiert überall, sobald nur Abstraktionen ins Spiel kommen. Hier einige Beispiele:

  • Etwas so Einfaches, wie das Iterieren über eine große zweidimensionale Tabelle, kann extrem unterschiedlich schnell ablaufen, je nachdem, ob du zuerst vertikal oder zuerst horizontal iterierst. Es hängt von der "Maserung" ab. Die eine Reihenfolgen kann enorm viel mehr Paging nötig machen als die andere, und Paging ist langsam. Sogar Assembler-Programmierern erlaubt man, so zu tun, als ob es einen großen, flachen Adressraum gäbe. Virtuelle Speicherung aber bedeutet, dass das nur eine Abstraktion ist, eine, die leckt, sobald Paging nötig wird und bestimmte Speicherzugriffe dadurch sehr viel mehr Nanosekunden brauchen als andere.
  • Die Abfragesprache SQL soll die Prozedurschritte, die nötig sind, eine Datenbank abzufragen, wegabstrahieren. Sie soll dir stattdessen erlauben, nur definieren zu müssen, was du haben willst, und die Datenbank muss die Prozedurschritte, die dafür nötig sind, selbst herausfinden. Es kommt aber vor, dass bestimmte SQL-Abfragen tausendmal langsamer als andere, logisch gleichwertige Abfragen. Ein bekanntes Beispiel dafür ist, dass manche SQL-Server dramatisch schneller arbeiten, wenn man "where a=b and b=c and a=c" spezifiziert anstatt nur "where a=b and b=c", obwohl natürlich das Ergebnis dasselbe ist. Eigentlich wird von dir nicht erwartet, dass du dir um die technische Auflösung Gedanken machen musst, sondern nur um den logischen Entwurf. Aber machmal leckt die Abstraktion und verursacht erschreckende Laufzeiten, und du musst dann das Ablaufanalyse-Programm anwerfen und untersuchen, was falsch läuft, um herauszufinden, wie du die Abfrage schneller machen kannst.
  • Auch wenn Netzwerkbibliotheken wie NFS oder SMB erlauben, dass du Dateien auf entfernten Rechnern behandelst, als ob sie lokal seien, wird die Verbindung hin und wieder sehr langsam oder sogar unterbrochen, wodurch sich die Datei nicht mehr wie eine lokale verhält. Als Programmierer musst du Kode schreiben, der damit umgehen kann. Die Abstraktion "eine entfernte Datei ist dasselbe wie eine lokale" leckt. Hier ein Beispiel aus der Praxis für UNIX-Systemverwalter. Wenn du die Home-Verzeichnisse der Benutzer auf ein über NFS eingehängtes Laufwerk legst (die erste Abstraktion) und deine Benutzer für ihre Elektropost ".forward-Dateien" woandershin anlegen (die nächste Abstraktion) und dann der NFS-Server abstürzt während gerade Post ankommt, dann werden die Nachrichten nicht weitergeleitet, weil die ".forward-Datei" nicht gefunden wird. Das Loch in der Abstraktion führt also dazu, dass Post verloren geht.
  • String-Klassen in C++ lassen dich so tun, als ob Zeichenketten Daten erster Güte seien. Sie versuchen die Tatsache wegzuabstrahieren, dass Zeichenketten harte Nüsse sind; sie lassen dich so tun, als seien sie simpel wie Zahlen. Aber weißt du was ? Egal wie sehr du dich anstrengst, keine String-Klasse der Welt lässt dir "fuss" + "ball" durchgehen, weil String-Literale in C++ immer char* sind und niemals string. In der Abstraktion klafft ein Loch, so groß, dass du es mit der Sprache nicht stopfen kannst. (Es wäre amüsant, die Entwicklungsgeschichte von C++ zu lesen als den immer wieder erneuerten Versuch, dieses Leck in der Abstraktion von Zeichenketten abzudichten. Warum man nicht einfach einen Basistyp string einführen konnte, will mir gerade nicht einfallen.)
  • Wenn es regnet, musst du langsamer fahren, selbst wenn dein Auto Scheibenwischer, Scheinwerfer, Dach und Heizung besitzt, alles, was dir die Sorge ums Regenwetter nehmen soll (sie abstrahieren das Wetter weg). Aber halt, du musst dich um Aquaplaning sorgen, und manchmal ist der Regen so stark, dass du nicht weit sehen kannst und langsamer fahren musst. Das Wetter kann man nicht komplett wegabstrahieren wegen des "Gesetzes von den leckenden Abstraktionen".

Das "Gesetz von den leckenden Abstraktionen" ist deshalb so problematisch, weil Abstraktionen unser Leben nicht so sehr vereinfachen, wie sie vorgeben. Hätte ich C++-Programmierer auszubilden, wäre es doch nett, auf char* und Zeigerarithmetik verzichten zu können und gleich zu den STL-Strings überzugehen. Aber irgendwann würden meine Schüler "fuss" + "ball" schreiben, mit seltsamen Folgen, und so müsste ich zurück und ihnen doch noch alles über char* erzählen. Oder, eines Tages versuchen sie eine Funktion der Windows-API rufen, bei der die Dokumentation sagt, sie habe OUT LPTSTR als Argument ... und sie können das nicht verstehen, bevor ich ihnen alles erzählt habe über char* und Zeiger und Unicode und wchar_t und über TCHAR-Header-Dateien, über all diese Sachen halt, die aus dem Leck herausquellen.

Wenn ich COM-Programmierung unterrichtete, wäre es schön, ich müsste nur zeigen, wie die Visual-Studio-Assistenten mit all ihren kodeerzeugenden Funktionen zu benutzen sind, nur, wenn dann etwas schief ginge, hätte niemand einen Schimmer, was passiert sein könnte, wie zu debuggen oder was sonst zu tun wäre. Ich wäre gezwungen doch noch alles zu erzählen über IUnknown, über CLSIDs und ProgIDs und äh ... über Menschen ganz allgemein.

Unterrichten von ASP.NET-Programmierung wäre einfach, wenn ich nur zeigen müsste, wie man irgendwo doppelt klickt um dann Kode zu schreiben, der auf einem Server läuft, sobald ein Anwender auch doppelklickt. ASP abstahiert tatsächlich von dem Unterschied zwischen HTML-Kode, der das Klicken auf einen Hyperlink (<a>) abarbeitet, und dem Kode, der dasgleiche für eine Schaltfläche erledigt. Das Problem ist nur: die ASP-Designer mussten dafür die Tatsache verschleiern, dass HTML mit einem Hyperlink keine Formulare versenden kann. Das erreichen sie, indem sie ein paar Zeilen Javascript generieren und damit einen OnClick-Handler an den Hyperlink anhängen. Diese Abstraktion leckt. Wenn der Endanwendet sein Javascript deaktiviert hat, funktioniert die ASP.NET-Anwendung nicht, und wenn die Programmierer nicht wissen, was ASP.NET wegabstrahiert hat, haben sie auch keine Ahnung, was fasch gelaufen sein könnte.

Das "Gesetz von den leckenden Abstraktionen" hat für jedes neue schlaue Kodeerzeugungswerkzeug - das uns alle so viel effizienter arbeiten lassen soll - nur den einen Ratschlag: "Lerne zuerst, wie man es per Hand macht - nimm dann erst das schlaue Tool, um Zeit zu sparen!" Kodeerzeugungswerkzeuge, die vorgeben, etwas wegzuabstrahieren, lecken, wie alle anderen Abstraktionen auch. Die einzige Methode, damit kompetent umzugehen, ist, zu lernen wie die Abstraktion funktioniert und von was sie abstrahiert. Abstraktionen sparen uns also Arbeitszeit, nicht aber die Zeit fürs Lernen.

Es klingt paradox, aber das bedeutet, dass es immer schwieriger wird, trotz Arbeitens auf immer höherer Abstraktionsebene mit immer besseren Werkzeugen, ein tüchtiger Programmierer zu werden.

Als ich das erste Mal als intern bei Microsoft arbeitete, schrieb ich String-Biliotheken für den Macintosh. Eine typische Aufgabe war: Schreib' eine Version von strcat, die einen Zeiger auf das Ende eines neuen Strings zurückgibt. Ein paar Zeilen Kode in C. Alles aus dem K&R, einem dünnen Büchlein über die Programmiersprache C.

Heute, wo ich an "CityDesk" arbeite, muss ich Visual Basic, COM, ATL, C++, InnoSetup, Interna des Internet Explorer, reguläre Ausdrücke, DOM, HTML, CSS und XML kennen. Alles hochsprachliche Tools verglichen mit dem alten K&R; trotzdem muss ich das K&R-Zeugs kennen, sonst bin ich verloren.

Vor zehn Jahren haben wir vielleicht davon geträumt, dass neue Paradigmen das Programmieren heute leichter machen würden. Und tatsächlich haben uns die im Laufe der Jahre entwickelten Abstraktionen in die Lage versetzt, mit Komplexität umzugehen, die um Ordnungen größer ist als alles vor zehn oder fünfzehn Jahren; beispielsweise das Programmieren von grafischen Benutzeroberflächen oder die Netzwerkprogrammierung. Während einerseits tolle Tools wie die modernen OO-basierten Sprachen uns erlauben, eine Menge Arbeit in erstaunlich kurzer Zeit zu erledigen, so passiert es andererseits, dass wir auf eine Stelle stoßen, an der die Abstaktion leckt und das kostet uns dann 2 Wochen. Wenn du einen Programmierer einzustellen hast, der vor allem VB programmieren soll, genügt es nicht einen VB-Programmierer zu nehmen; der wird nämlich, immer wieder, hängen bleiben, sobald eine der VB-Abstraktionen leckt.

Das "Gesetz von den leckenden Abstraktionen" macht uns noch fertig!

Personal tools