Über das Thema der verschiedenartigen Sprachen und ihrer angewandten Programmierung habe ich mich schon das ein oder andere mal gestritten. Um es etwas esoterisch auszudrücken: "Haben wir erkannt was wirklich wichtig ist? Was ist sinnvoll? Was ist schön? Brauchen wir wieder etwas Neues? Muss es immer Clean Code sein? Ist es nun gut, das es unter .NET auch andere Sprachen gibt?Funktionale, Dynamische oder was auch immer sie als Titel beanspruchen?
Wo komm ich her?
“We have a new static keyword: dynamic”. Schöner als unser C# Vater Anders Hejlsberg hätte ich es auch nicht sagen können. Und auch hier zeigt sich schön. Dynamisch und im Wandel bleiben. Was heute richtig ist ist morgen falsch. Und umgekehrt genau so. Aber dennoch haben sich über die Jahrzehnte hinweg Paradigmen und Strategien entwickeln, die aus Ähnlichem Gleiches machen und daraus Muster entstanden. Über Sinn und Unsinn der möglichen und verschiedenen Paradigmen zu diskutieren kann ganz schön anstregend sein.
Jedes bietet sein für und wieder. Alles hat seine Richtigkeit und ist doch wieder falsch. Zum einen weil es viel mit Vergleichen aus der Vergangenheit mit Aussichten in die Zukunft zu tun hat. Zum anderen weil es ja doch sehr subjektiv ist, was schön und unschön, was richtig und falsch ist. Darum will ich auch gar niemanden bekehren. Stattdessen konzentriere ich mich auf das hier und jetzt und stelle mir lieber die Frage: Welche Aspekte sind mir ganz persönlich denn wichtig wenn wir von Programmiersprachen reden?
Ist es die Produktivität, die Funktionalität des Ergebnisses, die Evolvierbarkeit/Wartbarkeit des Produktes? Für mich kann die Antwort gar nicht klarer sein. Ja, es sind all diese Punkte die wichtig sind. Aus keinem anderen Grund liegt mir die Clean Code Bewegung so am Herzen. Doch auch hier liegt in seiner Beschreibung der Grundsatz vor das nichts dogmatisch befolgt werden soll. Im Laufe der letzten Jahrzehnte haben sich gute Muster aus verschiedenen Studien und anderen Erfahrungen wie dem alltäglichen Berufsleben ergeben. Die einen aus akademische Studien und Beobachtungen, die anderen über die praktischen Erfahrungen in der freien und wilden Berufswelt da draußen.
Wo wollen wir hin?
Jeder für sich, so glaube ich und habe ich immer wieder gesehen und gesagt bekommen, entwickelt mit der Zeit das für sich richtige Wertsystem und lebt danach immer bestrebt es zu optimieren. Jeder der über sein “Bauwerk” nachdenkt und überlegt, was er daran anders machen kann, wo Probleme auftreten und auch wie er das ändern kann besitzt die Fähigkeit zu reflektieren und damit den Grundstein für Veränderung. Dabei ist es mir aber vollkommen unwichtig über die Geschichte meines “Bauwerkes” nachzudenken. Mir kommt es nicht darauf an was ich in der Vergangenheit geschaffen habe und ich in Zukunft noch alles erschaffen kann. Mir geht es einzig und allein darum zu sehen was ich gerade in diesem einen Moment verbesseren kann im Sinne der Anforderungen.
Ich möchte also nicht über Wertesysteme diskutieren, wie sie clean-code-developer.de vermittelt. Für mich liegt vor allem das “was” und “wie” im “hier” und “jetzt” am Herzen. Die mit Clean Code verbundenen Prinzipien lassen sich meiner Meinung nach nicht nur mit der Objektorientierung zusammen anwenden. Es sind muster die gut übertragbar sind. Sicher sind das die Eckpfeiler unserer bisherigen Entwicklung. Aber ich würde mich nicht darauf fixieren. Zur zeit experimentier ich mit funktionalen Programmiersprachen und ihren deklarativen Konzepten. Sie werden immer populärer und die Art und Weise wie Probleme hier angegangen werden sind sehr interessant. Wenn ich von interessant Rede was meine ich da? Das ist ja wieder sehr subjektiv. Letztendlich muss das jeder für sich selbst entscheiden. Wo soll ich da nur anfangen? Eine gute und wichtige Entwicklung ist für mich LINQ in C# gewesen. Dort hat der Mainstream angefangen interessant zu werden.
Königlich Herrschen, oder weise Erfahren?
Und was genau macht denn andere Programmiersprachen so interessant für mich? Nun ich habe mich Anfang letzten Jahres etwas für Compilerbau interessiert und mit der Zeit immer mal wieder in F#, Python, C# und Boo kleine Übungsaufgaben gelöst. Habe mir mit LINQ in C# auch weitere funktionale Theorien angeeignet. Mit LINQ hielten die Expression im großen Stil Einzug. Lazy Evaluation. Code wird als Expression gespeichert und erst wirklich dann ausgeführt, wenn es an der Zeit ist. In F# oder Boo gibt es Meta-Programmierung vom feinsten ala Template Haskel. QuasiQuotation und Splicing geben ihr bestes. Was das auf sich hat? Wer es nicht abwarten kann, soll ruhig schon mal googlen. Ich werde in späteren Posts darauf zurück kommen. F# an sich ist ja schon als Abkömmling von ML (Meta Language) im Namen damit verwandt.Neulich bin ich dann mit Lisp/Scheme und ein klein wenig Haskel in Berührung gekommen und habe mir daraufhin Nemerle (Seite zur Zeit wegen DNS Problemen überlastet, hier ein temporärer Mirror)wieder etwas unter die Lupe genommen. Auf dem .NET OpenSpace 2009 habe ich versucht etwas auf das Thema Language Oriented Programming (LOP) einzugehen.
Aber warum immer wieder nach etwas Anderem umschauen? Weil es einfacher werden soll. Weil einfach einfach einfach ist. Machen wir uns damit aber nicht alles kaput? Kann in dann die ganzen Prinzipien noch anwenden? Teils ja, teils nein. Manchmal kann man einfach mit Meta-Programmierung nicht DRY bleiben. Oder gehts es doch? Es gibt viele Fallstricke und andere Hindernisse. Aber der Einsatz ist lohnenswert. Ich stelle mir Idealerweise ein Entwicklung so vor, dass erst einmal ein Framework gebaut wird und dieses Framework als syntaktischer Zucker in eine DSL gegossen wird, sei es intern mit Macros, oder extern mit einer eigenen Sprache.
Raupe oder Schmetterling?
Es liegt also an der Einfachheit der kleinen Einheit. Nehmen wir unser Lieblings Muster aus der Informatik. Ein Eingang, darauf folgend der autonome Vararbeitungsprozess und ein Ausgang – kurz EVA. Über die Jahre hinweg rückte diese Zentrale Weisheit immer mehr in den Mittelpunkt. Im ZEN hätte binäre Einfachheit wohl kaum kürzer beschrieben werden können. Ein Input, Transformation, ein Output. Oder etwas erweitert beschrieben: Minimalen Input, minimalen Output.
Hier liegt im Kern eine der großen Stärken von modernen Sprachen, die über die imperativen Ansätze hinausgehen. Sie schaffen es auf deklarative Weise sich selbst zu erweitern, indem sie erkennen, reflektieren und mir als Entwickler damit Möglichkeiten geben meine Struktur zu vereinfachen. Damit wird aus dem steinigen weg hoffentlich ein gemütlicher Trampelpfad. Daraus leitet sich die meiner Meinung nach größte Stärke von modernen Sprachen ab. Es ist die Möglichkeit der Definition von neuen Operatoren und Schlüsselwörtern und damit die Möglichkeit die Programmierung auf ein neues Abstraktionsniveau zu bringen. Wo ich früher 20000 Zeilen Code geschrieben haben, schreibe ich aufgrund der von mir neu erstellten Syntax nur noch 2000 Zeilen um es einmal auf die Spitze zu treiben. In meinen Augen sind das die bessere Produktivität, geringere Fehleranfälligkeit und leichtere Evolvierbarkeit. So wirkt das DSL Prinzip, das ich hier zugrunde lege.
Schmetterling!
Wo sind die “STOP” Schreier? Bis ich das wieder alles lernen muss. Ja diesen Weg kann uns keiner nehmen. Entweder ich weiß, dass es steinig wird und das dies für mich persönlich der richtige Weg ist oder ich schaue weg, weil es mich nicht interessiert. Ich gehe diese Weg. Sofort! Wir begeben uns auf die META Ebene. Es findet eine Transformation statt, deren wir uns bewußt sind! D.h. im Klartext, wir wissen wie Code strukturiert wird, semantisch und syntaktisch und sind in der Lage diese beim Namen zu benennen. Daraufhin kann ich diese umwandeln. Lange rede, kurzer Sinn: Über kurz oder lang sollte sich jeder, denn diese Art und Weise des Programmierens interessiert mit Compilerbau und deren Techniken auseinandersetzen. Doch wo kommt das denn her, ist das wirklich so neu?
Sehe ich nun besser aus?
Nein es ist nicht so neu. Schon mit C++ war es mir möglich über den Preprozessor Macros zu schreiben, die eine schlankere und lesbarere Syntax erlaubte. Ganz klar eine Transformation und für mich auch ganz klar schon META Programmierung. Diese waren aber textgetrieben und fehleranfällig. Über die Jahre hinweg hat sich das aber verbessert und wir kommen von der unsicheren “nur Text” Transformation (Text Templates) zu modernen Konstrukten, die uns semantische Macros erlauben, mit denen wir über Compiler-Services Code für die Compilezeit schreiben können. Ich schaue mir aus diesem Grund die anderen Sprachen auf Basis des .NET Frameworks immer wieder an. Es ist durchaus lohnenswert. Manchmal kann ich Sachen entdecken, die mir vorher komplett vom Radar gefallen sind. Einige Kandidaten habe ich ja in meinem Artikel Le Parkour .NET vorgestellt.
Welche sind denn im Moment so interessant für mich? Es hat sich nicht viel geändert. Das ist sowohl Boo, wie auch F# und Nemerle. Nemerle hatte ich schon mal auf dem Radar, ist aber wieder verschwunden und vor kurzem erneut aufgetaucht. Python ist nicht nur wegen meiner aktuellen Arbeit seit 2007 verstärkt auf dem Bildschirm. IronScheme beobachte ich, aber lasse es mal weiter so sein. Bei IronRuby verhält sich das ähnlich. Obwohl Ruby ähnlich gute Möglichkeiten für eigene Spracherweiterungen (interne DSLs) bietet, werde ich damit noch nicht so recht warm, da die anderen genannten für mich momentan attraktiver sind. Dabei bietet Ruby aus meiner Sicht eine besonders attraktive Syntax und Erweiterungsmöglichkeiten an. Schaue man sich da doch mal Rake oder RSpec an. Machine.Specifications zeigt, dass so etwas auch durchaus mit C# möglich ist. Besonders fasziniert hat mich in letzter Zeit allerdings OMeta als ich beim Versuch BooLangStudio etwas weiter in Richtung VS2010 zu entwickeln erst einmal kläglich gescheitert bin. In den aktuellen Boo-Extensions gibt es eine weit fortgeschrittene Implementierung von einem OMeta Dialekt, der eine auf Boo abgewandelte Syntax besitzt, um OMeta als eigentlich eigene Sprache (externe DSL) zu einer internen in Boo zu machen. Somit wird Boo in Zukunft nicht nur Macros besitzen, sondern auch die Fähigkeit die eigene Sprache durch EBNF ähnliche Anweisungen leicht zu erweitern. Boo bietet aber auch noch mehr, was z.B. bei Funktionalen Programmiersprachen Gang und Gäbe ist.
Zeit für Selbsterkennung!
Am Anfang war da Code. Hauptsache er funktionierte irgendwie. Aber nach 12 Jahren Programmiererfahrung sieht das anders aus. Komposition, Aggregation, Strukturierung, wiederverwendbare Module. Warum wenden wir solche Strukturierungsmittel nur auf Ebene einer bereits starren Sprache an? C# lässt keine Manipulation der eigene Sprache zu. Das mag zum Teil auch gut sein. Denn so ergeben sich keine Dialekte und jeder spricht eine einheitliche Sprache. Denkt doch mal daran einen Niederbayern mit einem Nordlicht aus Flensburg zusammenzusetzen. Die Wahrscheinlichkeit, dass beide zusammen Plattdeutsch oder Niederbayrisch verstehen ist eher gering. Aber wie wir wissen ist eine Sprache im Ständigen wandel und lebt von seiner Veränderung. Für Programmiersprachen verhält es sich da für mich gleich. Aber hier haben wir als Otto-Normal-Entwickler keine Möglichkeiten uns aktiv in die Entwicklung einer solchen Programmiersprache wie C# mit einzubringen. Anders sieht das mit offenen Sprachen aus, die explizit auf so etwas ausgelegt sind. Denke man mal an das Potential, das Lisp nachgesagt wurde. Wer sich mal die Grundkonzepte dieser Sprache ansieht, wird verstehen was die Magie und die mystische Aura um diese Sprache herum ausmacht. Zugegeben keine schöne Syntax, aber faszinierend.
Alle Sprachen, die implizit eine Erweiterung ihrer selbst erlauben und dem Entwickler die notwendigen Werkzeuge mit an die Hand geben sind für mich die Zukunft. Systeme, die es schaffen das zu bieten was heutige Compiler und IDEs schon können, aber alles noch generisch und erweiterbar. Quasi einen Compilerbaukasten-mit-IDE-selbst-Integration. Und dabei meine ich nicht solche “ordinären” Werkzeuge wie … nein keine Namen. Ich denke hier eher an System, die vollintegrierte Sprachmittel bieten um sich eben selbst zu erweitern. Ich denke da an Systeme die Macros unterstützen, aber auf einer weiter gereiften Ebene mit allen möglichen Schikanen die uns im IDE Alltag begleiten. Ich denke an Systeme wie MPS, Intentional Workbench, Xtext und dergleichen. Auf eine Art und Weise, die intuitiv und einfach ist. Kommen wir da hin?
Was kommt morgen?
Da rede ich davon im hier und jetzt zu sein und bin schon wieder bei morgen. Was bieten uns Programmiersprachen denn heute? Über die Jahre hinweg bin ich wie viele andere mit verschiedenartigen Programmiersprachen in Berührung gekommen. C/C++, FoxPro, JavaScript, ActionScript, HTML, XML, C#, Visual Basic, Python, Ruby, Boo, F#, Nemerle, Scheme (das dürfte historisch sogar sehr exakt sein) und noch einige mehr. Mit den einen habe ich viel gearbeitet mit den meisten eher wenig. Aber eins haben doch alle gemeinsam. Sie versuchen uns den Alltag auf ihre ganz spezielle Weise zu erleichtern.
Die Verschiedenartigkeit der Objektorientierung habe ich bereits kennen gelernt. Ich habe für mich festgestellt, das es sinnvoll ist, möglichst unveränderliche, kleine Strukturen zu bauen, die sich funktional auf eine einzige Aufgabe stürzen (getreu dem Single Responsibility Prinzip). Abhängigkeiten werden soweit notwendig über Konstruktoren/Factories mitgegeben. Warum das ganze Factory Pattern hinter eigener Syntax verstecken? Da höre ich schon wieder die Unkenrufe: Aspekte und Querschneidende Belange. Ich will nicht, dass sowas missachtet wird. Das muss in der imperativen Programmierung keine Dependency Injection sein, hilft einem dabei aber sehr. Eine Einheit ist überschaubar und wartbar. Sie hat keine, oder nur wenig Seiteneffekte! Das ist per Definition kein Alleinstellungsmerkmal der OOP. Wiederverwenden und neue Funktion daraus zu schaffen ist die Aufgabe des Entwicklers, der gelernt hat, wie ordentliche Strukturierung funktioniert.
Alles ist eine Transformation! Schon die Physik lehrte uns das. Genauso wie “aktion = reaktion”. Wenn wir also unsere Intension ausdrücken wollen was bietet sich da besser an als Sprache. Explizit oder Implizit? Das lasse ich jetzt noch offen. Bisher war ich immer der Meinung explizit ist besser. Aber würde auch implizit mit Hinweisen langen?
Für mich steht eines fest. Ich bin. Im Moment ist das META. Und was morgen kommt lasse ich mir offen, denn dann könnte es schon wieder falsch sein.