März 2017

Band 32, Nummer 3

Muster – Active Events: ein Entwurfsmuster anstelle von Dutzenden

Von Thomas Hansen | März 2017

Anmerkung der Redaktion:

Als ich den Senior Contributing Editor James McCaffrey von MSDN Magazine bat, den vorläufigen Entwurf dieses Artikels zu prüfen, war er bezüglich einiger Meinungen und Vorstellungen, die vom Autor vertreten wurden, ziemlich schockiert. In den meisten Fällen hätte dies das Aus für einen Artikelentwurf bedeutet. Doch wie McCaffrey anmerkt, werden neue Ideen bei der Softwareentwicklung allzu häufig einfach nur deshalb verworfen, weil sie neu sind. McCaffrey hält noch immer viele Aussagen in diesem Artikel für frevelhaft. Wir sind uns aber beide einig, dass sie möglicherweise ein Nachdenken über Softwareentwürfe und Methodikparadigmen provozieren können. – Michael Desmond

Seit es Software gibt, gibt es Software, die fehlerhaft ist. Studien belegen, dass 25 Prozent aller Projekte komplett durchfallen, während die Fehlerfreiheit bei 50 Prozent als „fraglich“ bezeichnet werden kann. Stellen Sie sich vor, für einen KFZ-Hersteller würden die gleichen statistischen Werte gelten: 25 Prozent der Fahrzeuge würden nicht anspringen oder beim Einschalten der Scheinwerfer explodieren, während 50 Prozent nur eine Spitzengeschwindigkeit von 40 Stundenkilometern erreichen bzw. 56 Liter Treibstoff pro Kilometer verbrauchen. Ein weiterer wichtiger Aspekt: Was wäre, wenn die Käufer nicht einmal wüssten, welche Fahrzeuge funktionieren, bevor sie viel Geld dafür bezahlen? Dies entspricht in etwa dem heutigen Stand der Softwareentwicklung.

Verschiedene Lösungen wurden zur Verbesserung der tatsächlichen Lage vorgeschlagen. Keine davon bezieht sich auf die Grundursache: den Code! Meiner Meinung nach kann die Ursache für die Fehlerhaftigkeit von Softwareprojekten im Allgemeinen auf das gleiche Problem zurückgeführt werden: auf Spaghetticode. Der Grund, warum der Code einen so erbärmlichen Zustand aufweist: Änderungen sind schwierig bis unmöglich. Daher wurden Methodiken wie eXtreme-Programmierung und Agile-Softwareentwicklung empfohlen. Mit beiden Verfahren kann jedoch nicht wirklich besserer Code erstellt werden. Durch Agile-Programmierung wird nicht wie von Zauberhand Spaghetticode vermieden. Damit das Agile-Prinzip fasst, müssen Sie in der Lage sein, Ihre Concerns in atomische Bausteine zu trennen.

Die hier vorgestellten Ideen sind keine Alternative zu Agile- oder anderen ähnlichen Methodiken. Agile ist schließlich ein Verwaltungsframework und kein architektonisches Entwurfsmuster. Stattdessen schlage ich eine Entwurfsmethodik vor, die eine einfachere Anwendung der Agile-Prinzipien erlaubt, weil Sie sich schon im Vorfeld auf Änderungen vorbereiten können. Während der letzten Jahre habe ich ein Entwurfsmuster entwickelt, das ich als „Active Events“ bezeichne. Mit diesem Entwurfsmuster können Sie kleine, wiederverwendbare Komponenten erstellen, die einfach erweitert, geändert, wiederverwendet und durch andere Bestandteile ausgetauscht werden können. Es ermöglicht eine andere Einstellung zu Software, damit Sie Ihren Code „orchestrieren“ können (fast so, als bestünden die Einzelteile aus Lego-Steinen). Möglicherweise glauben Sie, dass dies in etwa dem Schreiben von Code mit einer objektorientierten Programmiersprache (OOP) entspricht. Active Events unterscheiden sich jedoch erheblich von der traditionellen OOP.

Überprüfen Sie Ihren eigenen Code

