Serviceaufrufregeln

In Schleupen.CS gibt es Regeln dafür, welcher Service einer bestimmten Kategorie welchen Service einer anderen Kategorie auf welche Weise nutzen darf. Diese Regeln haben folgende Ziele:

  • Unterstützung des Principle Of Least Surprise:
    Beispiel: Der Aufruf eines Process Service von einem Entity Service, wäre sehr unerwartet. (Gelöst werden kann dies durch ein ausgelöstes Business Event, das den Geschäftsprozess startet oder fortführt - Dependency Inversion auf Service-Ebene.)
  • Förderung von Resilienz:
    Wenn beispielsweise ein Service synchron in Kette zwei weitere Services aufruft, die jeweils Daten ändern, so wäre so etwas wie eine verteilte Transaktion notwendig, um unerwünschte Systemzustände zu vermeiden. Eine solche technische Kopplung zu einem Transaktionsmanager (MSDT o.ä.) ist in Schleupen.CS nicht erlaubt, da derartige Technologien nach unserer Erfahrung insbesondere programmiersprachen- / plattformübergreifend nicht zuverlässig genug funktionieren. Das Problem lässt sich auf mehrere Arten lösen (beispielsweise durch Sagas), nur i.A. nicht über synchrone, direkt in Reihe geschaltete Aufrufe.
  • Minimierung von Kopplung:
    Um die Kopplung der Länder untereinander zu begrenzen, kommen die sogenannten Geschäftsprozess-Komponenten ins Spiel, die hier die Orchestrierung übernehmen. Entsprechend darf ein Land beispielsweise ein anderes Land nicht synchron schreibend aufrufen.
  • Unterstützung einer Schichten-Architektur auf Makroebene:
    Um ein besseres Systemverständnis zu erzielen, gibt es in Schleupen.CS die Geschäftsprozess-Komponenten. Nur diese dürfen Process Services beinhalten.
  • Beachtung von Abstraktionsniveaus (~ Single-Responsibility-Principle (SRP) auf Architekturebene):
    Orchestrierung auf Ebene der Geschäftsprozesse hat beispielsweise ein höheres Abstraktionsniveau als ein Activity Service eines Landes.
Kontext von Serviceaufrufregeln in der Architektur
Exemplarische Beispiele der Servicenutzungsregeln:

Im Folgenden werden exemplarisch einige Regeln aufgeführt und kurz erläutert. Die angeführten Fälle versuchen einen Einblick in die Thematik zu geben.

Fall: Benutzeroberfläche ruft Process Service auf

Der Aufruf von Benutzeroberfläche zu einem Process Service ist natürlich erlaubt, da dies eine einfache Möglichkeit ist, um Geschäftsprozesse zu starten bzw. fortzuführen.

Fall: Ein Process Service ruft einen Activity Service eines Landes schreibend auf

Auch dieser Aufruf ist recht offensichtlich zu erlauben. Da Process Services als Workflows implementiert werden, sind auch schreibende Aufrufe in Reihe möglich. Denn die oben beschriebenen Probleme bzgl. der Implementierung von Transaktionen, die sich über mehrere Microservices erstrecken, lösen sich durch die zeitliche Entkopplung durch Verwendung von Workflows / Sagas auf.

Fall: Ein Activity Service eines Landes ruft eine lesende Operation eines Activity Service eines Landes auf

Das Lesen von Daten ist prinzipiell eine unkritischere Abhängigkeit als eine Schreibende. Würde man diese Möglichkeit nicht erlauben, würde das bedeuten, dass mehr Daten über die Orchestrierungsebene transportiert werden müssten, was in deutlich mehr Implementierungsaufwand und einem schlechteren Laufzeitverhalten münden würde.

Die Unterscheidung, ob sich die Logik auf Änderungen oder das Lesen von Daten bezieht, ist fundamental und zieht sich komplett von Servicedesign bis in die Domäne durch. Stichwort: CQRS.

Fall: Ein Activity Service eines Landes ruft synchron eine schreibende Operation eines Activity Service eines Landes auf

