Follow my new blog

Freitag, 26. Februar 2010

Bindungsenergie – Gedanken über ein Tooling für Event-Based Components

Der Gewinn, den Event-Based Components (EBC) bringen, steht nach meinem vorhergehenden Blogartikel inzwischen unzweifelhaft fest. Bevor EBC weitere Kreise ziehen können, muss es dafür aber ein Tooling geben, glaube ich. Dependency Injection kann man von Hand betreiben – aber das macht keinen Spaß, wenn die Anwendungen größer werden. Dasselbe gilt sogar potenziert für die Verdrahtung von EBC “Pins”. Deren Zahl ist viel größer als die der Interfaces, für die DI zuständig ist.

Wie könnte also ein Unterstützung von EBCs mit einem “Container” aussehen?

Die Grundsituation sieht so aus: Komponente Client und Service sind zusammen zu stecken. Client publiziert dafür einen Event, Service einen Event-Handler. Der Event ist der Output-Pin, der mit dem Event-Handler als Input-Pin verbunden werden muss. Zwischen beiden ist eine Leiterbahn zu legen.

Anmerkung: Ich benutze ab jetzt Begriffe aus der Elektrotechnik ohne Anführungszeichen. Platine, Pin, Bauteil, Leiterbahn usw. scheinen mir einfach so gut zu passen, dass ich sie nicht mehr als Analogie hervorheben will, sondern für den Moment mal zu EBC-Fachbegriffen mache.

Die EBC-Bauteilspezifikationen sehen dafür z.B. so aus:

interface IClient

{

    event Action<string> OnOutput;

}


interface
IService

{

    void ProcessString(string text);

}

Konkrete Bauteile, die diesen Spezifikationen folgen, können dann so zusammengesteckt werden:

IService s = new Service();

IClient c = new Client();

c.OnOutput += s.ProcessString;

Das ist ganz einfach. Aber wenn es um mehr als 2-3 Leiterbahnen geht, dann wird es lästig. Wie kann das also automatisiert werden?

Vom Nutzen eines DI Container

Zunächst dachte ich, ein DI Container hat bei EBC nicht mehr soviel Bedeutung. Doch das stimmt nicht. Er seinen vollen Wert für die Build Phase. In der werden die EBC-Bauteile instanziert. Die legt sie sozusagen auf die Werkbank, bevor sie in der Bind Phase auf einer Platine zusammengesteckt werden.

Im obigen Beispiel besteht die Build Phase aus den beiden Instanzierungen. Mit einem DI Container kann die so aussehen:

IUnityContainer uc = new UnityContainer();

uc.RegisterType<IService, Service>();

uc.RegisterType<IClient, Client>();

IService s = uc.Resolve<IService>();

IClient c = uc.Resolve<IClient>();

Obwohl die EBC-Komponenten keine funktionalen Abhängigkeiten untereinander haben, lohnt sich der Einsatz eines DI Containers. Denn zum einen können Bauteile von anderer Funktionalität abhängen, die nichts mit EBC zu tun hat. Zum anderen können Bauteile Platinen sein und insofern doch von Bauteilen abhängen. Davon später mehr.

Wenn Sie sich auf EBC einlassen, vergessen Sie Ihren liebsten DI Container also nicht! Instanzieren Sie die EBC-Bauteile mit ihm.

Bauteile binden

Die Herausforderung für das Tooling rund um EBCs liegt also nicht in der Instanzierung, sondern in der automatischen Verbindung von Pins, d.h. in der Bind Phase. Die besteht im Beispiel nur aus einer Zeile:

c.OnOutput += s.ProcessString;

Wenn das nun mehr Zeilen werden, wie könnte Ihnen ein Tool die Arbeit abnehmen? Ich stelle mir das derzeit so vor:

ComponentBinder.Bind(c, s);

