Am 13. Oktober 2008 haben Peter Bucher und ich unter dem Titel Noch Fragen, Bucher? Ja, Roden! angekündigt, jeweils zum ersten eines jeden Monats einen Kommentar zu einem vorab gemeinsam gewählten Thema verfassen zu wollen. Bisher sind in dieser Reihe folgende Kommentare erschienen:
Heute, am 1. März 2010, ist es nun wieder so weit, und unser Thema für diesen Monat lautet:
Abstraktion
So wohl Peter wie auch ich haben uns unabhängig voneinander im Vorfeld unsere Gedanken gemacht, wie wir diesem Thema gegenüberstehen. Außerdem nimmt diesen Monat auch Roberto Bez an unserem Streitgespräch teil.
Peters und Robertos Kommentare finden sich zeitgleich in den entsprechenden Blogs, folgend nun mein Kommentar zu diesem Thema:
Das Selbstverständnis der Informatik, anderen Fachgebieten eine Hilfswissenschaft zu sein, impliziert die Anwendung von Abstraktion bereits: Letztlich werden deren Objekte, Daten und Prozesse nämlich in geeinete informationstechnische Strukturen abstrahiert.
Abstraktion an sich wird dabei beispielsweise von Wikipedia als
induktiven Denkprozess des Weglassens von Einzelheiten und des Überführens auf etwas Allgemeineres oder Einfacheres
definiert. Es geht also letztlich darum, gegebene Probleme besser lösen zu können, indem für die Lösung unnötige Komplexität verringert wird – in der Regel, indem diese durch eine einfachere Darstellung verborgen wird.
Bereits im schulischen Mathematikunterricht findet Abstraktion in dieser Form statt, wenn beispielsweise die Lösung von Textaufgaben gefordert wird, die die eigentliche mathematische und abstrakte Aufgabe in einer mehr oder weniger anschaulichen Beschreibung verpacken.
Ohne Abstraktion wäre die Lösung mancher Aufgaben nicht nur bedeutend schwieriger und komplexer oder gar unmöglich, ohne sie wäre auch die Kommunikation mit anderen Disziplinen bedeutend erschwert.
Für einen Informatiker spielt es in der Regel nämlich zunächst keine Rolle, ob zum Beispiel Gepäckstücke an einem Flughafen oder aber Reagenzgläser in einem medizinischen Labor automatisiert befördert und verarbeitet werden sollen – beide Aufgaben können zu einem Logistikproblem abstrahiert werden, das mit entsprechenden Verfahren lösbar oder zumindest annäherbar ist.
Abstraktion nimmt also eine essenzielle Rolle in der Informatik ein – doch Abstraktion ist nicht per se als positiv zu bewerten. Abstraktionen verbergen nämlich nicht nur unnötige Komplexität, sondern neigen bewusst oder unbewusst auch dazu, Details zu verbergen, die für die Lösungsfindung allerdings relevant sind.
Joel Spolsky bezeichnet diesen Umstand als The Law of Leaky Abstractions. Er fasst seine Erkenntnisse bezüglich Abstraktion in dem Satz
All non-trivial abstractions, to some degree, are leaky.
zusammen, was letztlich so viel bedeutet, dass Abstraktionen nicht nur dabei helfen, Probleme zu lösen, sondern ihrerseits lecken und neue Probleme verursachen, weil die notwendigen Details nicht mehr bekannt sind – ironischerweise desto eher, je stärker abstrahiert wird.
Beispiele für Abstraktionen und die dazugehörigen Lecks sind – wie in der gesamten übrigen Entwicklung von Software – auch in .NET ohne weiteres zu finden:
So abstrahiert die Garbage Collection von .NET die Notwendigkeit, Speicher selbst zu verwalten – dies geschieht implizit. Doch sie löst nicht alle Probleme, zudem verursacht sie neue Probleme, derer sich Entwickler zumindest in kleinen Anwendungen nicht bewusst werden.
Denn nach wie vor haben Entwickler mit hängenden Referenzen zu kämpfen, die beispielsweise dadurch entstehen, dass Ereignisse nicht auch wieder abgemeldet werden.
Ebenfalls problematisch ist das vermeintlich günstige Erzeugen neuer Objekte im Verlass darauf, dass die Garbage Collection die erzeugten Objekte wieder entfernen wird – Speicherverschwendung und damit Performanceprobleme auf Grund falsch angewandter Instanziierung sind eher die Regel denn die Ausnahme.
Auch der grafische, in Visual Studio enthaltene Designer für WPF stellt eine solche Abstraktion dar: Er entledigt den Entwickler von der lästigen Aufgabe, WPF-Code per Hand schreiben zu müssen – kann aber natürlich nie die wahre Absicht des Entwicklers erahnen und muss daher gewisse Kompromisse zwischen Generalität und vernünftigem, das heißt performanten und wohlstrukturierten Code eingehen.
Last but not least stellt selbst der Konkatenationsoperator für Zeichenketten, dargestellt durch ein vermeintlich harmloses +, eine Abstraktion über die Vorgänge dar, die im Speicher stattfinden, um zwei Zeichenketten miteinander zu einer neuen zu verbinden. Die Speicher- und Performanceimplikationen dürften hinlänglich bekannt sein.
All diese Probleme werden durch Abstraktionen verursacht, die ursprünglich angetreten sind, bestehende Probleme zu lösen. Natürlich kann man auf Abstraktionen auch nicht verzichten – zu essenziell sind sie für die überschaubare Lösbarkeit eines gegebenen Problems.
So erspart beispielsweise ASP.NET als Abstraktion über das HTTP-Protokoll – das seinerseits übrigens nichts anderes als eine weitere Abstraktion über den Datenverkehr im Netzwerk darstellt – dem Entwickler eine ganze Menge an Aufgaben, die in der Regel ohnehin immer nach dem gleichen Schema erledigt werden.
Doch – wer nicht weiß, was bei ASP.NET unter der Haube geschieht, neigt schnell dazu, die vorgegebenen Pfade als das Nonplusultra anzusehen und dabei auftretende Probleme zu ignorieren, schlichtweg, weil sie auf Grund der Abstraktion nicht wahrgenommen werden.
Das Paradoxe an dieser Situation ist, dass es – je mehr und mächtigere Abstraktionen verfügbar sind, desto schwieriger wird es, zu wissen, was man eigentlich macht. Damit schließe ich mich nahtlos Joel Spolsky an, wenn er in seinem eingangs erwähnten Artikel schreibt:
[…] all this means that paradoxically, even as we have higher and higher level programming tools with better and better abstractions, becoming a proficient programmer is getting harder and harder.
Schlussendlich lässt sich zusammenfassen, dass es für hervorragende Entwickler nicht genügt, sich mit ihrer jeweils präferierten Technologie auseinanderzusetzen, sondern dass sie sich – um wirklich verstehen und nachvollziehen zu können, was geschieht – auch mit den zu Grunde liegenden Technologien auseinandersetzen müssen.
Das bedeutet, dass auch – oder erst recht – in Zeiten von Hochsprachen, Frameworks, Designern und Assistenten die Berechtigung oder gar die Pflicht gegeben ist, sich mit den Grundlagen zu beschäftigen.
Dass dies nicht zuletzt auch eine große Herausforderung für die Ausbildung darstellt, sei es in Firmen, an Hochschulen oder in sonstigen Formen, liegt auf der Hand.
Werden die Grundlagen nämlich zu Gunsten schnellerer und vermeintlich besserer Lernerfolge systematisch ignoriert, bedeutet das, Oberflächlichkeit zu fördern und verstehendes Wissen unter Anwendung der Root Cause Analysis, die unter anderem auch von der Clean Code Developer-Initiative wertgeschätzt wird, zu missachten.