Da ein Activity Service im Allgemeinen auch die eigenen Daten modifiziert, ist dieses Problem identisch zu dem Aufruf zweier schreibender Services. Denn es ist egal, um welche Art von Ressource (Datenbank, Service, etc.) es sich handelt. Auch hier wird so etwas wie eine verteilte Transaktion benötigt, was in Schleupen.CS auf Ebene von GP-Komponente durch Implementierung von Workflows als Sagas erfolgt.

Matrix

Die folgende Matrix definiert die Regeln für den Zugriff von einem Baustein auf den anderen.

AufruferRuft aufZielErlaubtAnmerkung
Implementierung UIProcessService

(i.A. als Abschluss eines Dialogablaufs, da SHIL (Service - Human Interaction Layer) nicht direkt unterstützt wird - hier ist Polling notwendig)
Implementierung UIActivityService 
Implementierung UIQueryService 
Implementierung UIEntityService 
Implementierung UIEventService
 
Implementierung UICommandService 
Implementierung WorkflowProcessService 
Implementierung WorkflowActivityService 
Implementierung WorkflowQueryService 
Implementierung WorkflowEntityService(Beachte hierbei: ist eine Verletzung des Abstraktionsniveaus vorhanden? 
Don't do it)
Implementierung WorkflowEventServiceauslösen
Implementierung WorkflowCommandService 
Implementierung ActivityService (in GP-Komponente)ProcessService 
Implementierung ActivityService (in GP-Komponente)ActivityService 
Implementierung ActivityService (in GP-Komponente)QueryService(nur lesend)
Implementierung ActivityService (in GP-Komponente)EntityService(nur lesend)
Implementierung ActivityService (in GP-Komponente)EventServiceauslösen
Implementierung ActivityService (in GP-Komponente)CommandService 
Implementierung ActivityService (in Land)ProcessService 
Implementierung ActivityService (in Land)ActivityService 
Implementierung ActivityService (in Land)QueryService(nur lesend, nur Land darf aufgerufen werden)
Implementierung ActivityService (in Land)EntityService(nur lesend)
Implementierung ActivityService (in Land)EventService 
Implementierung ActivityService (in Land)CommandService 
Implementierung QueryService (in GP-Komponente)ProcessService 
Implementierung QueryService (in GP-Komponente)ActivityService 
Implementierung QueryService (in GP-Komponente)QueryService(nur lesend)
Implementierung QueryService (in GP-Komponente)EntityService(nur lesend)
Implementierung QueryService (in GP-Komponente)EventService 
Implementierung QueryService (in GP-Komponente)CommandService 
Implementierung QueryService (in Land)ProcessService 
Implementierung QueryService (in Land)ActivityService 
Implementierung QueryService (in Land)QueryService(nur lesend, nur Land darf aufgerufen werden)
Implementierung QueryService (in Land)EntityService(nur lesend)
Implementierung QueryService (in Land)EventService 
Implementierung QueryService (in Land)CommandService 
Implementierung EntityServiceProcessService 
Implementierung EntityServiceActivityService 
Implementierung EntityServiceQueryService 
Implementierung EntityServiceEntityService 
Implementierung EntityServiceEventServiceauslösen
Implementierung EntityServiceCommandService 
Implementierung EventService (in GP-Komponente)ProcessService 
Implementierung EventService (in GP-Komponente)ActivityService(nur lesend)
Implementierung EventService (in GP-Komponente)QueryService 
Implementierung EventService (in GP-Komponente)EntityService(nur lesend)
Implementierung EventService (in GP-Komponente)EventServiceauslösen
Implementierung EventService (in GP-Komponente)CommandService 
Implementierung EventService (in Land)ProcessService 
Implementierung EventService (in Land)ActivityService 
Implementierung EventService (in Land)QueryService(nur Land darf aufgerufen werden)
Implementierung EventService (in Land)EntityService(nur lesend, nur Land darf aufgerufen werden)
Implementierung EventService (in Land)EventServiceauslösen
Implementierung EventService (in Land)CommandService(nur Land darf aufgerufen werden)
Implementierung CommandServiceProcessService 
Implementierung CommandServiceActivityService 
Implementierung CommandServiceQueryService(nur lesend, nur Land darf aufgerufen werden)
Implementierung CommandServiceEntityService(nur lesend)
Implementierung CommandServiceEventService 
Implementierung CommandServiceCommandService
Cookie Consent mit Real Cookie Banner