Schön einfach, oder? So soll es ja auch sein. Die Bind()-Methode soll halt irgendwie dafür sorgen, dass die Input- und Output-Pins der übergebenen Bauteile “zu einander finden”. Ganz allgemein sollen Sie also Bind() Instanzen aller zu verdrahtenden Bauteile übergeben. Wieviele das sind, hängt vom Abstraktionsniveau des Codes ab, in dem die Bindung stattfindet.

Sie können sich z.B. entscheiden, nur mit atomaren Bauteilen zu arbeiten. Dann rufen Sie Bind() nur einmal mit all diesen Bauteilen auf. Für die Bauteile

A->B->C->D

sähe das so aus: Bind(a, b, c, d)

Wenn Sie allerdings Bauteile auf Platinen zu größeren Einheiten aggregieren, dann sieht das anders aus:

A->Platine(B->C)->D

würde zu den Aufrufen Bind(a, platine, d) und Bind(b, c) führen.

Aufgerufen wird Bind() immer von einer Platine. Im einfachsten Fall gibt es nur eine für Ihre ganze Anwendung. Sobald die Sache jedoch etwas größer wird, werden Sie Bauteile auf kleineren Platinen zusammenfassen und sogar Platinen wieder auf größeren zusammenstecken. Davon gleich mehr.

Wie kann eine automatische Bindung von Output- mit Input-Pin stattfinden? Die Pins haben folgende Grundform:

Output: event Action<T> _
Input: void _(T _) {…}

Die Unterstriche stehen hier für Angaben, die für die Bindung zunächst nicht relevant sind. Im ersten Anlauf würde ich einfach mal alle Methoden mit 1 Parameter vom Typ T und ohne Rückgabetyp als Event-Handler bei allen Events vom Typ Action<T> registrieren.

image

Jedem Event sind also potenziell mehrere Event-Handler zugeordnet:

image

Und falls es mehrere Events vom selben Typ gibt, dann sind die Event-Handler mit all diesen Events verbunden:

image

Wer solches Leiterbahnenspaghetti vermeiden möchte, der muss einfach nur zusehen, dass sich die Typen der Events konsequent unterscheiden und dass es für jeden Event-Typ nur einen Handler gibt.

Soweit eine erste einfache Bindungsalgorithmusversion. Eine zweite Version könnte dann auch noch die Namen der Pins mit einbeziehen. Dann würden nur Pins verbunden, deren Typen übereinstimmen und (!) bei denen auch irgendwie die Namen passen. Dazu braucht es eine Konvention. Die könnte so aussehen:

Events haben den Präfix “On”, Event-Handler der Präfix “Process” oder “Handle”. Pins werden zusammengesteckt, wenn sie im Typ übereinstimmen und in dem, was auf den jeweiligen Präfix folgt:

image

Dem Nachrichtentypnamen ist sozusagen noch ein Pinname zugeordnet. Im vorstehenden Bild sind das T.X und T.Y.

Das scheint mir zunächst auszureichen. Das Matching der Output- mit den Input-Pins kann dann so ablaufen:

  1. Sammle alle Output-Pins
  2. Sammle alle Input-Pins
  3. Für jeden Output-Pin…
    1. Finde alle Input-Pins, die zu seinem “qualifizierten Typ” (Typ + Pinname) passen
    2. Wenn es solche Pins gibt, dann registriere sie als Event-Handler…
    3. …ansonsten suche alle Pins, die nur zu seinem Typ passen
      1. Wenn es solche Pins gibt, dann registriere sie als Event-Handler…
      2. …ansonsten hängt der Output-Pin in der Luft. Was tun? Ich denke, das ist eine Fehlermeldung wert – es sei denn, auf die wird ausdrücklich verzichtet.

Schritte 1. und 2. laufen auf allen an Bind() übergebenen Bauteilen ab. Alle Bauteile sind gleich. Wie schon in einem früheren Posting geschrieben, gibt es bei EBC formal keine Client-Service-Abhängigkeiten. Dadurch ist es auch möglich, eine Komponente mit sich selbst zu verbinden. Rekursionen sind also auch möglich.

