© Evannovostro/Shutterstock.com
Unter dem Druck der Ereignisse - Teil 3

Akkatecture und ActiveMQ


Die diversen in .NET enthaltenen Primitiva ermöglichen die Realisierung durchaus komplizierter Event-Systeme. Nicht alles, was technisch machbar ist, ist in der Praxis aber auch sinnvoll.

Diese kleine Binsenweisheit gilt in besonderer Weise im Bereich der Event-orientierten Programmierung. Ist man als Entwickler erst einmal von den Vorteilen dieser Vorgehensweise überzeugt, so warten sprichwörtlich Dutzende von Produkten nur darauf, das Tooling bereitzustellen. In diesem Artikel möchte ich zwei Kandidaten vorstellen.

Akkatecture herbei

Sucht man nach Frameworks für die Event-getriebene Programmierung, so findet man nur allzu häufig Tausendsassas, die für verschiedene Programmiersysteme gleichermaßen geeignet sein wollen. Als Erstes sehen wir uns das Akkatecture Framework an. Das mit einer aktiven Community ausgestattete Produkt ist ausschließlich für .NET vorgesehen, weshalb es in vielerlei Hinsicht am bequemsten ist. Zudem gilt, dass das Fehlen von Bindings für Java und Co. dafür sorgt, dass der auf GitHub [1] bereitstehende Quellcode vergleichsweise kompakt ausfällt. Andererseits legt es dem Entwickler ob der CQRS-Ausrichtung zumindest bis zu einem gewissen Grad Schienen in Bezug auf das Design der Applikationslogik an. Im Bereich der Testumgebung gibt uns das Entwicklerteam freie Hand. Als Programmiersystem kommt .NET Core zum Einsatz, die Zielversion ist das Standard Framework 2.0.

In den folgenden Schritten wird eine aktuelle Version von Visual Studio 2019 als Arbeitsumgebung verwendet, die eine Applikation auf Basis der Vorlage Konsolen-App (.NET Core) erstellt. Nach der erfolgreichen Generierung des Projektskeletts wechseln wir im ersten Schritt in die NuGet-Paketverwaltung, wo wir nach dem String Akkatecture suchen. Visual Studio reagiert darauf mit der in Abbildung 1 gezeigten Paketliste. Wir benötigen allerdings nur das oberste Paket, das zum Zeitpunkt der Drucklegung dieses Magazins in der Version 0.6.3 vorliegt. Es kann wie jedes andere Paket in unserer Solution installiert werden.

hanna_events_teil3_1.tif_fmt1.jpgAbb. 1: Das Deployment erfolgt automatisiert

Akkatecture arbeitet im Hintergrund mit dem System des Event Sourcings [2], weshalb wir im ersten Schritt Hilfsstrukturen anlegen müssen. Zur Erklärung sei an dieser Stelle vorausgeschickt, dass ein gemäß den Regeln des Event Sourcings aufgebautes Programm im Prinzip eine große Event-Sammlungsmaschine darstellt. Der aktuelle Zustand eines beliebigen Elements wird dadurch ermittelt, dass man alle es beeinflussenden Ereignisse nacheinander auf den Ausgangszustand anwendet, um danach das fertige Ergebnis abzuernten. Ganz unten in der Komplexitätshierarchie stehen dabei als Value Objects bezeichnete Klassen. Sie repräsentieren gemäß dem folgenden Aufbau einen mehr oder weniger beliebigen Zustand. Im Fall unserer Applikation handelt es sich dabei beispielsweise um den Wert, der in der SUSCounter-Klasse vorzuhalten bzw. anzutreffen ist:

public class SUSCounter : SingleValueObject<int> { public SUSCounter(int value) : base(value) { } }

Die Identity-Klasse ist im Großen und Ganzen ähnlich, unterscheidet sich aber insofern vom soeben besprochenen Value Object, dass sie statt eines Nutzwerts eine weltweit einzigartige ID repräsentiert, die zur Identifikation von Zustandsspeichern herangezogen werden kann. Im Fall unseres kleinen Projektbeispiels sieht sie folgendermaßen aus:

public class SUSAggregateID : Identity<SUSAggregateID> { public SUSAggregateID(string value) : base(value) { } }

Das Verwenden von Value als Speicher- bzw. Parametername ist keine Marotte des Autors, sondern manche Akkatecture-Primitiva werden mit einem Serialisierer ausgeliefert, der diesen Feldnamen erwartet. Darauf folgt eine Zustandsvariable, die die beiden soeben angelegten Elemente in eine Beziehung zueinander setzt:

public class SUSAggregateState : AggregateState<SUSAggregate, SUSAggregateID> { public SUSCounter StorageVal{ get; set; } }

Lohn dieser Vorbereitungshandlungen ist dann die Einführung der eigentlichen Aggregatklasse, die sich im Fall unseres Projektbeispiels folgendermaßen präsentiert:

public class SUSAggregate : AggregateRoot<SUSAggregate, SUSAggregateID, SUSAggregateState> { public SUSAggregate(SUSAggregateID aggregateId) : base(aggregateId) { } }

Kritisch ist an dieser an sich einfachen Deklaration nur, dass den Entwickler nichts daran hindert, mehrere Instanzen von SusAggregate anzulegen, die eine identische ID aufweisen. Zur Umgehung dieses Problems führt Akkatecture das Konzept des Managers ein, einer Art Masterklasse, die sich um die Erzeugung und die Verwaltung der einzelnen Aggregate kümmert und dabei quasi nebenbei diverse Regeln auferlegt:

public class SUSManager : AggregateManager<SUSAggregate, SUSAggregateID, Command<SUSAggregate, SUSAggregateID>> { }

Zustandsänderung durch Kommandos und Ereignisse

Die Errichtung der (zugegebenermaßen umfangreichen) Hilfsinfrastruktur ist kein Selbstzweck. Als Nächstes können wir uns darum kümmern, die in den Aggregaten enthaltenen Werte anzupassen. In der Wel...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang