Gemeinsam mehr erreichen

CQRS und DDD

CQRS und DDD

Gemeinsam mehr erreichen

CQRS und DDD


Die Verbreitung der Akronyme CQRS und DDD nimmt seit einigen Jahren stetig zu: Vor allem im Kontext von Microservices begegnet man den beiden Konzepten immer häufiger. Was steckt dahinter?

CQRS steht für Command Query Responsibility Segregation und bezeichnet die strikte Trennung der Schreib- und der Lesevorgänge einer Anwendung beziehungsweise eines API. In der klassischen Anwendungsarchitektur wird die mittlere Ebene, die typischerweise über ein API verfügt, als eine in sich geschlossene Einheit gesehen, auf die vom UI aus zugegriffen wird. CQRS schlägt stattdessen vor, die Aktionen des Benutzers ganz klar zu kategorisieren:

  • Auf der einen Seite stehen Commands, die eine Intention des Benutzers ausdrücken und zumeist eine Zustandsänderung innerhalb der Anwendung nach sich ziehen. Da sie die Intention ausdrücken, sollten sie nicht mit Create, Update und Delete benannt werden. Diese Verben bezeichnen nämlich technische Implikationen, nicht fachliche Absichten. In der Fachsprache tauchen üblicherweise andere, domänenspezifische Begriffe auf, die sich in den Commands entsprechend wiederfinden sollten.

  • Auf der anderen Seite stehen Queries, die den aktuellen Zustand der Anwendung abfragen, ihn aber nicht ändern. Queries entsprechen also reinen Lesevorgängen, wohingegen Commands das Schreiben in einer Anwendung repräsentieren.

Viel mehr als das ist CQRS zunächst einmal nicht. Es sagt insbesondere nichts über die konkrete Implementierung aus, auch nicht über die Struktur der Datenhaltung. CQRS gibt noch nicht einmal vor, wie das API strukturiert und seine Routen benannt sein sollten: Wichtig ist einzig und allein, dass das Schreiben vom Lesen getrennt wird – auf welche Art auch immer.

CQRS in einem API implementieren

Eine einfache Möglichkeit, CQRS in einem API zu implementieren, besteht darin, sich gedanklich von REST zu verabschieden und stattdessen nur noch POST und GET einzusetzen. POST steht dabei aus naheliegenden Gründen für schreibende Vorgänge (also für Commands), GET wird hingegen zum Lesen (also für Queries) verwendet. Da die Semantik wie Anlegen, Ändern oder Löschen von Dingen nun nicht mehr über das HTTP-Verb ausgedrückt wird, muss die eigentliche Aktion Bestandteil des URL werden.

Queries beziehen sich immer auf den aktuellen Stand und entsprechen vom Verb her letztlich immer dem Lesen. Bei ihnen genügt deshalb eine substantivische Beschreibung, welche Daten des Zustands gelesen werden sollen.

Bevor man beginnt, ein API zu implementieren, lohnt es sich, eine Liste der gewünschten Commands und Queries zu erstellen und zumindest für einen Moment über ihre Benennung nachzudenken. Das wiederum funktioniert natürlich nur in einem gegebenen fachlichen Kontext. Deshalb wird im weiteren Verlauf des Artikels eine einfache To-do-Listen-Anwendung als Beispiel verwendet, wie man sie beispielsweise aus dem Projekt TodoMVC [1] kennt.

Doch selbst das genügt noch nicht, um festzulegen, welche Commands und Queries man benötigt. Dafür muss nämlich zuerst noch mehr Klarheit bezüglich der tatsächlichen Funktionalität geschaffen werden. Abbildung 1 zeigt das dazu passende UI:

  • Der Anwender soll sich neue Aufgaben notieren können, wobei eine Aufgabe lediglich aus einer Beschreibung besteht.

  • Die Beschreibung einer Aufgabe soll sich auch im Nachhinein noch ändern lassen.

  • Aufgaben können, wenn sie erledigt wurden, vom Anwender abgehakt werden.

  • Das Abhaken einer Aufgabe soll sich zurücknehmen lassen. Das ist beispielsweise dann relevant, wenn eine Aufgabe fälschlicherweise oder aus Versehen abgehakt wurde.

  • Gelegentlich erübrigen sich Aufgaben im Lauf der Zeit auch von selbst. Sie sind zwar hinfällig, aber genau genommen nicht erledigt. Insofern wäre es falsch, sie abzuhaken. Vielmehr sollen solche Aufgaben verworfen werden können.

  • Zu guter Letzt soll es für den Anwender möglich sein, erledigte beziehungsweise hinfällige Aufgaben zu archivieren. Solche Aufgaben sollen dann zwar nicht gelöscht werden, über das UI aber nicht mehr sichtbar sein.

roden_ddd_1.tif_fmt1.jpgAbb. 1: UI der To-do-Anwendung

Wie bereits erwähnt empfiehlt es sich an der Stelle, nicht aus Gewohnheit auf Create, Update und Delete zu setzen, sondern Begriffe zu suchen, die auch in der Fachlichkeit enthalten sind. Das führt dazu, dass das API und die Fachlichkeit näher aneinanderrücken, was das Verständnis der Verwendern für das API wiederum verbessert: Man muss nicht eine fachliche und eine technische Sprache und das Mapping zwischen beiden lernen – es genügt, wenn man sich in der Fachsprache auskennt.

Commands und Queries definieren

Das Command zum Notieren einer neuen Aufgabe sollte also nicht Create Task heißen, denn Create ist von seiner Bedeutung her zu weit weg von „notieren“ (abgesehen davon handelt es sich bei der Anwendung um eine To-do- und nicht um eine Taskliste, weshalb auch das Wort Task unpassend ist). Deutlich besser wäre daher z. B. Note Todo.

Auch das Bearbeiten einer Aufgabe ist nicht einfach nur ein Update Todo, da Update ein Wort ist, das einen technischen Vorgang beschreibt, aber keinen fachlichen. Besser, weil inhaltlich treffender, wäre hier etwa Edit Todo. Spätestens beim Abhaken, dem Verwerfen und dem Archivieren merkt man sehr deutlich, wie unpassend Update und Delete sind: Während das eine viel zu unspezifisch ist, trifft das andere genau genommen in keinem einzigen Fall zu – schließlich sollen die verschiedenen Aktionen rückgängig gemacht werden können, und beim Archivieren ist sogar explizit gefordert, dass die Aufgabe zwar nicht mehr angezeigt, aber eben nicht gelöscht wird. Würde man sich hier mit dem klassischen Vokabular begnügen, hätte man lauter Update Todo-Commands, die man nicht voneinander unterscheiden könnte und die deshalb ziemlich beliebig wären.

Passender wären zum Beispiel Tick Off Todo, Resume Todo und Discard Todo zum Abhaken, Fortsetzen und Verwerfen von Aufgaben. Zum Archivieren schließlich könnte man das naheliegende Archive Todo verwenden. Benennt man nun die Routen des API entsprechend, hat man ein sprechendes API, bei dem man sich nicht über die (am Ende doch nur mangelhafte) Zuordnung von HTTP-Verben zu fachlichen Aktionen Gedanken machen muss, und das sich – wenn man die Fachlichkeit kennt – intuitiv verwenden lässt:

POST /note-todo
POST /edit-todo
POST /tick-off-todo
POST /resume-todo
POST /discard-todo
POST /archive-todo

Alle diese Formulierungen stehen bereits im Imperativ, also in der Befehlsform, was hervorragend die Tatsache widerspiegelt, dass es sich um Commands handelt: Der Anwender beauftragt den Computer bzw. die Anwendung damit, etwas für ihn zu erledigen, was den Zustand der Anwendung verändert. Genau das trifft die zuvor beschriebene Erklärung eines Commands in CQRS. Es repräsentiert die Intention des Anwenders und verändert den Zustand der Anwendung.

Die Queries lassen sich nach diesen Vorüberlegungen deutlich einfacher formulieren. Da das Verb bei ihnen festgeschrieben ist, genügt wie bereits erwähnt eine substantivische Beschreibung dessen, was zu lesen ist. Im einfachsten Fall ist das eine Liste aller noch nicht archivierten Aufgaben, unabhängig von ihrem sonstigen Zustand. Selbstverständlich könnte man noch weitere Sichten auf die Daten definieren, aber da eine To-do-Liste selten Tausende von Einträgen enthält, kann man es sich an der Stelle auch einfach machen und eine einzige Liste für alles verwenden und sie gegebenenfalls auf dem Client filtern: GET /todos

Und die Datenhaltung?

Damit ist nun das API gemäß CQRS definiert. Die Implementierung eines Clients dürfte relativ einfach vonstattengehen und auch der Server dürfte nicht allzu schwierig umzusetzen sein. Interessant ist an der Stelle höchstens noch die Frage nach der Datenhaltung. Sollte man, wenn man statt REST auf ein CQRS-basiertes API setzt, eine klassische relationale Datenbank zum Speichern von Daten verwenden?

Auf den ersten Blick spricht nichts dagegen. Ein erster Entwurf für ein Datenmodell könnte vorsehen, dass es eine Tabelle namens Todos gibt. Die Commands würden auf den einzelnen Datensätzen dieser Tabelle agieren und die Query würde alle Datensätze zurückgeben, die nicht als archiviert markiert wurden. Die einzige Herausforderung an der Stelle ist das Mapping von fachlichen auf technische Konstrukte: So würde in der Datenbank das Note Todo beispielsweise einem INSERT entsprechen, alle anderen Commands hingegen einem UPDATE.

Den aktuellen Anforderungen würde dieser Ansatz genügen, doch wäre er nicht besonders ausbaufähig. Insbesondere für das Reporting ist dieses Vorgehen nicht besonders gut geeignet, da keinerlei historische Informationen aufbewahrt werden. Gerade bei einer To-do-Liste könnte es aber interessant sein, gewisse Statistiken aus den Daten zu ermitteln. Beispielsweise könnte man folgende Fragen beantworten wollen:

  • Wie viel Zeit vergeht zwischen dem Notieren und dem Abhaken einer Aufgabe?

  • Wie häufig wird eine Aufgabe editiert, bevor sie abgehakt wird?

  • Wie viele Aufgaben werden verworfen, obwohl sie zuvor mindestens dreimal editiert wurden?

  • Wie häufig wird innerhalb von 30 Sekunden das Abhaken rückgängig gemacht?

Diese Liste ließe sich endlos fortsetzen. Das Erschreckende daran ist, dass sich keine einzige dieser Fragen ohne Weiteres beantworten ließe, weil die Datenbasis diese Informationen nicht enthält. Theoretisch hätte man diese Informationen aber speichern können – schließlich sind alle Aktionen, nach denen gefragt wird, irgendwann passiert. Warum liegen sie dann nicht vor?

Das Problem liegt darin begründet, dass das beschriebene Vorgehen die Historie verliert. Editiert ein Anwender beispielsweise eine Aufgabe mehrfach, lassen sich die einzelnen Bearbeitungsschritte nicht mehr nachvollziehen. Schlimmer noch: Es lässt sich noch nicht einmal mehr nachvollziehen, wann oder ob die Aufgabe überhaupt jemals editiert wurde. Selbstverständlich kann man das in den Griff bekommen, indem man ein Feld für einen Zeitstempel der letzten Aktualisierung einfügt. Doch auch das hilft noch nicht in allen Fällen, da sich die einzelnen Bearbeitungsstände nicht separat abrufen lassen. Hierzu müsste man entweder eine ganze Reihe von Feldern oder gleich eine neue Tabelle anlegen.

Da man nicht weiß, welche Datenabfragen zukünftig gestellt werden, kann man die Tabellen nicht auf die entsprechenden Antworten optimieren. Man sammelt daher entweder zu viele oder zu wenige Daten, ganz sicher aber stets die falschen. Werden dann Fragen wie die oben genannten gestellt, lassen sie sich – wenn überhaupt – nur mit Glück beantworten. In der Regel wird die Antwort auf jede dieser Fragen lauten, dass man zunächst Code schreiben müsse, der die dafür relevanten Daten erfasst und speichert. Anschließend müsse man lediglich noch ein paar Wochen oder Monate warten, und schon könne man die gewünschte Auswertung liefern. Dass das alles andere als befriedigend ist, liegt auf der Hand.

Vom Status quo zu Domain Events

Was man also braucht, ist eine andere Art der Datenspeicherung: Anstatt den aktuellen Zustand zu speichern, sollte man die einzelnen Veränderungen speichern, die zum Status quo geführt haben. Das klingt zunächst danach, als ob man die eingegangenen Commands sammeln sollte. Commands haben jedoch die Eigenschaft, dass eine Anwendung sie ausführen oder verweigern kann. Aus der reinen Tatsache, dass ein Command an ein API geschickt wurde, lässt sich noch nicht folgern, dass es auch erfolgreich ausgeführt wurde. Viel interessanter als das reine Command ist also die Reaktion darauf: Was wurde von der Anwendung in fachlicher Hinsicht entschieden, sozusagen als Reaktion auf das Command? Diese Reaktionen sind schnell identifiziert, da sie sich – zumindest im vorliegenden Beispiel – originär auf die Commands abbilden lassen. Das muss jedoch nicht bei jeder Anwendung so sein und insbesondere bei komplexeren Anwendungen ist das Vorgehen nicht mehr ganz so einfach:

  • Eine Aufgabe wurde notiert.

  • Eine Aufgabe wurde editiert.

  • Eine Aufgabe wurde abgehakt.

  • Eine Aufgabe wurde fortgesetzt.

  • Eine Aufgabe wurde verworfen.

  • Eine Aufgabe wurde archiviert.

Es fällt auf, dass alle diese Formulierung in der Vergangenheitsform stehen. Das hat den einfachen Grund, dass es sich hierbei um Fakten handelt, die als Reaktion auf ein Command entstanden sind. Diese Dinge sind passiert und es gibt nichts auf der Welt, das man tun könnte, um diese Ereignisse ungeschehen zu machen. Natürlich lässt sich eine Gegentransaktion ausführen, doch die reine Tatsache, dass ein Ereignis einmal stattgefunden hat, ist unumkehrbar. Der Effekt lässt sich ausgleichen – das Ereignis an sich nicht.

Diese Ereignisse werden als Domain Events bezeichnet und sie lassen sich in einer immer weiterwachsenden Liste von Ereignissen speichern. Dafür eine Datenbankstruktur aufzusetzen, ist sehr simpel: Außer INSERT und SELECT wird nichts benötigt. Wie das API bei CQRS reduziert man an der Stelle nun also die Datenbank auf einfaches Schreiben und Lesen. Als Ergebnis erhält man eine Liste, die der im Listing 1 ähnelt. Zusätzlich zu den bereits beschriebenen Informationen enthält sie außerdem noch eine id-Spalte, damit man mehrere Aufgaben unterscheiden kann, und eine order, mit der sich die Reihenfolge der Events in Bezug auf eine Aufgabe ermitteln lässt.

Listing 1

id    eventType         order    timestamp		payload
1     todoNoted		1         29.12.2019 19:05	{ description: 'go shoping' }
1     todoEdited	2         29.12.2019 19:07	{ description: 'go shopping' }
1     todoTickedOff     3         02.01.2019 10:13	{}
1     todoArchived      4         02.01.2019 13:49	{}

Speichert man Domain Events auf diese Weise, kann man nicht nur den aktuellen Zustand einer Aufgabe wieder ermitteln, sondern auch die zuvor angesprochenen Fragen beantworten:

  • Wie viel Zeit vergeht zwischen dem Notieren und dem Abhaken einer Aufgabe? Anders formuliert: Wie viel Zeit liegt zwischen dem todoNoted und dem todoTickedOff Event? Die Antwort lässt sich anhand des Timestamp rasch ermitteln: Zwischen den beiden Domain Events sind 3 Tage, 15 Stunden und 8 Minuten vergangen. Berechnet man diese Differenz für mehrere Aufgaben, kann man außerdem angeben, wie viel Zeit üblicherweise im Durchschnitt pro Aufgabe vergeht.

  • Wie häufig wird eine Aufgabe editiert, bevor sie abgehakt wird? Anders formuliert: Wie viele todoEdited Events gibt es nach dem todoNoted Event, aber vor dem zugehörigen todoTickedOff Event? Die Antwort für die Beispielaufgabe lautet 1.

  • Wie viele Aufgaben werden verworfen, obwohl sie zuvor mindestens dreimal editiert wurden? Anders formuliert: Wie viele Aufgaben weisen mindestens drei todoEdited und außerdem auch ein todoDiscarded Event auf? Im vorliegenden Beispiel trifft das nicht zu, weshalb die Antwort 0 lautet.

  • Wie häufig wird innerhalb von 30 Sekunden das Abhaken rückgängig gemacht? Anders formuliert: Bei wie vielen Aufgaben folgt innerhalb von 30 Sekunden ein todoResumed Event auf ein todoTickedOff Event? Da in dem Beispiel kein todoResumed Event enthalten ist, liegt die Häufigkeit bei 0.

Diese Art der Datenspeicherung nennt man Event Sourcing, weil Domain Events als Quelle genutzt werden, um Informationen zu ermitteln. Eine Datenbank, die wie die zuvor beschriebene Liste funktioniert, nennt man Event Store. Es liegt auf der Hand, dass man CQRS und Event Sourcing unabhängig voneinander nutzen kann – immerhin kam Event Sourcing in der Beschreibung von CQRS zunächst nicht vor und selbstverständlich lassen sich auch Ereignisse in einer Liste speichern, ohne dass das damit verbundene API nach CQRS strukturiert sein muss. Aber man kann die beiden Konzepte eben auch wunderbar miteinander verbinden.

Wenn man so vorgehen möchte, resultieren Commands also letztlich in Domain Events, die in einem Event Store gespeichert werden. Zum Auslesen müssen die Domain Events wieder abgespult werden. Dieser Vorgang wird als Replay bezeichnet. Allerdings gibt es dabei auch einen gravierenden Haken: Je mehr Events gesammelt und gespeichert werden, desto länger dauert es, ein Replay durchzuführen, da die Anzahl der Events zunehmend größer wird.

Allerdings gibt es einen einfachen Ausweg. Da Domain Events per Definition niemals geändert oder gelöscht werden, ergibt ein Replay bis zu einem bestimmten Zeitpunkt immer dasselbe Ergebnis. Um beim obigen Beispiel zu bleiben: Es spielt für den Replay der ersten drei Events keine Rolle, ob danach noch weitere Events kommen oder nicht – und wenn ja, wie viele. Das wiederum bedeutet, dass sich das Ergebnis eines Replays problemlos cachen lässt. Ein solcher zwischengespeicherter Wert wird beim Event Sourcing als Snapshot bezeichnet. Statt einen Replay stets von Anfang an durchführen zu müssen, kann man daher auf einen Snapshot zurückgreifen und muss nur noch die seither aufgetretenen Events abspielen, um auf den aktuellen Stand zu kommen. Werden solche Snapshots regelmäßig geschrieben, lässt sich damit eine nahezu lineare Performance erzielen. Außerdem lässt sich das Konzept dazu nutzen, Views vorzuberechnen: Schreibt man stets nach jedem Event einen neuen Snapshot, hat man jederzeit den aktuellen Zustand der Anwendung griffbereit und kann ihn präsentieren.