Platinen

Platinen sind ebenfalls EBC-Komponenten. Sie erfüllen allerdings keine Funktion im Sinne einer Geschäftslogik. Ihre Verantwortlichkeit ist allein die Aggregation von Bauteilen. Platinen bestehen daher vor allem aus einem Konstruktor, in dem die Platinenbauteile zusammengesteckt werden.

Hier ein simples Szenario:

image

Das Bauteil in der Mitte empfängt T-Nachrichten und erzeugt S-Nachrichten. Ob es atomar ist und die Transformationvon T nach S selbst vornimmt oder “nur” eine Platine ist, die andere Bauteile zu diesem Zweck aggregiert, das ist für die anderen Bauteile nicht erkennbar und auch nicht wichtig. Womöglich verändert sich das auch über die Zeit. Die Spezifikation bleibt gleich:

interface IMittelteil

{

    void ProcessX(string _);

    event Action<int> OnY;

}

Im Falle einer Platine sieht die Implementation allerdings speziell aus. Nehmen wir mal an, dass auf dem Mittelteil als Platine zwei andere Bauteile stecken:

image

Dann sähe die Implementation des Mittelteils mindestens so aus:

class Platine : IMittelteil

{

    public Platine(IB b, IC c)

    {

       

        ComponentBinder.Bind(b, c);

    }

   

Die Platine sorgt dafür, dass ihre Bauteile verdrahtet werden. Welche Bauteile das sind, bekommt sie über DI mitgeteilt. Hier tut also der DI Container wieder gute Dienste.

Auch wenn die Aufgabe der Platine denkbar simpel ist (und sie daher viele Abhängigkeiten haben darf), so ist sie wie oben noch nicht vollständig. Ihre Bauteile sind zwar untereinander verdrahtet – aber es fehlt die Verbindung zu den Pins der Platine. Der Input in die Platine muss ja in ihr Bauteil B fließen und Output aus C muss an die Umwelt der Platine weitergereicht werden.

Der Input-Event-Handler der Platine muss dazu mit dem Input-Event-Handler von B verbunden werden. Und der Output-Event von C muss den Output-Event der Platine feuern:

class Platine : IMittelteil

{

    private IB b;


    public
Platine(IB b, IC c)

    {

        this.b = b;

        this.c.OnY += x => this.OnY(x);

       

    }


    public
void ProcessX(string _)

    {

        this.b.ProcessX(_);

    }