Tun Sie mir einen Gefallen: Öffnen Sie die letzte Projektmappe, die Sie in Visual Studio erstellt haben, und überprüfen Sie Ihr Abhängigkeitsdiagramm. Wie viele Projekte und Klassen können aus Ihrer Projektmappe extrahiert werden? Wie viele Klassen könnten in zukünftigen Projekten wiederverwendet werden? Wie viele Klassen könnten Sie durch andere Klassen ersetzen, ohne die Funktionalität Ihrer Software zu zerstören?

Ich vermute, dass Ihre Projekt- und Klassenabhängigkeiten so wie in den meisten anderen Projekten aussehen. Höchstwahrscheinlich ähnelt das Abhängigkeitsdiagramm Ihres Projekts Spaghetticode. Entschuldigen Sie, dass ich so rücksichtslos ehrlich bin, genau dies sind jedoch meine Erfahrungen. Aber: Entspannen Sie sich, Sie sind nicht der einzige Betroffene. Auch wenn ich nicht über verlässliche statistische Daten verfüge, wage ich zu behaupten, dass 98 Prozent des Codes weltweit das gleiche Problem aufweist. Abgesehen davon würde ich Sie nicht mit diesem Problem konfrontieren, wenn ich keine Lösung hätte.

Wenn Sie diese ganzen Abhängigkeiten irgendwie entwirren und wiederverwendbare Komponenten erstellen könnten, in denen nicht einzelne Teile Ihres Codes auf andere Teile verweisen, würde sich Ihr Programmiererleben erheblich verbessern. Wenn Ihre Projekte und Klassen nicht so verschlungen wären, wie sie es zurzeit sind, könnten Sie einzelne Teile einfacher austauschen. Wenn Sie Ihre Klassen entwirren könnten, könnten Sie sie in zukünftigen Projekten wiederverwenden. Wenn Ihre Projekte nur minimale Abhängigkeiten enthielten, würden Sie über eine Sammlung von Komponenten verfügen, deren Wiederverwendbarkeit wahrscheinlicher als bei einem monolithischen Monster wäre. Active Events ermöglichen das Arbeiten mit null Abhängigkeiten in Ihren Klassen und Projekten. Was die Softwareverwicklung betrifft, ist null der einzige akzeptable Wert!

Wie funktionieren Active Events?

Das Entwurfsmuster von Active Events ist tatsächlich erstaunlich leicht zu verstehen. Anstatt Schnittstellen zu erstellen, um die Implementierung und den Consumer der Programmlogik zu trennen, markieren Sie Ihre Methoden einfach durch ein Attribut. Im Folgenden finden Sie ein Beispiel:

[ActiveEvent (Name = “foo.bar”)]
protected static void foo_bar(ApplicationContext context, ActiveEventArgs e)
{
  var input = e.Args[“input”].Value as string;
  e.Args.Add(“output”, “Hello there ” + var);
}

Diese Syntax stammt aus Phosphorus Five, einer von mir erstellten Open Source Active Event-Implementierung. Weitere Informationen finden Sie unter „Software, die fast nicht vorhanden ist“.

Das Aufrufen einer Methode, die mithilfe des Active Event-Paradigmas definiert wurde, ist ebenfalls einfach. Anstatt Ihre Methode direkt aufzurufen, rufen Sie sie indirekt über ihren Active Event-Namen auf:

/* ... some method in another assembly ... */
var args = new Node ();
args.Add ("input", "John Doe");
/* context is your ApplicationContext instance, which keeps
   track of your Active Events */
var result = context.Raise ("foo.bar", args)["output"].Value as string;

Durch den Aufruf von „Raise“ wird das Active Event „foo.bar“ aufgerufen. Beachten Sie, dass es null Abhängigkeiten zwischen dem Ort des Aufrufs Ihres Active Event und dessen Implementierung gibt. Außerdem werden keine allgemeinen Klassen gemeinsam verwendet. Es werden nur Daten in die Ereignisse und aus den Ereignissen übergeben. Beachten Sie außerdem, dass alle Active Events die gleiche Signatur aufweisen. Klassen, Schnittstellen und Methoden treten daher etwas in den Hintergrund und stehen nicht im Mittelpunkt des Quellcodes.

