November 2018
Band 33, Nummer 11
.NET: Erstellen einer eigenen Skriptsprache mit symbolischen Delegaten
Von Thomas Hansen | November 2018
Ich liebe meinen C#-Compiler. Meine Freundin behauptet, ich liebe ihn mehr als ich sie liebe, aber das würde ich in der Öffentlichkeit aus offensichtlichen Gründen niemals zugeben. Starke Typisierung, Generika, LINQ, Garbage Collection, CLI. Die Liste der interessanten Merkmale ist fast endlos. Ab und zu brauche ich jedoch ein paar Tage Urlaub von den komfortablen Sicherheiten, die mir mein Compiler normalerweise zur Verfügung stellt. An diesen Tagen entscheide ich mich für die Programmierung in dynamischen Programmiersprachen. Und je dynamischer die Sprache, desto gefährlicher und unterhaltsamer ist die ganze Angelegenheit.
Gut soweit. Das soll als Einführung reichen. Machen wir nun das, was echte Programmierer machen, wenn sie allein gelassen werden – erstellen wir Code:
hello world
Was? Sie dachten doch, ich hätte von „Code“ gesprochen? Ja, genau das habe ich gemeint, und dieser Text ist tatsächlich Code. Damit Sie verstehen, was ich meine, sehen wir uns an, welche Möglichkeiten dieser Code bietet. Werfen Sie einen Blick auf Abbildung1. Sie zeigt ein minimalistischer Beispiel dafür, was als „symbolische Delegaten“ bezeichnet wird. Erstellen Sie eine leere Konsolen-App in Visual Studio, und geben Sie den Code aus Abbildung1 ein.
Abbildung 1A: Ein minimalistisches Beispiel für symbolische Delegaten
using System;
using System.Collections.Generic;
class MainClass
{
public static void Main(string[] args)
{
// The "programming language"
var keywords = new Dictionary<string, Action> {
// The "hello" keyword
["hello"] = () => {
Console.WriteLine("hello was invoked");
},
// The "world" keyword
["world"] = () => {
Console.Write("world was invoked");
}
};
// The "code"
string code = "hello world";
// "Tokenising" the code
var tokens = code.Split(' ');
// Evaluating the tokens
foreach (var token in tokens) {
keywords[token]();
}
}
}
Mit nur 25 Codezeilen habe ich meine eigene Mikroprogrammiersprache erstellt. Um ihre Vorteile zu verstehen, sollten Sie sich bewusst machen, dass die Variable „Code“ über das Netzwerk gesendet werden kann. Sie kann aus einer Datenbank abgerufen oder in einer Datei gespeichert werden, und ich kann die Zeichenfolge dynamisch aus „hello world“ in „world hello“ oder „hello hello world world“ und damit das Ergebnis vollständig ändern, in das sie ausgewertet wird. Diese Möglichkeit bedeutet, dass ich Delegaten dynamisch kombinieren kann, um am Ende eine Liste von Funktionsobjekten zu erhalten, die entsprechend dem Inhalt des Codes sequenziell ausgewertet werden. Plötzlich habe ich eine statisch kompilierte Programmiersprache in eine dynamische Skriptsprache umgewandelt, indem ich einfach einen Satz in seine Wörter zerlegt und die einzelnen Wörter als Nachschlageschlüssel in einem Wörterbuch verwendet habe. Das Wörterbuch in Abbildung 1 wird daher zu einer „Programmiersprache“. In Wirklichkeit ist es ein symbolischer Delegat.
Dieses Beispiel ist offensichtlich ziemlich langweilig und soll nur die Kernidee veranschaulichen. Ich werde ein interessanteres Beispiel erstellen, indem ich diese Ideen ein wenig weiter auf die Spitze treibe, wie in Abbildung 2 gezeigt.
Abbildung 2: Dynamische Verkettung von Delegaten
using System;
using System.Linq;
using System.Collections.Generic;
public class Chain<T> : List<Func<T, T>>
{
public T Evaluate(T input)
{
foreach (var ix in this)
{
input = ix(input);
}
return input;
}
}
class MainClass
{
public static void Main(string[] args)
{
var keywords = new Dictionary<string, Func<string, string>>
{
["capitalize"] = (input) =>
{
return input.Replace("e", "EE");
},
["replace"] = (input) =>
{
return input.Replace("o", "0");
}
};
string code = "capitalize replace";
var tokens = code.Split(' ');
var chain = new Chain<string>();
chain.AddRange(tokens.Select(ix => keywords[ix]));
var result = chain.Evaluate("join the revolution, capitalize and replace");
Console.WriteLine(result);
}
}
Jetzt verfüge ich über etwas, das fast nützlich erscheint: die Fähigkeit, Delegaten dynamisch miteinander zu verketten, was zu einem Lambda-Objekt mit lose gekoppelten Funktionen führt. Somit deklariert der Code eine Kette von Funktionen, die ein Objekt sequenziell gemäß den Symbolen transformieren, die ich in meinen Code einfüge. Zur Erinnerung: Normalerweise sollte keine Vererbung von „List“ erfolgen. Um das Beispiel kurz zu halten, habe ich mich aber entschieden, doch so vorzugehen, um die Grundidee zu veranschaulichen.
Die Erweiterung dieser Idee ist einfach. Die Aufgabe besteht darin, den kleinsten gemeinsamen Nenner für einen generischen Delegaten zu finden, der jedes Ihnen bekannte Programmierkonstrukt beschreiben kann. Dabei handelt es sich um den folgenden Delegaten:
delegate object Function(List<object> arguments);
Dieser Delegat kann fast jede Programmierstruktur darstellen, die jemals erfunden wurde. Alles in der Informatik kann eine Liste von Eingabeargumenten annehmen und etwas an den Aufrufer zurückgeben. Dieser Delegat ist die eigentliche Definition von Eingabe/Ausgabe, die für alle Computingideen grundlegend ist, und wird zu einer atomischen Programmierstruktur, mit der Sie alle Ihre Computingprobleme lösen können.
Darf ich vorstellen: Lizzie
Als ich diesen Artikel schrieb, habe ich eine Programmiersprache erstellt, die die oben vorgestellte Idee beinhaltet. Ich habe die gesamte Sprache (die ich nach meiner Freundin Lisbeth „Lizzie“ nenne) an ein paar Vollmond-Wochenenden geschrieben. Die Sprache ist vollständig in einer einzelnen Assembly enthalten, die aus ungefähr 2.000 Zeilen Code besteht. Nach dem Kompilieren belegt die Assembly nur 45 KB auf dem Datenträger, und ihr „Compiler“ besteht aus nur 300 Zeilen C#-Code. Lizzie ist außerdem leicht erweiterbar und ermöglicht es jedem Programmierer, seine eigenen „Schlüsselwörter“ hinzuzufügen, sodass Sie ganz einfach Ihre eigene domänenspezifische Sprache (Domain-Specific Language, DSL) erstellen können. Ein Anwendungsfall für eine solche Sprache ist eine regelbasierte Engine, in der Sie Code dynamischer verbinden müssen als es C# ermöglicht. Mit Lizzie können Sie Ihrer statisch kompilierten C#-Anwendung dynamischen Skriptcode hinzufügen, der Turing-vollständige Codeausschnitte für Funktionalität bereitstellt. Lizzie ist für C#, was Gewürze für Ihr Essen sind. Sie möchten nicht nur Gewürze essen, aber wenn Sie Ihrem Steak etwas Würze hinzufügen, wird Ihre Esserfahrung offensichtlich angenehmer. Um Lizzie auszuprobieren, erstellen Sie eine leere Konsolenanwendung in C#, fügen Lizzie als NuGet-Paket hinzu und verwenden den Code in Abbildung 3.
Abbildung 3: Erstellen einer domänenspezifischen Sprache
using System;
using lizzie;
class Demo1
{
[Bind(Name = "write")]
object write(Binder<Demo1> binder, Arguments arguments)
{
Console.WriteLine(arguments.Get(0));
return null;
}
}
class MainClass
{
public static void Main(string[] args)
{
var code = "write('Hello World')";
var lambda = LambdaCompiler.Compile(new Demo1(), code);
lambda();
}
}
In nur 22 Codezeilen habe ich so meine eigene domänenspezifische Sprache erstellt und der Sprache mein eigenes domänenspezifisches Schlüsselwort hinzugefügt.
Die Hauptfunktion von Lizzie besteht darin, dass Sie Ihren Lizzie-Code an einen Kontexttyp binden können. Die LambdaCompiler.Compile-Methode in Abbildung 3 ist in der Tat eine generische Methode, aber ihr Typargument wird automatisch durch ihr erstes Argument abgeleitet. Intern erstellt Lizzie eine Bindung, die an Ihren Typ gebunden wird, und stellt Ihnen so alle Methoden mit dem Bind-Attribut aus Ihrem Lizzie-Code zur Verfügung. Wenn Ihr Lizzie-Code ausgewertet wird, verfügt er über ein zusätzliches Schlüsselwort namens „write“. Sie können jede beliebige Methode an Ihren Lizzie-Code binden, solange sie die richtige Signatur aufweist. Und Sie können Ihren Lizzie-Code an jeden beliebigen Typ binden.
Lizzie weist mehrere Standardschlüsselwörter auf, die für Ihren eigenen Code zur Verfügung gestellt werden, aber Sie müssen diese nicht verwenden, wenn Sie es nicht möchten. Abbildung 4 zeigt ein vollständigeres Beispiel, das einige dieser Schlüsselwörter verwendet.
Abbildung 4: Verwenden einiger Standardschlüsselwörter
using System;
using lizzie;
class Demo1
{
[Bind(Name = "write")]
object write(Binder<Demo1> binder, Arguments arguments)
{
Console.WriteLine(arguments.Get(0));
return null;
}
}
class MainClass
{
public static void Main(string[] args)
{
var code = @"
// Creating a function
var(@my-function, function({
+('The answer is ', +(input1, input2))
}, @input1, @input2))
// Evaluating the function
var(@result, my-function(21,2))
// Writing out the result on the console
write(result)
";
var lambda = LambdaCompiler.Compile(new Demo1(), code);
lambda();
}
}
Der Lizzie-Code in Abbildung 4 erstellt zunächst eine Funktion namens „my-function“ und ruft diese Funktion dann mit zwei Integerargumenten auf. Schließlich schreibt er das Ergebnis des Funktionsaufrufs in die Konsole. Mit 21 Zeilen C#-Code und acht Zeilen Lizzie-Code habe ich dynamischen Code ausgewertet, der eine Funktion in einer dynamischen Skriptsprache aus meinem C#-Code heraus erstellt, während ich der von mir verwendeten Skriptsprache ein neues Schlüsselwort hinzugefügt habe. Es waren insgesamt nur 33 Zeilen Code erforderlich, einschließlich der Kommentare. Diese 33 Zeilen Code ermöglichen es Ihnen zu behaupten, dass Sie Ihre eigene Programmiersprache erstellt haben. Anders Hejlsberg, move over rover, and let little Jimmy take over …
Ist Lizzie eine „echte“ Programmiersprache?
Um diese Frage zu beantworten, müssen Sie darüber nachdenken, was Sie unter einer echten Programmiersprache verstehen. Lizzie ist Turing-vollständig und erlaubt es Ihnen (zumindest theoretisch), jedes Computingproblem zu lösen, das Sie sich vorstellen können. Nach der formalen Definition dessen, was eine „echte“ Programmiersprache ausmacht, ist Lizzie also sicherlich so echt wie jede andere Programmiersprache. Andererseits wird sie weder interpretiert noch kompiliert, da jeder Funktionsaufruf einfach ein Wörterbuchlookup ist. Außerdem gibt es nur eine Handvoll von Konstrukten, und alles dreht sich um die Syntax „function(arguments)“. Tatsächlich folgen selbst if-Anweisungen der zuvor im generischen Delegaten definierten Funktionssyntax:
// Creates a function taking one argument
var(@foo, function({
// Checking the value of the argument
if(eq(input, 'Thomas'), {
write('Welcome home boss!')
}, {
write('Welcome stranger!')
}) // End of if
}, @input)) // End of function
// Invoking the function
foo('John Doe')
The syntax of if is as follows:
if(condition, {lambda-true}, [optional] {lambda-else})
Das erste Argument für das Schlüsselwort „if“ ist eine Bedingung. Das zweite Argument ist ein Lambda-Block, der ausgewertet wird, wenn die Bedingung einen Nicht-NULL-Wert (TRUE) ergibt. Das dritte Argument ist ein optionaler Lambda-Block, der ausgewertet wird, wenn die Bedingung NULL (FALSE) ergibt. Das Schlüsselwort „if“ ist also in der Tat eine Funktion, an die Sie ein Lambda-Argument übergeben können, indem Sie die Syntax „{ .... code ... }“ verwenden, um das Lambda zu deklarieren. Dies mag sich anfangs etwas seltsam anfühlen, denn alles geschieht zwischen den öffnenden und schließenden Klammern Ihrer Schlüsselwörter, im Gegensatz zu anderen Programmiersprachen, die eine eher traditionelle Syntax verwenden. Um jedoch einen Compiler für Programmiersprachen in 300 Codezeilen zu erstellen, mussten einige mutige Entscheidungen getroffen werden. Und bei Lizzie dreht sich alles um Einfachheit.
Lizzies Funktionen ähneln überraschend der Struktur einer s-expression (symbolischer Ausdruck) aus Lisp, allerdings ohne die seltsame polnische Notation. Da eine s-expression alles beschreiben kann und Lizzies Funktionen einfach s-expressions mit dem Symbol (erstes Argument) außerhalb der Klammern sind, können Sie mit Lizzie alles beschreiben. Dies macht Lizzie wohl zu einer dynamischen Implementierung von Lisp für die CLR (Common Language Runtime), mit einer intuitiveren Syntax für C#-/JavaScript-Entwickler. Sie ermöglicht Ihnen, Ihrem statisch kompilierten C#-Code dynamischen Code hinzuzufügen, ohne Tausende von Seiten Dokumentation lesen zu müssen, um eine neue Programmiersprache zu erlernen. Tatsächlich besteht die gesamte Dokumentation für Lizzie aus nur 12 Seiten Text, was bedeutet, dass ein Softwareentwickler Lizzie buchstäblich in etwa 20 Minuten erlernen kann.
Lizzie: JSON für Code
Eines meiner Lieblingsfeatures von Lizzie ist das Fehlen jeglicher Features. Lassen Sie mich anhand einer unvollständigen Liste veranschaulichen, was Lizzie nicht kann. Lizzie kann die folgenden Aufgaben nicht ausführen:
- Lesen aus dem oder Schreiben in das Dateisystem
- Ausführen von SQL-Abfragen
- Abfragen des Kennworts
- Ändern des Status Ihres Computers
Tatsächlich kann ursprünglicher Lizzie-Code nicht böswillig sein (nicht einmal theoretisch)! Dieses Fehlen von Features verleiht Lizzie einige einzigartige Fähigkeiten, die Roslyn- und C#-Skripts nicht bieten.
Im Originalzustand ist Lizzie völlig sicher, sodass Sie Code sicher über ein Netzwerk von einem Computer auf einen anderen Computer übertragen können, so wie Sie JSON zur Datenübertragung verwenden würden. Dann müssen Sie an Ihrem Endpunkt, der Lizzie-Code akzeptiert, explizit die Unterstützung für alle Funktionen implementieren, auf die Ihr Lizzie-Code Zugriff haben soll, damit er für Ihren Anwendungsfall funktioniert. Dies kann eine C#-Methode beinhalten, die Daten aus einer SQL-Datenbank liest, oder die Möglichkeit, Daten in einer SQL-Datenbank zu aktualisieren oder Dateien zu lesen oder zu schreiben. Alle diese Funktionsaufrufe können jedoch verzögert werden, bis Sie sichergestellt haben, dass der Code, der versucht, das zu bewirken, was seine Absicht ist, tatsächlich berechtigt ist, die entsprechende Aktion auszuführen. Somit können Sie Authentifizierung und Autorisierung einfach implementieren, bevor Sie Vorgänge wie „SQL einfügen“, „Datei lesen“ usw. zulassen.
Diese Eigenschaft von Lizzie ermöglicht es Ihnen, einen generischen HTTP REST-Endpunkt zu erstellen, an dem die Clientschicht Lizzie-Code an Ihren Server sendet, der dort dann ausgewertet wird. Sie können dann Ihren Server eine JSON-Antwort erstellen lassen, die er zurück an Ihren Client sendet. Und was noch interessanter ist: Sie können dies sicher implementieren. Sie können einen einzelnen HTTP REST-Endpunkt implementieren, der nur POST-Anforderungen akzeptiert, die Lizzie-Code enthalten, und Ihr gesamtes Back-End buchstäblich durch eine 100-prozentig dynamische und generische Lizzie-Auswertung ersetzen. Auf diese Weise können Sie Ihre gesamte Geschäftslogik und Datenzugriffsschicht in Ihren Front-End-Code verschieben, sodass Ihr Front-End-Code dynamisch Lizzie-Code erstellt, den er zur Auswertung an den Server sendet. Und Sie können dies auf sichere Weise erreichen, indem Sie Ihre Clients authentifizieren und autorisieren, bevor Sie ihnen erlauben, Ihren Lizzie-Code auszuwerten.
Im Grunde genommen wird Ihre gesamte Anwendung plötzlich auf einfache Weise in JavaScript, TypeScript, ObjectiveC usw. erstellt, und Sie können Clients in jeder beliebigen Programmiersprache erstellen, die dynamisch Lizzie-Code erstellt und diesen Code an Ihren Server sendet.
Vorbild Einstein
Als Albert Einstein seine berühmte Gleichung zur Erklärung unseres Universums aufstellte, bestand diese aus nur drei einfache Komponenten: Energie, Masse und Lichtgeschwindigkeit im Quadrat. Diese Gleichung konnte von jedem 14-jährigen Kind mit einem guten Verständnis für Mathematik leicht nachvollzogen werden. Das Verständnis der Computerprogrammierung hingegen erfordert Tausende von Seiten und Millionen, wenn nicht sogar Billionen von Wörtern, Akronymen, Token und Symbolen sowie einen ganzen WikiPedia-Abschnitt über Paradigmen, zahlreiche Entwurfsmuster und eine Vielzahl von Sprachen, die jeweils völlig unterschiedliche Strukturen und Ideen aufweisen und individuelle „wesentliche“ Frameworks und Bibliotheken erfordern, die Sie Ihrer „Lösung“ hinzufügen müssen, bevor Sie mit der Arbeit an Ihrem Domänenproblem beginnen können. Und es wird erwartet, dass Sie all diese Technologien verinnerlicht haben, bevor Sie anfangen können, sich selbst als fortgeschrittenen Softwareentwickler zu bezeichnen. Bin ich der Einzige, der das Problem hier sieht?
Lizzie ist keine Wunderwaffe, und symbolische Delegaten sind es auch nicht, aber sie sind definitiv ein Schritt in Richtung „20 GOTO 10“. Um sich vorwärts zu bewegen, muss man unter Umständen zunächst einen Schritt zurücktreten. Manchmal hilft eine neutrale Betrachtungsweise von außen. Als professionelle Community könnten wir dann vielleicht erkennen, dass die Lösung für unseren derzeitigen Wahnsinn Einfachheit ist und nicht 50 weitere Entwurfsmuster, 15 neue Abfragesprachen, 100 neue Sprachfunktionen und eine Million neue Bibliotheken und Frameworks mit jeweils unzähligen beweglichen Teilen.
Weniger ist immer mehr, also gib mir mehr von diesem Weniger! Wenn Sie auch weniger möchten, besuchen Sie github.com/polterguy/lizzie. Dort finden Sie Lizzie, ganz ohne Typsicherheit, ohne Schlüsselwörter, ohne Operatoren, ohne OOP, und definitiv ist keine einzige Bibliothek und auch kein Framework in Sichtweite.
Zusammenfassung
Der Großteil der Computerbranche tendiert dazu, mit den meisten meiner Ideen nicht einverstanden zu sein. Wenn Sie den durchschnittlichen Softwarearchitekten fragen würden, was er von diesen Ideen hält, würde er Ihnen wahrscheinlich ganze Bibliotheken als Beweis dafür entgegenschleudern, wie falsch ich liege. In der Softwareentwicklung wird beispielsweise davon ausgegangen, dass starke Typisierung gut und schwache Typisierung schlecht ist. Für mich ist Einfachheit jedoch der wichtigste Aspekt, auch wenn dies bedeutet, sich von starker Typisierung zu verabschieden. Denken Sie jedoch daran, dass Konzepte wie Lizzie dazu gedacht sind, Ihren vorhandenen statisch typisierten C#-Code „aufzupeppen“ und nicht zu ersetzen. Selbst wenn Sie die in diesem Artikel vorgestellten Programmierideen nie direkt verwenden, kann das Verständnis der Schlüsselkonzepte Ihnen helfen, Standardcode in einer traditionellen Programmiersprache effektiver zu schreiben, und Ihnen helfen, auf das Ziel der Einfachheit hinzuarbeiten.
Eine Lektion in Programmiergeschichte
Früher, als ich noch Junior-Entwickler war, habe ich 3-schichtige Anwendungen erstellt. Das Ziel war, die Datenschichten von den Geschäftslogikschichten und den Benutzeroberflächenschichten zu trennen. Das Problem besteht darin, dass Sie mit zunehmender Komplexität der Front-End-Frameworks gezwungen sind, eine 6-schichtige Anwendungsarchitektur zu erstellen. Zunächst müssen Sie eine 3-schichtige serverseitige Architektur erstellen, dann eine 3-schichtige clientseitige Architektur. Und als ob das noch nicht genug wäre, müssen Sie dann Ihren Code nach Java, ObjectiveC usw. portieren, um alle möglichen Clients da draußen zu unterstützen. Ich entschuldige mich für meine Unverblümtheit, aber diese Art von Architektur ist das, was ich als „von Irrsinn geprägten Entwurf“ bezeichne, weil sie die Komplexität von Apps so weit steigert, dass sie häufig fast nicht mehr zu verwalten sind. Eine einzige Änderung in der Benutzeroberfläche des Front-Ends erstreckt sich oft über 15 Architekturschichten und vier verschiedene Programmiersprachen und zwingt Sie, Änderungen in all diesen Schichten vorzunehmen, nur um einer Datentabelle im Front-End eine einfache Spalte hinzuzufügen. Lizzie löst dies, indem Ihrem Front-End erlaubt wird, Code an Ihr Back-End zu senden, den Ihr Back-End auswertet und als JSON an Ihren Client zurückgibt. Klar verlieren Sie die Typsicherheit, aber wenn Typsicherheit auf Kosten der Verknüpfung der verschiedenen Schichten Ihrer Anwendungen geht, sodass sich Änderungen an einer Stelle auf alle anderen Schichten in Ihrem Projekt auswirken, sind die Kosten für Typsicherheit einfach nicht gerechtfertigt.
Ich begann mit der Programmierung, als ich 8 Jahre alt war. Das war 1982 auf einem Oric 1. Ich erinnere mich noch genau an das erste Programm, das ich geschrieben habe. Das sah so aus:
10 PRINT "THOMAS IS COOL"
20 GOTO 10
Wenn ein 8-jähriges Kind heute diese Erfahrung unter Beachtung aller bewährten Methoden mit einem clientseitigen Framework wie Angular und einem Back-End-Framework wie .NET reproduzieren wollte, müsste dieses Kind wahrscheinlich Tausende von Seiten technischer Informatikliteratur verinnerlicht haben. Im Gegensatz dazu begann ich mit einem Buch mit etwa 300 Seiten und einer Handvoll Computerzeitschriften. Bevor ich es bis auf Seite 100 schaffte, hatte ich im Alter von 8 Jahren mein eigenes Computerspiel erstellt. Es tut mir leid, wenn mich das alt erscheinen lässt, aber das ist keine Evolution und Verbesserung, das ist „Devolution“ und Wahnsinn. Und ja, bevor Sie anfangen, Ihre Einwände fieberhaft aufzuschreiben: Dieses Problem wurde von Professoren und anderen Akademikern, die alle viel klüger sind als ich, wissenschaftlich erforscht und neutral untersucht und bestätigt.
Tatsache ist, dass die Computerprogrammierung als (menschlicher) Beruf am Rande des Aussterbens steht, denn die Komplexität, die ständig hinzugefügt wird, kann bald den Punkt erreichen, an dem sie die Fähigkeit des menschlichen Gehirns zur Erstellung von Computerprogrammen übersteigt. Da die Programmierung aus kognitiver Sicht so anspruchsvoll wird, kann es sein, dass schon in 10 Jahren kein Mensch mehr dazu in der Lage sein wird. Gleichzeitig ist der Mensch von Tag zu Tag mehr und mehr auf Computer und Software angewiesen. Nennen Sie mich hier altmodisch, aber ich mag die Idee, dass ein Mensch irgendwo da draußen in der Lage ist, die Dinge zu verstehen, die für mein Glück, meine Existenz und meine Lebensqualität entscheidend sind.
Thomas Hansen hat sich schon im Alter von 8 Jahren mit dem Erstellen von Software beschäftigt. Damals (im Jahr 1982) begann er mit dem Schreiben von Code auf seinem Oric 1-Computer. Er bezeichnet sich selbst als Zen-Computerprogrammierer, der die Komplexität moderner Programmierung verringern möchte und sich weigert, unreflektiert Glaubenssätze hinsichtlich technologischer Dogmen zu verkünden. Hansen arbeitet für Bright Code in Zypern und erstellt dort FinTech-Software.
Unser Dank gilt dem folgenden technischen Experten bei Microsoft für die Durchsicht dieses Artikels: James McCaffrey