    public
event Action<int> OnY;

}

Inputs einer Platine müssen an Inputs von Bauteilen weitergeleitet werden, unverdrahtete Output-Pins von Bauteilen müssen verbunden werdne mit Output-Pins der Platine.

Das ist – wie gesagt – nicht schwierig und sehr regelmäßig - dennoch ein wenig nervig. Im Augenblick sehe ich allerdings noch keinen Weg, um das zu automatisieren. Die Verbindung von Bauteil-Outputs mit Platinen-Outputs wäre möglich, weil dafür nur ein Delegat ad hoc erzeugt werden muss (s. Lambda Funktion im Ctor). Aber was tun mit der Weiterleitung vom Platinen-Event-Handler zum Bauteil-Event-Handler? Vielleicht ist da etwas zu machen, wenn Platinen abstrakte Basisklassen sind oder ihre Event-Handler virtuelle Methoden? Dann könnte man von ihnen zur Laufzeit ableiten und die Event-Handler überschreiben. Hm… darüber muss ich mal nachdenken. Für den Anfang kann ich allerdings auch ohne eine Automatisierung dieses Aspektes der Verdrahtung von EBCs leben.

Injektionen

Wenn eine automatische Bindung grundsätzlich funktioniert, dann wäre der nächste Schritt, in diesen Prozess eingreifen zu können. Ich könnte mir vorstellen, dass ein ComponentBinder Events feuert, wenn er dabei ist, Pins zu verbinden. Auf diesen Events könnten Sie lauschen und eingreifen. Eine Verdrahtung könnte unterdrückt werden. Oder sie könnten einen anderen Event-Handler-Delegaten zurückreichen (z.B. einen für einen Tracer).

Alternativ könnten dem ComponentBinder Prädikate mit anhängenden Kommandos mitgegeben werden. Bei jeder bevorstehenden Bindung könnten die Prädikate geprüft und bei Wahrheit ihre Kommandos ausgeführt werden.

In jedem Fall scheint mir die Injektion von Zwischenstücken zwischen Output- und Input-Pins, wenn sie denn von Hand vorgenommen wird, keine so große Sache. In einer ersten Version eines Binders würde ich sie dennoch raus lassen.

Automatische Dokumentation

Ein interessanter Aspekt ist mir noch zur automatischen Bindung eingefallen: Der Binder “sieht” ja alle Bauteile. Warum sollte er dann nicht auch Auskunft geben darüber, welche das sind und wie er sie verdrahtet hat? Konkret: Warum sollte der Binder nicht eine Dokumentation generieren können über die Schachtelung und Verbindung von Bauteilen? In einem XML-Format ausgegeben könnte daraus anschließend eine Visualisierung der de facto Architektur generiert werden. Wie wäre das?

DI Container hätten das auch immer schon tun können. Haben sie aber nicht. Schade. So kann es denn ein ComponentBinder von vornherein besser machen.

PS: Jetzt hab ich es doch schon getan. Eine erste Version eines Binders für EBCs ist online bei CodePlex unter http://ebcbinder.codeplex.com:

image

Probieren Sie den Binder mal aus. Dann diskutieren wir im Forum des Projektes, wie es damit weitergehen kann.

11 Kommentare:

Markus hat gesagt…

Zum Problem der event-Weiterleitung von der Platine zum Bauteil:
Wäre nicht die Lösung die Handler explizit zu definieren?

In etwa so:

public event Action OnY
{
  add
  {
    this.c.OnY += value;
  }
  remove
  {
    this.c.OnY -= value;
  }
}

Oder spricht etwas dagegen?

Ralf Westphal - One Man Think Tank hat gesagt…

@Markus: Es geht um die Weiterleitung des Event-Handler Aufrufs auf der Platine an den Event-Handler des Bauteils. Also Platine.ProcessX() and B.ProcessX().

Die Events (On_) sind kein Problem.

-Ralf

Volker von Einem hat gesagt…

Hallo Ralf,

ich finde Deine Reihe zur EBC Architektur wirklich lesenswert!
Allerdings bin ich mir nicht sicher, ob diese automatische Bindung über Typ und Namenskonvention wirklich zielführend ist.
Wenn man das mal wieder auf die Elektronik überträgt, hieße das doch: Ich schmeiße 3 Transistoren, einen OPV und 5 Wiederstände auf den Tisch, und diese verbinden sich dann, wie von Geisterhand und machen dann noch etwas sinnvolles.

Habe ich da was falsch verstanden?

Ralf Westphal - One Man Think Tank hat gesagt…

@Volker: Ja, wie von Geisterhand sollen die Pins der Komponenten verbunden werden.

Bei Hardware geht das nicht. Bei Software schon. Warum also nicht?

Konsequente Namensgebung (convention over configuration) hat schon andere Plattformen einen Siegeszug antreten lassen.

Ich kann deine Bedenken andererseits auch verstehen. Findet da wirklich zueinander, was zueinander gehört?

Ich denke, das funktioniert. Technisch ohnehin. Ich habs ja schon gebaut ;-) Aber ich behaupte nicht, dass es schon fertig ist. Es braucht Nachvollziehbarkeit. Also müssen passende Logs (bei Bedarf) produziert werden. Und es müssen auch Ausnahmen und Sonderwege möglich sein. Aber das ist mit Platinen ja kein Problem. Die können die autom. Bindung nutzen - oder auch nicht. Wie du magst.

Überhaupt kannst du auf die autom. Verdrahtung verzichten. Kein Problem. Du musst dich auch an keine Namensregel halten. Alles ok. Nur sobald es regellos wird (in Bezug auf Namen und Parameter), musst du eben auf gute alte Handarbeit umsteigen. Das kann dann sehr mühsam sein. Aber es geht ohne Frage.

Eigentlich sind Interfaces übrigens auch nicht viel anders. Die Konvention lautet da nur: Einer der es haben will, muss es z.B. im Ctor verlangen. Und einer der es anbieten will, muss es implementieren. Zusammenstecken tut dann der DI Container. Es gibt nur viel weniger Interfaces als "Pins".

Das mag für die autom. Injection vorteilhaft sein. Aber für die Defintition einer Komponentenspezifikation ist das nachteilig, wie ich gezeigt habe. Die ist mit "traditionellen" Interfaces nicht mehr self contained. Und Interfaces als "Noppen" oder Steckverbindungen sind sehr grob granular. Von den Schwierigkeiten der Interception will ich gar nicht erst anfangen.

-Ralf

Markus Schmidt hat gesagt…

Hallo Ralf,
Es gibt da ein paar Dinge, die mir durch den Kopf gehen. Die ersten zwei Dinge betreffen das Verhalten zur Laufzeit:

a) Events - und mehrere Objekte die einen Event beim der gleichen Event-Quelle (gleiches Objekt) registrieren. Da ist durchaus Vorsicht geboten, denn jedes Objekt muss beim Beenden (Dispose) alle registrierten Events wieder de-registrieren. Ansonsten gibt’s „Geisterobjekte“, die durch nicht aufgelöste Eventhandler im Speicher bleiben und weiterhin Events empfangen und bearbeiten! Auch dann, wenn offensichtlich die letzte Referenz auf ein Objekt aufgelöst wurde. Ich denke, Du weißt was ich meine!?
b) Der zweite Punkt ist das synchrone Verhalten. Man sollte sich darüber klar sein, dass beim synchronen „versenden“ einer Nachricht, der Response-Eventhandler erst dann aufgerufen werden kann, wenn der Aufrufer fertig ist – nichts mehr tut! Wer also in einer Schleife viele Requests absetzt, wird die erste Response-Message erst dann bekommen, wenn die Schleife beendet ist.

Beides Dinge, die vielen Programmierern so sicher nicht bewusst sind.

Dabei fiel mir auf, dass Du vielleicht noch klarer Darstellen solltest, dass nicht jede _Klasse_ so ausgeprägt werden sollte, wie beschrieben. Sonst kommen die Programmierer noch auf die Idee, die Kommunikation von Klassen innerhalb einer Assembly so zu programmieren.

Generell halte ich Deinen Ansatz für gut. Allerdings nicht für jeden Zweck!

Wenn die Komponentenkommunikation synchron ausgeprägt ist - Laufzeit: Client wartet auf Server und er benötigt das Ergebnis, bevor er weitermachen kann - dann halte ich die oben genannten Gefahren der „virtuellen“ Asynchronität (Events) für relativ hoch. Ich bin (noch) nicht sicher, ob ich Dein Modell dafür wählen würde … . Vielleicht ist mir auch der Programmfluss (wie gesagt bei synchroner Verarbeitung) durch die vielen Events nicht mehr ganz transparent. Man erkannt ja nicht mehr, was in welcher Reihenfolge ausgeführt wird.

Sinn macht das Ganze, wenn die die Komponenten tatsächlich asynchron laufen – also die Messages tatsächlich jederzeit hin- und herfeuern, weil sie die Objekte in unterschiedlichen Threads ablaufen. Aber auch dann wird’s für viele Programmierer komplex. Wenn der Request und der Response „gleichzeitig“ laufen, wollen Ressource geschützt werden etc.