Das Laden der Active Event-Komponenten ist völlig dynamisch und kann über eine Liste von Assemblys erfolgen, auf die in der Konfigurationsdatei Ihrer Anwendung verwiesen wird, oder durch automatisches Laden aller DLLs aus einem Ordner und Registrieren dieser DLLs als Active Event-Handler. Intern traversiert der Active Event-„Kernel“ während des Ladens alle Typen in Ihrer DLL und speichert einen MethodInfo-Verweis auf die Active Event-Methoden in einem string/MethodInfo-Wörterbuch. Dieses Wörterbuch wird später während des Aufrufs Ihres Ereignisses verwendet. Wenn Sie einen Geltungsbereich für ein Active Event festlegen oder diesem einen Zustand zuordnen möchten, können Sie dynamisch eine Instanz einer Klasse als Active Event-Listener hinzufügen und eine Instanzmethode anstelle einer statischen Methode als Ereignissenke des Active Event verwenden. Diese Vorgehensweise wurde z. B. im plugins/p5.web-Projekt in Phosphorus Five gewählt.

Auf diese Weise wird eine Umgebung erstellt, in der Ihre verschiedenen Komponenten einfach Bausteine sind, die sich gegenseitig indirekt aufrufen. Sie können daher jede einzelne Active Event-Assembly auf einfache Weise durch eine andere Implementierung ersetzen. Auch das vollständige Ändern der sich ergebenden Anwendung ist ganz einfach. Sie ändern nur eine Konfigurationseinstellung oder ersetzen eine DLL durch eine andere. Ebenso simpel ist das Ändern der Zeichenfolge „foo.bar“ in „foo.bar-2“. Trotz dieser Einfachheit kann jede Assembly in Ihrer Projektmappe weiterhin Methoden in Ihren anderen Assemblys aufrufen, ohne auch nur eine POD-Struktur (Plain Old Data) mit der anderen Seite gemeinsam zu verwenden. Ihnen steht im Prinzip eine Konstante des Typs „eine weitere Abstraktionsschicht“ zur Verfügung. Man könnte auch sagen, dass Ihre Komponenten „atomisiert“ wurden.

Vergleichen wir diese Vorgehensweise mit den erforderlichen Aktionen in traditioneller OOP. Wenn Sie einen Ansatz verwenden, bei dem der Entwurf eine Schnittstelle vorsieht, arbeiten Sie mit einer Schnittstelle und mindestens einer Implementierung der Schnittstelle. Abhängig vom jeweiligen Szenario verwenden Sie ggf. ein abstraktes Factoryschema zum Erstellen von Objekten. Dies ergibt also zwei Klassen und eine Schnittstelle, die wohl in mindestens 30 Codezeilen beschrieben werden. Wenn Sie ein echtes Plug-In aus Ihrer Implementierung erstellen möchten, wäre das Ergebnis außerdem ein Projekt für die Consumerseite, die das Plug-In nutzt, sowie ein Projekt für die Implementierungsseite: das Projekt mit Ihrer Klasse, das die Schnittstelle implementiert. Wenn Sie einen vollständig modularen Ansatz wählen, können Sie ein drittes Projekt verwenden, das Ihre Schnittstelle und ggf. Ihre abstrakte Factory enthält. Wenn Sie sich das Ergebnis ansehen, stellen Sie fest, dass mindestens drei komponentenübergreifende Verweise in Ihren drei Projekten vorhanden sind. Außerdem können Sie die Eingaben bzw. Ausgaben Ihrer Schnittstelle nicht hinzufügen oder ändern, ohne alle drei Projekte ändern zu müssen. Vergleichen Sie dieses Ergebnis mit der einzeiligen Lösung ganz ohne Verweise aus dem Active Event-Beispiel, bei dem es sogar ganz egal ist, welche Eingabe- oder Ausgabeargumente bereitgestellt werden. Die traditionelle Vorgehensweise weist wahrscheinlich mindestens die doppelte Anzahl von Codezeilen auf. Dies führt meiner Erfahrung nach zu einem weitaus komplexeren Abhängigkeitsdiagramm, einem wenig flexiblen Ergebnis und wesentlich komplexerem Code.

OOP ist nicht OO

Ich mag OOP sehr gern. Es ist ein wunderbares Paradigma, mit dem Sie einfach Codelogik, Methoden und Daten kapseln können. Man kann jedoch behaupten, dass OOP nicht alle Codierungsprobleme vollständig gelöst hat. Unter bestimmten Umständen müssen Sie bei der Verwendung von OOP mehrere Klassen definieren, die viel zu häufig eng gekoppelt sind und zu Abhängigkeiten führen.

Bei OOP müssen Sie die Signatur einer Methode kennen. Sie benötigen Zugriff auf eine Schnittstelle und müssen wissen, wie eine Instanz dieser Schnittstelle erstellt wird. Außerdem müssen Sie häufig Typen für den Consumer und die Implementierung Ihrer Schnittstelle gemeinsam verwenden. Auf diese Weise entstehen Abhängigkeiten zwischen den Bausteinen. Bei OOP müssen häufig sogar mehrere Klassen erstellt werden, um ein einfaches Plug-In „Hello World“ zu generieren. Wenn Sie eine OOP-Schnittstelle ändern, müssen Sie ggf. mehrere Assemblys erneut kompilieren, wenn Sie die Schnittstelle nicht sehr sorgfältig entworfen haben. Das Ergebnis kann sein, dass ein Großteil des Codes aus abstrakten Schnittstellen und Codebausteinen besteht. Oder Sie müssen die Tatsache einfach akzeptieren, dass eine Änderung an einer Schnittstelle ggf. zu einem Dominoeffekt führt und erhebliche weitere Codeänderungen erfordert. Wenn etwas extrem komplex ist oder umfangreiche mühselige und repetitive Arbeiten erfordert, sollte Ihr Bauch Sie warnen, dass hier etwas falsch läuft.

Stellen Sie sich die folgende Frage: „Wenn OOP die Möglichkeit bietet, objektorientierte (OO) Software zu erstellen, warum ist dann die erfolgreiche Verwendung so schwierig“? Meiner Meinung nach ist OOP nicht identisch mit OO. Wenn es so wäre, müssten Sie nicht so viele Entwurfsmuster kennen, um die Vorteile umfassend nutzen zu können.

Ich glaube, dass für OOP (wie zurzeit praktiziert) verschiedene grundlegende Einschränkungen gelten. Alle diese Entwurfsmuster, die implementiert werden müssen, um OOP adäquat verwenden zu können, sind nur ein Symptom für ein viel fundamentaleres Problem in der Architektur: die Unmöglichkeit, OO-Software bereitstellen zu können. Active Events beheben diese Probleme, und zwar nicht durch Implementieren besserer abstrakter Factorys oder neuer Klassenkonstrukte, sondern durch Ändern der eigentlichen Art und Weise, wie Methoden und Funktionen aufgerufen werden. OOP spielt dabei keine Rolle mehr. Damit OO-Software erstellt werden kann, sind keine neuen Verfahren zum Instanziieren abstrakter Klassen und Schnittstellen erforderlich, sondern ein anderer Mechanismus zum Aufrufen von Funktionalität sowie die Möglichkeit, mit einer gemeinsamen Signatur für jede Schnittstellenmethode arbeiten zu können, die aufgerufen wird.

Software, die fast nicht vorhanden ist

Ein Beispiel dafür, wie weit Sie mit Active Events gehen können, finden Sie im Projekt Phosphorus Five unter github.com/polterguy/phosphorusfive. Phosphorus Five ist ein großes Softwareprojekt. Die Active Events-Implementierung umfasst jedoch nur ungefähr 1.000 Codezeilen. Sie finden die Active Events-Implementierung in core/p5.core.

In diesem Projekt habe ich eine neue Programmiersprache (Hyperlambda) zum Erstellen von Active Events-Hooks erstellt. Auf diese Weise kann ich auf Wunsch die Implementierung meiner for-each- und while-Anweisungen ändern. Ich kann außerdem meine else-Anweisungen horizontal hochskalieren, damit sie auf einem anderen Server ausgeführt werden. Und ich kann auf einfache Weise die Programmiersprache so erweitern, dass ich eigene domänenspezifische Schlüsselwörter erstellen kann, mit denen ich alle Aufgaben ausführen kann, die für meine Domänenprobleme erforderlich sind.

