Ist CQRS nicht Überentwicklung?

14

Ich erinnere mich immer noch an gute alte Tage der Aufbewahrungsorte. Aber Repositories wuchsen mit der Zeit hässlich. Dann wurde CQRS zum Mainstream. Sie waren nett, sie waren ein Hauch frischer Luft. Aber in letzter Zeit habe ich mich immer wieder gefragt, warum ich die Logik in der Action-Methode eines Controllers nicht richtig einstelle (insbesondere in Web Api, wo action eine Art Befehls- / Abfragehandler für sich ist).

Bisher hatte ich eine klare Antwort darauf: Ich mache es zum Testen, da es schwierig ist, Controller mit all diesen nicht verspottbaren Singletons und der insgesamt hässlichen ASP.NET-Infrastruktur zu testen. Die Zeiten haben sich jedoch geändert und ASP.NET-Infrastrukturklassen sind heutzutage viel einfacher zu testen (insbesondere in ASP.NET Core).

Hier ist ein typischer WebApi-Aufruf: Befehl wird hinzugefügt und SignalR-Clients werden darüber benachrichtigt:

public void AddClient(string clientName)
{
    using (var dataContext = new DataContext())
    {
        var client = new Client() { Name = clientName };

        dataContext.Clients.Add(client);

        dataContext.SaveChanges();

        GlobalHost.ConnectionManager.GetHubContext<ClientsHub>().ClientWasAdded(client);
    }
}

Ich kann es leicht testen / verspotten. Außerdem kann ich dank OWIN lokale WebApi- und SignalR-Server einrichten und einen Integrationstest durchführen (und das übrigens ziemlich schnell).

In letzter Zeit fühlte ich mich immer weniger motiviert, umständliche Befehle / Abfragen-Handler zu erstellen, und ich neige dazu, Code in Web-API-Aktionen beizubehalten. Ich mache nur dann eine Ausnahme, wenn die Logik wiederholt wird oder wirklich kompliziert ist und ich sie isolieren möchte. Aber ich bin mir nicht sicher, ob ich hier das Richtige tue.

Was ist der vernünftigste Ansatz zum Verwalten von Logik in einer typischen modernen ASP.NET-Anwendung? Wann ist es sinnvoll, den Code in die Handler für Befehle und Abfragen zu verschieben? Gibt es bessere Muster?

Aktualisieren. Ich habe diesen Artikel über den DDD-Lite-Ansatz gefunden. Mein Ansatz, komplizierte Teile des Codes in Kommandos / Queries-Handler zu verschieben, könnte also CQRS-lite heißen.

SiberianGuy
quelle
1
Ich verstehe nicht, wie CQRS die Dinge testbarer macht / bei Singletons / Controllern / etc. Von Nutzen ist. Sie haben weitgehend nichts miteinander zu tun. Außerdem erstellen Sie in Ihrem (counter?) - Beispiel immer noch einen Befehl, der ungerade ist.
guillaume31
Wenn Sie Ihren Code zusammen mit dem Infrastrukturcode speichern (dh die IP-Adresse des Clients abrufen), ist dies nur schwer zu testen. Wenn Sie die Logik in einer Abfrage / einem Befehl isolieren, ist dies viel einfacher. Das Codebeispiel war etwas verwirrend, daher habe ich es aktualisiert.
SiberianGuy
1
Abfragen und Befehle haben keine Logik. Sie sind dumme DTOs. Dann haben Sie Ihre Befehls- / Abfragehandler , aber sie sind genau die gleichen wie Anwendungsdienste, Interaktoren, Geschäftsdienste, Sie nennen es ... in einem Nicht-CQRS-Kontext. Das Platzieren der Anwendungs- / Anwendungsfalllogik in einem anderen Objekt als dem Controller ist keine CQRS-spezifische Sache.
Guillaume31
Auch die Frage von Singleton vs. injizierter Abhängigkeit ist zu CQRS völlig orthogonal. Sie könnten einen Controller haben, der ein CommandHandler-Singleton aufruft, das ein Repository-Singleton aufruft ...
guillaume31
1
@ guillaume31, CQRS ist in der Regel umständlicher als Repository- / Aplication-Service-Aufrufe. Sie benötigen in der Regel 2-3 Klassen (dh Abfrage, Queryhandler, Queryresult), Infrastruktur usw.
SiberianGuy

Antworten:

17

Ist CQRS ein relativ kompliziertes und kostspieliges Muster? Ja.

Ist es Überentwicklung? Absolut nicht.

In dem Originalartikel, in dem Martin Fowler über CQRS spricht , finden Sie zahlreiche Warnungen, dass CQRS nicht verwendet wird, sofern dies nicht zutreffend ist:

Wie jedes Muster ist CQRS an einigen Stellen nützlich, an anderen jedoch nicht.

CQRS ist ein bedeutender mentaler Sprung für alle Beteiligten und sollte nur angegangen werden, wenn der Nutzen den Sprung wert ist .

Obwohl ich CQRS erfolgreich eingesetzt habe, war die Mehrzahl der Fälle, in die ich geraten bin, bisher nicht so gut ...

Trotz dieser Vorteile sollten Sie bei der Verwendung von CQRS sehr vorsichtig sein .

... das Hinzufügen von CQRS zu einem solchen System kann die Komplexität erheblich erhöhen .

Mein Schwerpunkt oben.

Wenn Ihre Anwendung CQRS für alles verwendet, ist es nicht CQRS, das überarbeitet wurde, sondern Ihre Anwendung. Dies ist ein hervorragendes Muster zur Lösung einiger spezifischer Probleme, insbesondere von Anwendungen mit hoher Leistung und hohem Volumen, bei denen die gleichzeitige Verwendung von Schreibvorgängen ein Hauptproblem darstellen kann.

Und es kann nicht die gesamte Anwendung sein, sondern nur ein kleiner Teil davon.

Als Beispiel aus meiner Arbeit setzen wir CQRS in der Auftragserfassung ein, bei der wir keine Aufträge verlieren können, und wir haben Spitzenwerte, bei denen Tausende von Aufträgen zur gleichen Zeit aus verschiedenen Quellen zu bestimmten Zeiten eingehen. CQRS half uns dabei, das System am Leben zu erhalten und zu reagieren, und ermöglichte es uns, die Back-End-Systeme gut zu skalieren, um diese Aufträge bei Bedarf schneller (mehr Back-End-Server) und langsamer / billiger zu verarbeiten, wenn sie nicht benötigt werden.

CQRS ist ideal für das Problem, bei dem mehrere Akteure an einem Datensatz zusammenarbeiten oder auf dieselbe Ressource schreiben.

Wenn Sie ein Muster, das zur Lösung eines einzelnen Problems erstellt wurde, auf alle Ihre Probleme verteilen, entstehen Ihnen einfach mehr Probleme.


Einige andere nützliche Links:

http://udidahan.com/2011/04/22/when-to-avoid-cqrs/

http://codebetter.com/gregyoung/2012/09/09/cqrs-is-not-an-architecture-2/

Machado
quelle
3
Einigen Sie sich auf alles außer auf den Teil "relativ kompliziertes und teures Muster". CQRS trennt nur Lesevorgänge von Schreibvorgängen. Sie können es mit Klebeband, Zero Middleware / komplizierten Werkzeugen und der gleichen Datenbank wie zuvor tun, egal wie wichtig es ist.
Guillaume31
@ guillaume31, das ist ein fairer Punkt. Ich denke, es entspricht ziemlich genau der Idee aus der ursprünglichen Frage: "In Web Api, wo Aktion eine Art Befehl / Abfrage an sich ist". Aber haben Sie irgendwelche funktionierenden CQRS-Beispiele gesehen (vorzugsweise Github), die keine separaten Klassen für Befehle und Abfragen verwenden? Das ist es, was ich finde, wenn ich versuche zu sehen, wie andere Leute CQRS in .NET implementieren.
SiberianGuy
Ja, aber es ist keine Überentwicklung. Es ist die Grundvoraussetzung des Musters - Abfragen von Schreibvorgängen trennen, Modell von Domänenmodell lesen.
Guillaume31
Der CQRS Ansatz könnte vorbei sein Abtötung in vielen Kontexten, aber das ist eine ganz andere Geschichte. Es ist kein Overkill wegen all der kleinen technischen Details, die Sie CQRS in Ihrem Q zu Unrecht zuschreiben. Es ist ein Overkill, weil Sie nicht immer das brauchen, was CQRS Ihnen bringt.
Guillaume31
Ich denke, Fowlers Punkt ist nur bis zu einem bestimmten Punkt gültig. SQL Views ist eine Art von CQRS und es gibt sie schon seit Ewigkeiten und niemand sagt, dass sie sehr komplex sind. Da es viele CQRS-Varianten gibt, dh Event-Sourcing-Projektionen, können diese in einigen Bereichen als komplex und in anderen als trivial angesehen werden.
Alexey Zimarev
3

CQRS ist kein Eins-zu-Eins-Ersatz für Repositorys, da es sich um ein komplexes, kostspieliges Muster handelt, das nur in einigen Fällen nützlich ist.

Hier ist, was Udi Dahan zu sagen hat:

Die meisten Benutzer von CQRS (und auch von Event Sourcing) hätten dies nicht tun sollen.

[...]

Es tut mir leid, dass die meisten Online-Beispielanwendungen, die CQRS anzeigen, architektonisch falsch sind. Ich würde auch sehr vorsichtig sein, wenn Sie Frameworks verwenden, die Sie zu einem CQRS-Gesamtmodell im Entity-Stil führen.

( Quelle )

Martin Fowler:

[...] Sie sollten bei der Verwendung von CQRS sehr vorsichtig sein . Viele Informationssysteme passen gut zum Konzept einer Informationsbasis, die auf dieselbe Weise wie beim Lesen aktualisiert wird. Das Hinzufügen von CQRS zu einem solchen System kann eine erhebliche Komplexität verursachen.

( Quelle )

Schließlich Greg Young:

CQRS kann als Architekturmuster bezeichnet werden.

[...]

Dies ist sehr wichtig, um zu verstehen, dass die meisten Architekturmuster nicht überall angewendet werden können. Wenn Sie Architekturmuster in einer Architekturrichtlinie sehen, haben Sie wahrscheinlich ein Problem

[...]

Der größte Fehler, den ich bei Leuten sehe, die Event-Sourcing verwenden, ist, dass sie versuchen, es überall zu verwenden.

( Quelle )

Sklivvz
quelle