Zu guter Letzt: ich programmiere gerne asynchron und auch event-basiert.
Was mir bei Deinem Modell vielleicht fehlt, ist eine Statemachine, die mir meine Objekte zur Laufzeit verwaltet! Die Statemachine könnte dann auch das Tracing der Messages etc. übernehmen und die „überflüssigen“ Eventhandler eliminieren … ich muss das mal zu Ende denken … ist momentan mehr so ein „Gefühl“, dass das gut sein könnte – gerade bei asynchronen (multi-threaded) Nachrichten, bei denen Objekte im Speicher bleiben müssen (z.B. Port-Listener, ... ).
Gruß aus Wiesbaden
Markus Schmidt

Ralf Westphal - One Man Think Tank hat gesagt…

@Markus: Danke für deine ausführlichen Gedanken. Ich glaube aber, wir haben noch ein Missverständnis: EBCs sind eben nicht (!) für async Kommunikation gedacht. Sie sehen vielleicht so aus, funktionieren aber sync. Mit Absicht. Sie bieten damit einen Migrationspfad von methdodenbasiert sync nach eventbased async.

Zu deinen Punkten im einzelnen:

a) Nein, da sehe ich keine Gefahr. Oder jedenfalls nicht mehr Gefahr als bei jeder anderen Eventverwendung. Was du beschreibst ist kein spezielles Problem von EBCs.

Ich meine sogar, dass EBCs mit diesen potenziellen Problemen wenig zu tun haben. EBCs sind Singletons oder zumindest Objekte, die während der ganzen Anwendungslaufzeit existieren. Die werden instanziert... und dann bleiben sie. Wie die Bauteile auf einer Platine. Die tauscht man auch nicht während des Betriebs aus.

Das kann man zwar mit Softwarebauteilen machen. Aber das ist vergleichsweise selten. Dann muss man halt aufpassen. Joe Developer wird damit erstmal nix zu tun haben.

b) Das Gegenteil ist der Fall. Der Response-Handler wird schon aufgerufen während der Request noch nicht zurückgekehrt ist. Aufrufender Code muss also reentrant ausgelegt sein.

Auch wenn man das verstehen muss, halte ich das für kein so großes Problem. Der Gewinn der Ereignisbasiertheit ist so groß, dass man diese kleine Unannehmlichkeit in Kauf nehmen kann.

Du hast Recht: Nicht mit jeder Klasse soll eventbasiert kommuniziert werden. Wir reden ja aber auch über Komponenten und nicht über Klassen. Das ist ein anderes Abstraktionsniveau.

Was man innerhalb einer EBC tut, ist quasi egal. Und was zwischen EBCs fließt, das ist auch keine EBC. EBCs unterscheiden noch klarer als "traditionelle" Komponenten zwischen Prozess und Daten.

Ich halte EBCs für jeden Zweck angemessen. Damit meine ich, dass sie nicht auf spezielle Anwendungen beschränkt sind. Buchhaltung oder Game, egal.

Aber EBCs sind halt eben Komponenten und insofern sind sie recht grobe Funktionseinheiten. Sie sind architekturrelevante Funktionseinheiten.

Eine Entität würde ich nicht als EBC auslegen. Eine Entität ist "Material", das zwischen EBCs fließt und von ihnen verarbeitet wird. Aber ein Repository ist eine EBC.

Ein Zustandsautomat mag ein Pattern sein, das man mal generell implementieren kann. Ich sehe aber nicht, dass der ganz allgemein fehlt im Konzept der EBCs. EBCs beschreiben die Form von Komponenten, nicht ihre Funktionalität.

-Ralf

frank jurisch hat gesagt…