Außerdem habe ich ein Dateiformat erstellt, mit dem eine Knotenstruktur dynamisch wie ein Textbaustein deklariert und dann auf meinem Datenträger oder in meiner Datenbank gespeichert werden kann. Darüber hinaus habe ich meine eigene Ausdruckssyntax erstellt, mit der ich auf beliebige Knoten in jedem Teil meines Baums verweisen kann. Das Ergebnis wird von mit gern als „Nichtprogrammiersprache“ bezeichnet, die jedoch zu 100 Prozent gemäß Turing vollständig ist. Meine Nichtprogrammiersprache wird weder dynamisch interpretiert noch statisch kompiliert und kann unter Umständen mit fünf Codezeilen Ergebnisse erzielen, für die in anderen Programmiersprachen Hunderte von Codezeilen erforderlich wären.

Mit Active Events sowie Hyperlambda und einer verwalteten AJAX-Bibliothek (die nur ein AJAX-Widget enthält) habe ich etwas kreiert, von dem ich nicht einmal weiß, wie ich darüber reden soll, ohne Begriffe wie „Webbetriebssystem“ zu verwenden. Phosphorus Five enthält ungefähr 30 Projekte ohne Verweise zwischen den verschiedenen Plug-Ins. Alle Projekte verweisen einfach auf p5.core (die Active Events-Implementierung) und p5.exp (das Ausdrucksmodul). Das ist alles. Das Websitehauptprojekt p5.website im Kernordner enthält nur ein einfaches Containerwidget und fast keine Programmlogik. Alle Plug-Ins werden während des Anwendungsstarts dynamisch in „Global.asax“ geladen. Dennoch rufen alle Projekte dynamisch Funktionen in anderen Projekten auf. Keine Verweise, keine Abhängigkeiten, keine Probleme!

Zurück zu den Grundlagen

Die Lösung liegt immer im Problem. Einige der Probleme, die OOP beheben sollte (globale Funktionen und Daten) sind paradoxerweise die Lösung für die Probleme, die OOP unbeabsichtigt verursacht hat. Wenn Sie sich das Entwurfsmuster von Active Events ansehen, fällt Ihnen zunächst auf, dass es in gewissem Ausmaß ein Schritt zurück zu den Grundlagen ist, jedoch mit globalen Funktionen anstelle von Methoden und Klassen. Da jedoch keine Signaturen oder Typen zwischen dem Consumer und der Implementierung eines aktiven Ereignisses bekannt sein bzw. gemeinsam verwendet werden müssen, ähnelt die Umgebung weitaus mehr einer Blackbox als bei OOP. Auf diese Weise kann z. B. „SaveToDatabase“ ganz einfach durch „InvokeWebService“ oder „SaveToFile“ ausgetauscht werden. Keine Schnittstellen, keine Typen, keine POD-Strukturen, keine Klassen und nur eine gemeinsam verwendete Signatur. Nur gute alte, einfache Daten. Data im Eingang und Daten im Ausgang!

Polymorphie ist so einfach wie das Ändern einer Zeichenfolge. Das folgende Beispiel zeigt, wie Polymorphie mithilfe von Active Events implementiert wird:

string myEvent = "some-active-event";
if (usePolymorphism) {
  myEvent = "some-other-active-event";
}
context.Raise (myEvent);

Mir ist bewusst, dass dieses Polymorphiekonstrukt einem erfahrenen Architekten lächerlich naiv und einfach vorkommen muss. Seine Einfachheit ist jedoch der Grund, warum es funktioniert. Mit Active Events können Sie den Namen einer Methode oder Funktion aus einer Datenbank, einer Konfigurationsdatei oder sogar von einem Benutzer abrufen, der deren Namen über ein Textfeld in Ihrem Formular bereitstellt. Sie können dies als eine Variation von Polymorphie betrachten, für die keine expliziten Klassen erforderlich sind. Dies ist Polymorphie ohne Typen. Dies ist Polymorphie, die dynamisch während der Laufzeit ermittelt wird. Indem alle traditionellen Vorstellungen von Polymorphie aus der Gleichung entfernt werden und ein Refactoring der Essenz von Polymorphie erfolgt, erhalten Sie als Ergebnis tatsächlich funktionierende Polymorphie: Kapselung und Polymorphie ohne Klassen, Typen, Schnittstellen oder Entwurfsmuster. Das Verketten von Active Events ist so einfach wie das Kombinieren von Atomen zu Molekülen. Das ist agile Software!