Semantik und Struktur von Domain Events

Da CQRS und Event Sourcing zwei technisch geprägte Konzepte sind, lösen sie auch ausschließlich technische Probleme. Die Semantik und Struktur von Domain Events ergibt sich jedoch weder aus dem einen noch aus dem anderen – ob Events also sinnvoll modelliert sind und fachlich relevante Daten enthalten, wird durch CQRS und Event Sourcing nicht beeinflusst. Die beiden Mechanismen beschreiben lediglich, wie sich Daten auf Basis von Events speichern und wie sich fachlich sprechende APIs entwickeln lassen. Woher kommt also die Semantik? Beziehungsweise wie geht man beim Entwurf einer Anwendung vor, um sicherzugehen, dass die verwendeten Commands und Events auch tatsächlich das abbilden, was der Fachlichkeit nützt?

Das ist aus naheliegenden Gründen keine technische Frage, weshalb sie sich auch nicht technisch beantworten lässt. Stattdessen benötigt man ein Konzept, um fachliche Konzepte bereits beim Entwurf und während der Entwicklung zu verstehen, zu greifen und in Code zu implementieren. Genau hier kommt der Ansatz Domain-driven Design (DDD) ins Spiel: DDD ist eine Methodik, um in einem interdisziplinären Team ein gemeinsames Verständnis und eine gemeinsame Sprache für die Fachlichkeit zu entwickeln. DDD rückt also, anders als beispielsweise Test-driven Design (TDD) kein technisches Artefakt in den Fokus, sondern die Fachlichkeit und deren Verständnis.

Dadurch kommunizieren unter anderem Fachexperten, Entwickler und Designer frühzeitig miteinander und bekommen auf diesem Weg ein gemeinsames Verständnis der zu entwickelnden Thematik. Die gemeinsame Sprache, die in DDD als Ubiquitous Language bezeichnet wird, vereinfacht die Kommunikation in den späteren Phasen der Entwicklung spürbar. Obwohl die Begriffe dieser Sprache von der modellierten Fachdomäne abhängen, folgen sie doch gewissen Regeln.

So gibt es in DDD beispielsweise wie in CQRS Commands, die die Wünsche der Anwender darstellen. Domain Events hingegen sind die von der Anwendung als Reaktionen auf die Commands geschaffenen Fakten, die nicht mehr veränderlich sind und deshalb in der Vergangenheitsform stehen. Das klingt inzwischen bereits vertraut, obwohl es unabhängig von CQRS und Event Sourcing entstanden ist. Die gemeinsame Logik der Commands und Events ist in sogenannten Aggregates gekapselt, die zudem auch den Zustand der Anwendung in logische Einheiten kapseln. Eine der Besonderheiten von DDD ist, dass es nicht die Daten der Anwendung in den Mittelpunkt rückt, sondern die Prozesse. Warum das wichtig ist, hat Steve Yegge sehr anschaulich in seinem lesenswerten Blogeintrag „Execution in the Kingdom of Nouns“ [2] beschrieben.

Gemeinsam mehr erreichen

