Die Abstraktionskaskade

Jeder Informatiker kennt das: wenn man heutzutage Software entwickelt, kämpfen zig Frameworks und andere Technologien um die Gunst der Nutzung bei der Implementierung. Dabei versprechen letztlich alle, die Komplexität der Welt zu verstecken hinter einem mächtigen Schutzschild der Abstraktion. Mit Java ist es uns egal, auf welchem Betriebssystem wir laufen. Mit Hibernate ist es uns egal, welches DB-System wir nutzen. Mit JEE ist es uns egal, auf welchem Application Server wir laufen und mit welcher Middleware wir kommunizieren. Mit GWT ist es uns egal, in welchem Browser unsere Oberfläche dargestellt wird. Und mit Spring ist uns alles egal.

Das Problem ist nur: keine Abstraktion ist perfekt. Und damit meine ich nicht das Phänomen, das Joel Spolsky mit “leaky abstraction” benannt hat. Manche Abstraktion verhindert, dass wirklich gute Software entstehen kann. “Gut” im Sinne von performant, ins System integriert, ressourcenschonend. Allgemein könnte man sagen: Abstraktion verhindert eine spezifische Problemlösung.

Nehmen wir Java als Beispiel. Das “WORA”-Prinzip – “Write Once Run Anywhere” – ist das große Versprechen. Bei der graphischen Oberfläche war der erste Versuch “AWT”, ein Toolkit, das das Prinzip der Abstraktion schon im Namen trägt. Um “WORA” zu garantieren, implementierte AWT schlicht den kleinsten gemeinsamen Nenner bei den graphischen Oberflächen dieser Zeit. Es war erschreckend, wie klein dieser Nenner wirklich war. Der zweite Versuch – Swing – basierte auf dem Ansatz, dass es wenigstens möglich sein müsste, anständige graphische Oberflächen so zu bauen, dass sie wenigstens überall gleich aussehen, wenn auch nicht wirklich “nativ”. Mit der “pluggable Look&Feel”-Technik gab es immerhin die Möglichkeit, sich den einzelnen Plattformen aussehensmäßig anzunähern. Im Detail gab es trotzdem immer Unterschiede, weil Swing bis heute z.B. nicht das plattform-native Font-Rendering verwendet hat. Und auch Swing litt durchaus unter dem Ansatz des kleinsten gemeinsamen Nenners, der erst partiell durch das JDIC-Projekt entschärft wurde.

Wenn man es kritisch formuliert, könnte man sagen: wenn man ein Cross-Plattform-UI-Toolkit verwendet, hat man zwar auf vielen Plattformen ein UI, aber eben auch überall ein suboptimales UI. Erinnert ein wenig an die Situation im Bereich der mobilen Plattformen, wo die “im-Browser-aber-dafür-überall”-Lösungen gegen die “native-und-dafür-nicht-überall-oder-überall-anders”-Lösungen kämpfen.

Wenn man ganz weit zurückgeht, könnte man die CISC-CPUs als erste Abstraktionsschicht begreifen. Beim Z80 zum Beispiel gab es den schönen Speicherblockkopierbefehl “LDIR” (echte Nerds mit Vertiefung in Z80-Assembler wissen durch jahrelanges Studium von Hexdumps sofort den Op-Code auswendig: ED B0). Man hat drei Register geladen, LDIR aufgerufen und 21 Zyklen pro kopiertem Byte verbraten. Hat man das Kopieren “von Hand” übernommen, konnte man allerdings zwei Bytes in nur 16 Zyklen (über clevere Manipulation des Stack-Pointers und Verwendung von Push und Pop) kopieren. Also damals schon ein Fall von Performance vs. Bequemlichkeit, und auch ein wenig “einfacher zu verstehen aufgrund der Abstraktion” – eine Eigenschaft, die nicht alle Abstraktionen haben, denn oftmals abstrahieren sie so weit vom Problem, dass es eher komplizierter wird.

Ich persönlich fühle mich hinter zuviel Abstraktionen unwohl. Zu oft sind die Implementierungen fehlerhaft, so dass man beim Finden von Workarounds von der abstrakten Ebene hinabsteigen muss in den Maschinenraum. Oft wird dann die Problemlösung deutlich komplizierter – eben weil sie irgendwie wieder in die Abstraktion passen muss. Trotzdem habe ich mich über die Jahre mit Java angefreundet, begrenzt auch mit Swing und Vaadin. Trotzdem genieße ich die Abstecher zu C und ARM Assembler unter RISC OS, wo man per SWI-Aufruf mit dem Betriebssystem spricht und die Register dazu direkt befüllt – es ist instruktiv sowohl in Hinsicht auf damit erreichbare Performance und Kompaktheit als auch als Erinnerung an die eigene Fehlbarkeit.

Letztlich gibt es keinen Königsweg. Wer alles selbst machen will, wird niemals in akzeptabler Zeit fertig werden. Wer alles aus Fremdkomponenten zusammenstöpselt, wird bei der Qualität der Lösung immer Abstriche machen müssen. Time to market, Quality and Performance, Price. Choose any two. Und die Kunden nicht aus den Augen verlieren – nicht immer werden Argumente vom Schlage “kann man nix machen, das Framework macht das halt so” akzeptiert. Auf der anderen Seite kann es böse ins Auge gehen, dem Fehlschluss “wenn die Abstraktion eh nix taugt, kann ich es gleich selbst machen” zu erliegen.