Node.cs, der letzte Diagrammtyp, den Sie jemals benötigen

Mit Active Events senden Sie ausschließlich Daten in Ihre aktiven Ereignisse und aus Ihren aktiven Ereignissen. Auf diese Weise erfolgt die lose Koppelung der Komponenten. Zu diesem Zweck benötigen Sie eine Datenklasse. Dies ist der einzige erforderliche Diagrammtyp bei der Verwendung eines Active Events-Paradigmas. Ihre Klasse muss in der Lage sein, als Wrapper für alle möglichen Felder und Eigenschaften aus allen möglichen Klassen zu fungieren. In Phosphorus Five wird diese Klasse als „Node.cs“ bezeichnet. Es handelt sich einfach um ein Diagrammobjekt mit einem Entwurf vom Typ Schlüssel/Wert/untergeordnetes Element.

Der Schlüssel für die erfolgreiche Implementierung von Active Events liegt darin, dass die Node-Klasse das einzige Argument ist, das Active Events als Eingabe annehmen und als Ausgabe zurückgeben darf. Daher ist es möglich, fast alle Klassen auf effiziente Weise auf ein POD-Diagrammobjekt vom Typ Schlüssel/Wert/untergeordnetes Element zu reduzieren. Auf diese Weise (in Kombination mit dem dynamischen Laden der Active Events-Assemblys) wird die Anzahl der Abhängigkeiten zwischen Projekten erheblich verringert.

Die Node.cs-Implementierung muss in der Lage sein, einen Schlüssel oder Namen, einen Wert, der ein beliebiges Objekt sein kann, sowie eine „untergeordnete“ Sammlung von Knoten anzunehmen. Wenn Ihre Node-Klasse mit diesen Einschränkungen kompatibel ist, können Sie auf einfache Weise fast alle möglichen Objekte in eine Node-Instanz transformieren. Entwicklern, die mit JSON oder XML vertraut sind, fallen die Ähnlichkeiten an diesem Punkt bestimmt auf. Das folgende Beispiel enthält einfachen Pseudocode, der die Node-Klassenstruktur zeigt:

class Node
{
  public string Name;
  public object Value;
  public List<Node> Children;
}

Intern können Sie in Ihren Komponenten so viel OOP wie gewünscht verwenden. Wenn eine Komponente jedoch Programmlogik in einer anderen Komponente aufrufen muss, müssen alle Eingabedaten irgendwie in eine Node-Instanz transformiert werden. Wenn Informationen von Active Events zurückgegeben werden, muss der gleiche Vorgang ausgeführt werden. Innerhalb Ihrer Komponenten steht Ihnen jedoch die Verwendung von beliebigen gewünschten Klassen, Schnittstellen, abstrakten Factorys, Facadekomponenten, Singleton-Elementen und Entwurfsmustern frei. Extern gibt es nur den Knoten, und Active Events wird zur Brücke zwischen den einzelnen Komponenten. Betrachten Sie Active Events als das Protokoll und die Knoten als seine Daten, wenn dieses Bild Ihnen hilft, die Beziehung mental zu verstehen.

Zusammenfassung

Active Events soll zwar die meisten zurzeit verwendeten Entwurfsmuster ersetzen, ist aber auch keine einfache Universallösung. Diese Technologie bringt unter anderem auch Mehraufwand mit sich. Anstatt Methoden direkt aufzurufen, muss beispielsweise ein Nachschlagevorgang in einem Wörterbuch ausgeführt werden. Außerdem verwenden die Methoden in gewissem Ausmaß Reflektion. Diese indirekten Methodenaufrufe sind möglicherweise um Größenordnungen kostenintensiver als der traditionelle virtuelle Methodenaufruf. Außerdem müssen Ihre Objekte in Knoten und Daten transformiert werden, wenn eine Schnittstelle mit anderen Komponenten verwendet wird.