Obwohl DDD unabhängig von CQRS und Event Sourcing entstanden ist und sich daher unabhängig von diesen beiden Ansätzen einsetzen lässt, ergänzen sich die drei Konzepte hervorragend. Dabei wird den Events eine tragende Rolle zuteil: In DDD fungieren sie als fachliche und semantische Grundlage für die Modellierung. In Event Sourcing legt bereits der Name nahe, dass es ebendiese Events sind, die es als Veränderungen zu speichern gilt. Und in CQRS dienen Events schließlich der Synchronisation von Schreib- und Leseseite. Abbildung 2 stellt den Zusammenhang zwischen DDD, Event-Sourcing und CQRS an Hand des Datenflusses einer Anwendung grafisch dar. Im Write Model, also der Schreibseite der Anwendung, verwendet man DDD, um eingehende Commands zu verarbeiten und sie in Domain Events zu transformieren. Diese Events legt man anschließend mit Hilfe von Event Sourcing in einen Event Store. Danach werden die Events für die Synchronisation der Schreib- und der Leseseiten, die in einer CQRS-Anwendung existieren, an das Read Model übertragen. Dort interpretiert man die Events und aktualisiert die zu lesenden Views gemäß den individuellen Anforderungen.

roden_ddd_2.tif_fmt1.jpgAbb. 2: Zusammenhang zwischen DDD, Event Sourcing und CQRS

Auf diese Art fügen sich die drei Konzepte wie Puzzleteile zu einem großen Ganzen zusammen. Als Ergebnis erhält man einen Ansatz zum Entwickeln von Anwendungen, der sich nah an der Fachlichkeit bewegt, hervorragende Analysemöglichkeiten bietet, und der sich außerdem gut skalieren lässt. Dank des Einsatzes von DDD ist von Vornherein ein interdisziplinäres Team involviert, weshalb auf diesem Weg in kürzerer Zeit bessere Software gelingt.

Fazit

Selbstverständlich gibt es zu jedem der drei einzelnen Konzepte, CQRS, Event Sourcing und DDD, noch weitaus mehr zu schreiben. Insbesondere gibt es, bedingt durch die andere Art der Architektur, eine Reihe von Sonderfällen, die man zwar nicht alle im finalen Code berücksichtigen muss, denen man sich aber zumindest bewusst sein sollte. Folgt man während der Entwicklung von Software diesen Konzepten, erhält man als Ergebnis eine Reihe von Vorteilen gegenüber klassischer Architektur und einem herkömmlichen Vorgehensmodell – man hat aber eben auch mit einer anderen Art von Problemen zu kämpfen.

Ob die Vor- oder die Nachteile überwiegen, muss für jede Anwendung einzeln bewertet werden. Tendenziell lässt sich aber sagen, dass es kein Vorgehen gibt, das keinerlei Probleme mit sich brächte, man durch den Einsatz von CQRS und Co. aber zumindest eine ganze Reihe üblicher Probleme lösen kann – was insbesondere im Bereich der Datenauswertung praktisch ist. Auch die Tatsache, dass DDD zu einem besseren Verständnis der Fachlichkeit bei allen Beteiligten führt, ist ein enormer Gewinn: Wer schreibt schließlich bessere Software als der, der nicht nur technisch, sondern auch fachlich weiß, was er tut?

roden_golo_sw.tif_fmt1.jpgGolo Roden ist Gründer und CTO der the native web GmbH, ein auf native Webtechnologien spezialisiertes Unternehmen. Für die Entwicklung moderner Webanwendungen bevorzugt er JavaScript und Node.js und hat mit „Node.js & Co.“ das erste deutschsprachige Buch zu diesem Thema geschrieben. Darüber hinaus ist er journalistisch für Fachmagazine und als Referent und Contentmanager für Konferenzen im In- und Ausland tätig. Für sein qualitativ hochwertiges Engagement in der Community wurde Golo dreifach als Microsoft MVP ausgezeichnet.

Web
Golo Roden

Golo Roden ist Gründer und CTO der native web GmbH. Er berät Unternehmen zu Technologien und Architekturen im Web- und Cloud-Umfeld, unter anderem zu TypeScript, Node.js, React, CQRS, Event-Sourcing und Domain-Driven Design (DDD).


Weitere Artikel zu diesem Thema