Geht doch wenn man ein wenig drin rumspielt. Die Bedenken mit der Magie sind berechtigt wenn man meint die Beispielimplementierung von Compomentbinder ist schon der Verkaufsschlager. Da brauchts dann wirklich eine absolute Passfähigkeit der Pins die zusammengehören sollen. Da wird es dann mit gleichartigen Bauteilen schwierig, die verkuppeln sich so oft sie können: Kurzschluss weil jedes OnStrom mit jedem ProcessStrom. Eine kleine Ergänzung im Bind unterscheidet aber schon die Typen und ein wenig Reflection mehr erlaubt sicher feinere Differenzierungen. Ausprobiert und ja:es gefällt mir.
Mal Zeit dazu: Danke Ralf für Deine tollen Ideen und vor allem Beispielimplementierungen nicht nur hier.
Ein "tiefgründendes" brown-vb6 (schwimmende Torfinseln) hat mein Interesse an eventbasiertem Eindringen seit einigen gelungenen Interceptions in Beschlag.

Ralf Westphal - One Man Think Tank hat gesagt…

@Frank: Danke für deine Mühe mit den Posting bei ecbbinder.codeplex.com.

Klar, da ist beim ComponentBinder noch was zu tun. Ist bisher ein erster Wurf.

Inzw. halte ich die Reichweite eines ComponentBinder aber auch für begrenzt. Der ist nett für den Einstieg - doch schon recht bald stößt man auf Szenarien, wo die Namenskonventionen nicht helfen oder gar nicht eingehalten werden können.

Der wesentliche Schritt in der Zukunft muss daher sein, eine Designhilfe zu haben.

-Ralf

Peter hat gesagt…

Hallo Ralf,
nun habe ich mich für ein neues Projekt auch dieser "Erfindung" angenommen und habe noch kleinere Bauchschmerzen.

Folgendes Szenario:
Ein Repository (sagen wir einfach mal AdressenRepository)

Clients (gemeint sind hier mehrere Sichten, die unterschiedliche Personen zeigen) zur Anzeige der Adressen unterschiedlicher Personen.

Wenn man nun den normalen Weg gehen würde
(AdressenRepository.ProcessAddressRequest(guid personId);
event Action AdressenRepository.OnAddressResult;), könnte man wunderbar mittels des EBC-Binders tatsächlich ein MessageTracing einbinden (nachträglich, konfigurationsabhängig, etc). Aber was nun zur Krux wird, ist das zuordnen von Request zu Response, denn es soll ja jeder Client nur seine Response bekommen.

Für die aufruferabhängigen Requests müsste man also tatsächlich die Responseadresse in den Request verlegen. Jetzt verliere ich aber die so schön einfache Möglichkeit später an den Kommunikationsstellen Senken einzubinden.

Habe ich nur was übersehen, oder habe ich hier ein grummeln in der Magengegend wo keines sein sollte?

Gruß, Peter

Ralf Westphal - One Man Think Tank hat gesagt…

@Peter: Dass du über diesen Punkt stolperst, ist normal. Aber du übersiehst auch zweierlei.

1. EBCs sind zunächst einmal synchron! Damit kann du Responses zu Requests einfacher zuordnen als in async Szenarien.

2. Ich habe in anderen EBC-Postings schon Patterns erklärt, wie man mit Request/Response (bzw. Queries) umgeht. Das ist nie so einfach wie mit normalen Funktionsaufrufen. Ist ja auch klar. Aber es ist so einfach, dass es nicht weiter stört. Es geht ja nur darum, an Komponentengrenzen so zu kommunizieren.

Versuch es mal.

-Ralf

Patrick Hesse hat gesagt…

Hallo Ralf,

ich glaube die automatische verbindung widerspricht so ein wenig der Idee von EBC mit seiner synchronität. Ich kann einen Prozeß modellieren in dem ich gewisse Komponenten in einer mir gewünschten Reihenfolge verbinde. In einem früheren Block war auchmal gezeigt worden, das das Verbinden ebenfalls eine Logik enthält (Mwst und runden).

Da ich nun zwischen meinen Komponenten zugunsten einer hohen wiederverwendbarkeit untypisierte Nachrichten verwende, kann ich nicht mehr den korrekten Lauf der Dinge vorraussagen. Ich glaube dieses automatische Binding funktioniert in asnchronen Modellen besser, welche ich aber erst noch durch deinen Migrationsweg erreichen muss.