Aktive Ereignisse sollen jedoch nicht ersatzweise für alle Aufgaben verwendet werden, die Sie ausführen. Die Idee hinter diesem Entwurfsmuster ist das Bereitstellen besserer Schnittstellen zwischen Komponenten, und für diesen Zweck steht der Leistungsmehraufwand nicht im Vordergrund. Es ist vollkommen irrelevant, ob 5 CPU-Zyklen oder 500 CPU-Zyklen zum Aufrufen Ihrer SaveToDatabase-Methode erforderlich sind, wenn die eigentliche Implementierung 5.000.000 CPU-Zyklen benötigt! Donald Knuth hat einmal Folgendes gesagt: „Vorzeitige Optimierung ist die Wurzel alles Bösen“.

Jedes Mal, wenn Sie planen, eine Schnittstelle zu schreiben, sollten Sie sich fragen, ob es besser wäre, stattdessen ein aktives Ereignis zu erstellen. Sobald Sie einige Erfahrungen mit Active Events gesammelt haben, wird die Antwort auf diese Frage wahrscheinlich „möglicherweise ja“ lauten. Mit Active Events verlieren Schnittstellen und abstrakte Klassen größtenteils an Bedeutung.

Ich weiß, dass dies wie eine absurd gewagte Aussage klingt, aber sehen Sie sich das Phosphorus Five-Projekt an, das ich unter „Software, die fast nicht vorhanden ist“ vorgestellt habe. In Hyperlambda (der Sprache, die ich für Active Events erstellt habe) kann ein Objekt eine Datei, ein Ordner, ein Lambdarückruf, ein Teil eines Node-Diagrammbaums, eine Textzeichenfolge aus einer Datenbank oder ein über HTTP gesendeter Datenstrom sein. Und alle Objekte können so ausgeführt werden, als würde es sich um für Computer verständliche Ausführungsbäume handeln. In Hyperlambda könnten Sie theoretisch die Zahl 42 ausführen.

Ich habe mir vor mehr als sieben Jahren erstmals über Active Events Gedanken gemacht und war intuitiv von der inneren Schönheit dieses Konzepts überzeugt. Das Problem besteht darin, dass Active Events 60 Jahre konventioneller Programmierweisheit in Frage stellt. Active Events werden zu dem Punkt, an dem selbst für unsere besten bewährten Methoden ein Refactoring stattfinden muss. Es hat sieben Jahre gedauert, bis ich alles bisher Gelernte ignorieren und meiner Intuition vertrauen konnte. Das größte Problem bei Active Events ist tatsächlich nicht ihre Implementierung, sondern Ihr Kopf. Die Tatsache, dass ich Phosphorus Five fünf Mal komplett neu erstellt habe, ist Beweis genug.

Im ersten Entwurf dieses Artikels habe ich Dutzende von Analogien verwendet. Indem ich auf Ihre Vorkenntnisse in anderen Bereichen (z. B. Physik und Biologie) verwies, wollte ich Sie von der Überlegenheit von Active Events überzeugen. In meinem zweiten Entwurf habe ich versucht, Sie zu provozieren. Ich wollte Sie auf diese Weise motivieren, mir zu beweisen, dass ich Unrecht habe. Sie sollten z. B. nach Fehlern in meinen Aussagen suchen. Natürlich ohne welche zu finden. In meinem dritten und endgültigen Entwurf habe ich mich entschieden, Sie nur mit Active Events vertraut zu machen. Wenn Sie Ihren Kopf dazu bringen können, meinen Gedankengängen zu folgen, wird Active Events das letzte Entwurfsmuster sein, das Sie jemals erlernen müssen.


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. Gelegentlich erstellt er Code, der mehr nützt als schadet. Seine Lieblingsthemen sind das Web, AJAX, Agile-Methodiken und Softwarearchitektur.

Unser Dank gilt dem folgenden technischen Experten bei Microsoft für die Durchsicht dieses Artikels: James McCaffrey